Android Handler 消息處理使用

本文內容

  • 環境
  • 演示 Handler 消息處理
  • 參考資料

Handler 有兩個主要做用或者說是步驟:發送消息和處理消息。在新啓動的線程中發送消息,在主線程中獲取、並處理消息。Android 平臺只容許UI線程修改 Activity 裏的UI組件。css

本文只給出核心代碼,若是你是初學者,能夠下載本文後面的源代碼。html

環境


  • Windows 2008 R2 64 位
  • Eclipse ADT V22.6.2,Android 4.4.3
  • 三星 SM-G3508,Android OS 4.1

 

演示 Handler 消息處理


演示主程序以下圖 1 所示,有 4 個演示。java

1

圖 1 主程序android

主程序 XML 頁面,只是四個按鈕,併爲它們添加相應事件,顯示 4 個演示的 Activity 而已,略,核心代碼以下所示:ajax

public class MainActivity extends Activity {
    Handler handler = new Handler();
    Intent intent = null;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
        findViewById(R.id.btn1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                intent = new Intent(MainActivity.this, Handler1Demo.class);
                startActivity(intent);
            }
        });
 
        findViewById(R.id.btn2).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                intent = new Intent(MainActivity.this, Handler2Demo.class);
                startActivity(intent);
            }
        });
 
        findViewById(R.id.btn3).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                intent = new Intent(MainActivity.this, Handler3Demo.class);
                startActivity(intent);
            }
        });
 
        findViewById(R.id.btn4).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                intent = new Intent(MainActivity.this, Handler4Demo.class);
                startActivity(intent);
            }
        });
    }
}

加入和移除 Handler 到主線程

「加入」和「移除」 Handler 到主線程,點擊「開始」時,每隔1秒,將 Handler 加入到主線程隊列中,執行 Runnable 中 run 方法內的代碼,顯示當前時間;點擊「結束」時,從主線程隊列移除  Handler。app

2

圖 2 加入和移除 Handler 到主線程ide

XML 頁面包含三個組件:兩個 Button,一個 TextView(TextView 在 ScrollView 內),略,核心代碼以下所示:函數

public class Handler1Demo extends Activity {
    private TextView tv = null;
    private Button start = null;
    private Button end = null;
 
    Handler handler = new Handler();
    // 線程每次執行時,輸出時間,延時1秒加入主線程隊列
    Runnable r = new Runnable() {
        public void run() {
            tv.append(new Date().toLocaleString() + "\r\n");
            handler.postDelayed(r, 1000);
        }
    };
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.handler_1_demo);
 
        tv = (TextView) findViewById(R.id.text_view);
 
        start = (Button) findViewById(R.id.start);
        end = (Button) findViewById(R.id.end);
        // 開始 將handler加入到主線程隊列中
        start.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                handler.post(r);
            }
        });
        // 結束 從主線程隊列中移除handler
        end.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                handler.removeCallbacks(r);
            }
        });
    }
}

定時 Handler

利用 Timer、TimerTask 和 Handler 定時刷新時間。oop

3

圖 3 定時 Handlerpost

XML 頁面文件略,核心代碼以下所示:

public class Handler2Demo extends Activity {
    private TextView tv = null;
    Timer timer = new Timer();
    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case 1:
                // 處理消息
                tv = (TextView) findViewById(R.id.text_view);
                tv.append(new Date().toLocaleString() + "\r\n");
                break;
            }
            super.handleMessage(msg);
        }
 
    };
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.handler_2_demo);
 
        timer.schedule(new TimerTask() {
            public void run() {
                Message message = new Message();
                message.what = 1;
                handler.sendMessage(message);
            }
        }, 0, 1000);
    }
}

播放動畫

跟前一個示例相似。

4

圖 4 播放動畫

XML 頁面文件略,核心代碼以下所示:

public class Handler3Demo extends Activity {
    // 定義週期性顯示的圖片的ID
    int[] imageIds = new int[] { R.drawable.java, R.drawable.ee,
            R.drawable.ajax, R.drawable.xml, R.drawable.classic };
    int currentImageId = 0;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.handler_3_demo);
        final ImageView show = (ImageView) findViewById(R.id.show);
        final Handler myHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                // 若是該消息是本程序所發送的
                if (msg.what == 0x1233) {
                    // 動態地修改所顯示的圖片
                    show.setImageResource(imageIds[currentImageId++
                            % imageIds.length]);
                }
            }
        };
        // 定義一個計時器,讓該計時器週期性地執行指定任務
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                // 發送空消息
                myHandler.sendEmptyMessage(0x1233);
            }
        }, 0, 1200);
    }
}

計算質數

這個一個更復雜的 Handler。計算從 2 開始,到你指定數之間的全部質數,並用 Toast 顯示出來。

Handler 涉及以下幾個組件:Message、Looper 和 MessageQueue。

  • Looper:每一個線程只有一個 Looper,它負責管理 MessageQueue,不斷從 MessageQueue 中取出消息,並將消息分給對應的 Handler 處理。
  • MessageQueue:由 Looper 負責管理。採用先進先出的方式管理 Message。
  • Handler:它能把消息發給 Looper 管理的 MessageQueue,並負責處理 Looper 分給它的消息。

5

圖 5 計算質數

XML 頁面文件略,核心代碼以下所示:

public class Handler4Demo extends Activity {
    static final String UPPER_NUM = "upper";
    EditText etNum;
    CalThread calThread;
 
    // 定義一個線程類
    class CalThread extends Thread {
        public Handler mHandler;
 
        public void run() {
            Looper.prepare();
            mHandler = new Handler() {
                // 定義處理消息的方法
                @Override
                public void handleMessage(Message msg) {
                    if (msg.what == 0x123) {
                        int upper = msg.getData().getInt(UPPER_NUM);
                        List<Integer> nums = new ArrayList<Integer>();
                        // 計算從2開始、到upper的全部質數
                        outer: for (int i = 2; i <= upper; i++) {
                            // 用i處於從2開始、到i的平方根的全部數
                            for (int j = 2; j <= Math.sqrt(i); j++) {
                                // 若是能夠整除,代表這個數不是質數
                                if (i != 2 && i % j == 0) {
                                    continue outer;
                                }
                            }
                            nums.add(i);
                        }
                        // 使用Toast顯示統計出來的全部質數
                        Toast.makeText(Handler4Demo.this, nums.toString(),
                                Toast.LENGTH_LONG).show();
                    }
                }
            };
            Looper.loop();
        }
    }
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.handler_4_demo);
        etNum = (EditText) findViewById(R.id.etNum);
        calThread = new CalThread();
        // 啓動新線程
        calThread.start();
    }
 
    // 爲按鈕的點擊事件提供事件處理函數
    public void cal(View source) {
        // 建立消息
        Message msg = new Message();
        msg.what = 0x123;
        Bundle bundle = new Bundle();
        bundle.putInt(UPPER_NUM, Integer.parseInt(etNum.getText().toString()));
        msg.setData(bundle);
        // 向新線程中的Handler發送消息
        calThread.mHandler.sendMessage(msg);
    }
}

在新線程內建立了一個 Handler,因爲在新線程中建立 Handler 時必須先建立 Looper,所以程序先調用 Looper.prepare() 方法爲當前線程建立了一個 Looper實例,並建立配套的MessageQueue,新線程有了 Looper 對象後,接下來建立了一個Handler對象,該 Handler 能夠處理其餘線程發送過來的消息。程序最後調用了 Looper.loop() 的啓動方法。

 

參考資料


 

下載 Demo

相關文章
相關標籤/搜索