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 voidrun(){ 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)方法中進行處理。