關於 Android Handler 跟 Thread 通信交互的小實例,配備了 Demo 供初學/新手小夥伴參考

昨天羣裏一實習生問了我關於 Handler 主線程跟子線程 Thread 的通信與交互的問題,我當時就跟他解釋了一丟丟,然後他說很

統,就說給一個demo看下,介於反正都是要寫,那就寫一篇博客,就可以解決在遇到類似問題的小夥所面臨的問題了,開篇前

新手可以打開工具一起敲,老手沒事吐吐槽就行了,哈哈,OK,我們開始


首先介紹一下 Looper ,Looper 作爲 MessageQueue 的管理制,在一個主線程中一個 MessageQueue 只有一個 Looper 管理整

個 MessageQueue,但是一個 MessageQueue 可以有多個 Message ,多個 Handler ,Looper 分別需要 Message 和 Handler 從 

MessageQueue 中存儲或者拿出消息執行相應的任務操作


即:Looper 數目1 它是 MessageQueue 的管理者


MessageQueue 數目1 即消息隊列


Message 數目多 即消息媒介


Handler 數目多 即搬運工人


Demo:

package com.example.engineerjspcustomview;

import custom.thread.CustomThread;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class HandlerActivity extends Activity {

	private TextView handler_text, thread_text;
	private Button start_working;
	private CustomThread mThread;
	private int id = 0;

	private Handler mHandler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			case 0:// show handler status
				switch (msg.arg1) {

				case 0:
					handler_text.setText("Handler require Thread calc :1+1");
					HandRequireThreadCalc(1, 1);
					break;

				case 1:
					handler_text.setText("Handler require Thread calc :1+2");
					HandRequireThreadCalc(1, 2);
					break;

				case 2:
					handler_text.setText("Handler require Thread calc :1+3");
					HandRequireThreadCalc(1, 3);
					break;

				case 3:
					handler_text.setText("Handler require Thread calc :1+4");
					HandRequireThreadCalc(1, 4);
					break;
				}
				break;

			case 1:// show thread status
				thread_text.setText((String) msg.obj);
				isLossFoucse = true;
				setBtnLossFoucse();
				break;
			}
		};
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.handler_activity);
		initView();
		mThread = new CustomThread(mHandler);
		mThread.start();
	}

	private boolean isLossFoucse = true;

	private void initView() {
		handler_text = (TextView) findViewById(R.id.show_handler_status);
		thread_text = (TextView) findViewById(R.id.show_thread_status);
		start_working = (Button) findViewById(R.id.start_working);
		start_working.setOnClickListener(mListener);
	}

	private void setBtnLossFoucse() {
		Log.v("Engineer-Jsp", "setBtnLossFoucse() Enabled:" + isLossFoucse);
		start_working.setEnabled(isLossFoucse);
	}

	private void HandRequireThreadCalc(int j, int k) {
		Message msg = mThread.thread_handler.obtainMessage();
		msg.what = 0;
		msg.arg1 = j;
		msg.arg2 = k;
		mThread.thread_handler.sendMessage(msg);
	}

	private OnClickListener mListener = new OnClickListener() {

		@Override
		public void onClick(View arg0) {

			switch (id) {
			case 0:
				mHandler.obtainMessage(0, 0, 0).sendToTarget();
				id++;
				isLossFoucse = false;
				setBtnLossFoucse();
				break;
			case 1:
				mHandler.obtainMessage(0, 1, 0).sendToTarget();
				id++;
				isLossFoucse = false;
				setBtnLossFoucse();
				break;
			case 2:
				mHandler.obtainMessage(0, 2, 0).sendToTarget();
				id++;
				isLossFoucse = false;
				setBtnLossFoucse();
				break;
			case 3:
				mHandler.obtainMessage(0, 3, 0).sendToTarget();
				id++;
				if (id >= 3) {
					id = 0;
				}
				isLossFoucse = false;
				setBtnLossFoucse();
				break;
			}
		}
	};
}

上述代碼大致構思是在主頁面即 HandlerActivity 下點擊 satrt working 按鈕之後,初始化一個整形數值來分工4個異化操

作,執行到 case 3 的時候會重新初始化,從最初的值開始循環,在點擊的過程中需要子線程即 CustomThread 完成之後才能讓

它可以點擊,這樣做可以避免在大型的消耗操作時,避免子線程 即 CustomThread  的臃腫,導致出現異常,需要在子線程 即 

CustomThread 完成之後重新獲得可點擊事件,這個結果需要由  主頁面即 HandlerActivity 的 mHandler 對象來發送給自己,並且更新到UI上,

因爲在實例化 子線程 即 CustomThread 的時候,我傳了一個 mHandler 對象過去,爲的就是方便演示結果顯示在主UI上,而 子線程 即 

CustomThread 也定義了一個搬運工 即 Handler 對象 thread_handler ,它主要負責將 主頁面即 HandlerActivity 的計算要求發送給到自己的

消息隊列中,當子線程 即 CustomThread 拿到結果之後 調用 Calc 函數進行計算,並且將結果推送到自己的消息隊列中,再由主頁面即 

HandlerActivity 在初始化時傳過來的 mHandler 對象來發送到主界面 UI 進行計算結果的顯示,以及更新 start working 按鈕的可點擊事件

大致的構思就這樣

package custom.thread;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

public class CustomThread extends Thread {

	public Handler thread_handler;
	private Handler handler;

	public CustomThread(Handler h) {
		this.handler = h;
	}

	@Override
	public void run() {
		super.run();
		Looper.prepare();

		thread_handler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				super.handleMessage(msg);
				switch (msg.what) {
				case 0:

					int j = msg.arg1;
					int k = msg.arg2;
					Calc(j, k);

					break;

				case 1:
					String sendStr = (String) msg.obj;
					if (handler != null) {
						Message msg1 = handler.obtainMessage();
						msg1.what = 1;
						msg1.obj = sendStr;
						handler.sendMessage(msg1);
					}
					break;
				}
			}
		};

		Looper.loop();
	}

	private void Calc(int j, int k) {

		int result = j + k;
		String results = "Thread Calc from Handler test result:" + j + "+" + k
				+ "=" + result;

		Log.v("Engineer-Jsp", results);

		Message msg = thread_handler.obtainMessage();
		msg.what = 1;
		msg.obj = results;
		thread_handler.sendMessage(msg);
	}
}

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal" >

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" >

        <TextView
            android:id="@+id/show_handler_status"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:textColor="#000000" />

        <Button
            android:id="@+id/start_working"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/show_handler_status"
            android:layout_margin="5dp"
            android:text="@string/start_working" />

        <TextView
            android:id="@+id/show_thread_status"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/start_working"
            android:layout_margin="5dp"
            android:textColor="#000000" />
    </RelativeLayout>

</RelativeLayout>

源碼目錄附帶了博主寫的個別自定義控件,歡迎 clone 和 pull !

源碼地址:https://github.com/Mr-Jiang/EngineerJspCustomView

git url:https://github.com/Mr-Jiang/EngineerJspCustomView.git

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