1. 程式人生 > >Handler(原理) HandlerThread 輕鬆實現非同步功能

Handler(原理) HandlerThread 輕鬆實現非同步功能

上文說道Handler可以與任意執行緒繫結,這點可以幫助我們很輕鬆就是想非同步工能

見如下程式碼,

public class MainActivity extends Activity {


    private static final String TAG = "Handler_demo";
    private  Handler myHandler;
    class MyThread extends  Thread {
        public  Handler handler ;
        public Looper looper;
        public void 
run(){ Looper.prepare(); looper = Looper.myLooper(); handler = new Handler(){ @Override public void handleMessage(Message msg) { Log.e(TAG, "當前執行緒:" + Thread.currentThread()); } }; Looper.loop(); } } @Override protected void onCreate
(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MyThread mt = new MyThread(); mt.start(); myHandler = new Handler(mt.looper){ @Override public void handleMessage(Message msg) { Log.e(TAG, "Run IN 執行緒:" + Thread.currentThread
()); } }; myHandler.sendEmptyMessage(0); } }

執行後發現包以下異常

09-27 22:41:50.577    1608-1608/com.liaoli.handleexample E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.liaoli.handleexample/com.liaoli.handleexample.MainActivity}: java.lang.NullPointerException
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
            at android.app.ActivityThread.access$600(ActivityThread.java:141)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:5103)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:525)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.NullPointerException
            at com.liaoli.handleexample.MainActivity.onCreate(MainActivity.java:52)
            at android.app.Activity.performCreate(Activity.java:5133)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2175)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
            at android.app.ActivityThread.access$600(ActivityThread.java:141)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:5103)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:525)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
            at dalvik.system.NativeStart.main(Native Method)

報異常的為

myHandler = new Handler(mt.looper){
這一行,也就是mt.looper為空了,這說明子線成還未來得及建立Looper例項,

此時取出來的肯定為空啊,針對這種情況,android為我們提供了一種解決方案,

提供了一個類,

public class HandlerThread extendsThread 

他是一個執行緒類,下面看一個簡單的例子:

package com.liaoli.handlerthread_demo;
import android.app.Activity;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends Activity {

    private static final String TAG = "MainActivity";
    private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
HandlerThread  ht = new HandlerThread("my HandlerThread");
ht.start();
handler = new Handler(ht.getLooper()){

            @Override
public void handleMessage(Message msg) {
                Log.e(TAG, "Run IN 執行緒:" + Thread.currentThread());
}
        };
handler.sendEmptyMessage(0);
}


}
執行後列印:

09-27 23:07:09.237  11939-11956/com.liaoli.handlerthread_demo E/MainActivity﹕ Run IN 執行緒:Thread[my HandlerThread,5,main]

my HandlerThread 是我們給這個HandlerThread執行緒的名字,這個HandlerThread的run 方法中會去建立一個與此執行緒繫結的Looper,

@Override
public void run() {
    mTid = Process.myTid();
Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
notifyAll();
}
    Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}

此時並沒有報空指標,那麼,他是怎麼做到的呢?我們看HandlerThread的

/**
 * This method returns the Looper associated with this thread. If this thread not been started
 * or for any reason is isAlive() returns false, this method will return null. If this thread 
 * has been started, this method will block until the looper has been initialized.  
 * @return The looper.
 */
public Looper getLooper() {
    if (!isAlive()) {
        return null;
}
    
    // If the thread has been started, wait until the looper has been created.
synchronized (this) {
        while (isAlive() && mLooper == null) {
            try {
                wait();
} catch (InterruptedException e) {
            }
        }
    }
    return mLooper;
}
方法,他首先會取判斷執行緒自己是不是活的,然後判斷mLooper是否為null ,如果為空就wait(),也就是說為空就不會往下走了,器run方法中當mLooper 建立後,會取喚醒這個方
   synchronized (this) {
        mLooper = Looper.myLooper();
notifyAll();
}

法,繼續往下走,所以,就保證了我們在建立

handler = new Handler(ht.getLooper()){
時,不會出現空指標的情形。

我們可一同過HandlerThread很輕鬆就實現一部操作,此時我們的Handler是與HandlerThread這個子執行緒繫結的,所以這個handler的所傳送的訊息都將在這個子執行緒中進行處理

。所以此時我們就可一將一些耗時的操作放在這個Handler 的handleMessage(Message msg)方法中進行處理。