Android學習之多線程編程(handler篇)

在Android中爲了執行一些耗時的操作,但有不想因此導致主線程堵塞的時候,就必須通過多線程的方式來處理。

在Java中主要有以下兩種生成子線程的方法:

方法一:

class MyThread extends Thread {
@Override
public void run() {
// 處理具體的邏輯
}
}
new MyThread().start();

方法二:

class MyThread implements Runnable {
@Override
public void run() {
// 處理具體的邏輯
}
}
MyThread myThread = new MyThread();
new Thread(myThread).start();

當然,第二種方法使用匿名類的方式將會更加簡潔。


Android中,禁止在主線程之外的線程中直接更新UI(android中的UI操作線程不安全),所以當我需要在子線程中處理UI的操作以減輕主線程負擔的時候,我們考慮使用Android中提供的異步處理方式。

這裏我給出一個代碼實例:

UI部分:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:layout_marginTop="5dp"
        android:layout_gravity="center_horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="紅樓夢"
        android:id="@+id/change_button" />
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/imageView" />

</LinearLayout>

Activity部分:

public class MainActivity extends Activity implements View.OnClickListener {

    private ImageView imageView;
    private Button changeButton;
    //圖片id
    private int[] choose = {R.drawable.dream1, R.drawable.dream2,R.drawable.dream3, R.drawable.dream4,R.drawable.dream5};
    //記錄更新
    private static final int UPDATE_IMAGE = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_layout);
        imageView = (ImageView) findViewById(R.id.imageView);
        changeButton = (Button) findViewById(R.id.change_button);
        changeButton.setOnClickListener(this);
    }

    private Handler handler = new Handler(){
        //通過重寫的handleMessage獲取msg
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case UPDATE_IMAGE:
                    // 對比指令後,在這裏可以進行UI操作
                    imageView.setImageResource(choose[Math.abs(new Random().nextInt())%5]);
                    break;
                default:
                    break;
            }
        }
    };
    public void onClick(View v){
        switch (v.getId()){
            case R.id.change_button:
                new Thread(new Runnable() {
                    //開啓子線程發送一個Message
                    @Override
                    public void run() {
                        Message message = new Message();
                        message.what = UPDATE_IMAGE;
                        handler.sendMessage(message);
                    }
                }).start();
                break;
            default:
                break;
        }

    }

}
實現效果圖:


Android 中的異步消息處理主要由四個部分組成,Message、Handler、MessageQueue 和Looper。 
1. Message
Message 是在線程之間傳遞的消息,它可以在內部攜帶少量的信息,用於在不同線程之間交換數據。除了 Message 的 what 字段,還可以使用 arg1 和 arg2 字段來攜帶一些整型數據,使用 obj 字段攜帶一個 Object 對象。
2. Handler
Handler 顧名思義也就是處理者的意思,它主要是用於發送和處理消息的。發送消息一般是使用 Handler 的 sendMessage()方法,而發出的消息經過一系列地輾轉處理後,最終會傳遞到 Handler 的 handleMessage()方法中。
3. MessageQueue
MessageQueue 是消息隊列的意思,它主要用於存放所有通過 Handler 發送的消息。這部分消息會一直存在於消息隊列中,等待被處理。每個線程中只會有一個 MessageQueue對象。
4. Looper
Looper 是每個線程中的 MessageQueue 的管家,調用 Looper 的 loop()方法後,就會進入到一個無限循環當中,然後每當發現 MessageQueue 中存在一條消息,就會將它取出, 並傳遞到 Handler 的 handleMessage()方法中。 每個線程中也只會有一個 Looper 對象。

流程:

1)首先需要在主線程當中創建一個 Handler 對象,並重寫handleMessage()方法。

2)然後當子線程中需要進行UI 操作時,就創建一個 Message 對象,並通過 Handler 將這條消息發送出去。

3)之後這條消息會被添加到 MessageQueue 的隊列中等待被處理,而 Looper 則會一直嘗試從 MessageQueue 中取出待處理消息,最後分發回 HandlerhandleMessage()方法中。

由於 Handler 是在主線程中創建的,所以此時 handleMessage()方法中的代碼也會在主線程中運行,於是我們在這裏就可以安心地進行 UI 操作了。


最後給出一張流程圖:


發佈了195 篇原創文章 · 獲贊 194 · 訪問量 67萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章