上一篇我介绍了Handler机制的工做原理,默认状况下,ActivityThread类为咱们建立的了主线程的Looper和消息队列,因此当你建立Handler以后发送消息的时候,消息的轮训和handle都是在ui线程进行的。这种状况属于子线程给主线程发消息,通知主线程更新ui...等,那么反过来,怎么才能让主线程给子线程发消息,通知子线程作一些耗时逻辑??ide
以前的学习咱们知道,Android的消息机制遵循三个步骤:oop
1 建立当前线程的Looper 学习
2 建立当前线程的Handler ui
3 调用当前线程Looper对象的loop方法this
看过以前文章的朋友会注意到,本篇我特地强调了“当前线程”。是的以前咱们学习的不少都是Android未咱们作好了的,譬如:建立主线程的Looper、主线程的消息队列...就连咱们使用的handler也是主线程的。那么若是我想建立非主线程的Handler而且发送消息、处理消息,这一系列的操做咱们应该怎么办那???不怎么办、凉拌~~~什么意思???依葫芦画瓢,依然遵循上面的三步走,直接上代码!!!!spa
public class ChildThreadHandlerActivity extends Activity { private MyThread childThread; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_handler); childThread = new MyThread(); childThread.start(); Handler childHandler = new Handler(childThread.childLooper){//这样以后,childHandler和childLooper就关联起来了。 public void handleMessage(Message msg) { }; }; } private class MyThread extends Thread{ public Looper childLooper; @Override public void run() { Looper.prepare();//建立与当前线程相关的Looper childLooper = Looper.myLooper();//获取当前线程的Looper对象 Looper.loop();//调用此方法,消息才会循环处理 } } }
代码如上,咱们依然循序Android的三步走战略,完成了子线程Handler的建立,难道这样建立完了,就能够发消息了么?发的消息在什么线程处理?一系列的问题,怎么办?看代码!!!运行上述代码,咱们发现一个问题,就是此代码一会崩溃、一会不崩溃,经过查看日志咱们看到崩溃的缘由是空指针。谁为空???查到是咱们的Looper对象,怎么会那?我不是在子线程的run方法中初始化Looper对象了么?话是没错,可是你要知道,当你statr子线程的时候,虽然子线程的run方法获得执行,可是主线程中代码依然会向下执行,形成空指针的缘由是当咱们new Handler(childThread.childLooper)的时候,run方法中的Looper对象还没初始化。固然这种状况是随机的,因此形成偶现的崩溃。线程
那怎么办?难道咱们不能建立子线程Handler ???No!!!No!!!No!!!,你能想到的Android早就为咱们实现好了,HandlerThread类就是解决这个问题的关键所在,看代码!!!指针
public class HandlerThreadActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_handler); TextView textView = (TextView) findViewById(R.id.tv); textView.setText("HandlerThreadActivity.class"); HandlerThread handlerThread = new HandlerThread("HandlerThread"); handlerThread.start(); Handler mHandler = new Handler(handlerThread.getLooper()){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); Log.d("HandlerThreadActivity.class","uiThread2------"+Thread.currentThread());//子线程 } }; Log.d("HandlerThreadActivity.class","uiThread1------"+Thread.currentThread());//主线程 mHandler.sendEmptyMessage(1); } }
建立HandlerThread对象的时候,有个参数,是指定线程名字的。上面的代码无论运行多少次都不会奔溃!!!而且这种方法建立的handler的handleMessage方法运行在子线程中。因此咱们能够在这里处理一些耗时的逻辑。到此咱们完成了主线程给子线程发通知,在子线程作耗时逻辑的操做。日志
下面咱们去看看源码,看看为何使用HandlerThread就能够避免空指针那?code
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; }
HandlerThread类的getLooper方法如上,咱们看到当咱们获取当前线程Looper对象的时候,会先判断当前线程是否存活,而后还要判断Looper对象是否为空,都知足以后才会返回给我Looper对象,不然处于等待状态!!既然有等待,那就有唤醒的时候,在那里那???咱们发现HandlerThread的run方法中,有以下代码:
@Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; }
说明了什么那???HandlerThread类start的时候,Looper对象就初始化了,并唤醒以前等待的。因此HandlerThread很好的避免了以前空指针的产生。因此之后要想建立非主线程的Handler时,咱们用HandlerThread类提供的Looper对象便可。
至此,前三篇咱们讲了Handler的使用、工做原理、建立子线程Handler。下一篇我会讲使用Handler引发的内存泄漏的解决办法。