上次讲了关于Android多线程中通信中Thread、Handler、Looper等的基础概念和基本用法,用现实世界两个人写信交流的过程来理解是再好不过了。但是不得不说这一套完整的细节的确很繁琐,好在Android中为我们提供了另一个简化的API——HandlerThread,通过使用HandlerThread,我们可以以一种简单的方式开启线程、进行线程通信。Let's do it!
三、HandlerThread
1)参考文档:http://developer.android.com/reference/android/os/HandlerThread.html
前面的连篇文章中我都贴出来相应内容的官方文档地址,也斗胆说了一下读文档的重要性。这次我们换一种方式——读源代码,好的代码本身就是一份文档,除了会写还得能读!如何找到Android的源码?不管你用的是不再更新的ADT+Eclipse还是AS(Android studio),你的电脑里一定得下载sdk,在sdk目录下有个叫sources的文件夹,里面放的就是Android的系统源码。(开源大法好!)如果你没有,那就“翻墙”下一份,如何快速更新sdk我会在下一篇博客里写......
2)HandlerThread源码:
我在这把源码贴出来方便查看(我电脑上的源码是Android-22的)
package android.os; /** * Handy class for starting a new thread that has a looper. The looper can then be * used to create handler classes. Note that start() must still be called. */ public class HandlerThread extends Thread { //线程的优先级 int mPriority; //线程id int mTid = -1; //与线程绑定的Looper对象 Looper mLooper; public HandlerThread(String name) { super(name); mPriority = Process.THREAD_PRIORITY_DEFAULT; } /** * Constructs a HandlerThread. * @param name * @param priority The priority to run the thread at. The value supplied must be from * {@link android.os.Process} and not from java.lang.Thread. */ public HandlerThread(String name, int priority) { super(name); mPriority = priority; } /** * Call back method that can be explicitly overridden if needed to execute some * setup before Looper loops. * 这里是你需要实现的部分,你的在这里实现对Handler的准备工作,定义你的Hadnler并实现 *handlerMessage(Message msg)方法。 */ protected void onLooperPrepared() { } @Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; } /** * 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; } /** * Quits the handler thread's looper. * <p> * Causes the handler thread's looper to terminate without processing any * more messages in the message queue. * </p><p> * Any attempt to post messages to the queue after the looper is asked to quit will fail. * For example, the {@link Handler#sendMessage(Message)} method will return false. * </p><p class="note"> * Using this method may be unsafe because some messages may not be delivered * before the looper terminates. Consider using {@link #quitSafely} instead to ensure * that all pending work is completed in an orderly manner. * </p> * * @return True if the looper looper has been asked to quit or false if the * thread had not yet started running. * * @see #quitSafely */ public boolean quit() { Looper looper = getLooper(); if (looper != null) { looper.quit(); return true; } return false; } /** * Quits the handler thread's looper safely. * <p> * Causes the handler thread's looper to terminate as soon as all remaining messages * in the message queue that are already due to be delivered have been handled. * Pending delayed messages with due times in the future will not be delivered. * </p><p> * Any attempt to post messages to the queue after the looper is asked to quit will fail. * For example, the {@link Handler#sendMessage(Message)} method will return false. * </p><p> * If the thread has not been started or has finished (that is if * {@link #getLooper} returns null), then false is returned. * Otherwise the looper is asked to quit and true is returned. * </p> * * @return True if the looper looper has been asked to quit or false if the * thread had not yet started running. */ public boolean quitSafely() { Looper looper = getLooper(); if (looper != null) { looper.quitSafely(); return true; } return false; } /** * Returns the identifier of this thread. See Process.myTid(). */ public int getThreadId() { return mTid; } }
这里我们重点看两个方法:
protected void onLooperPrepared() 这是一个在拓展类中需要重写的方法,它完成准备工作,一般是对Handelr进行定义。比如接受到主线程发来的消息时如何做出应对。在后面的示例中我就会对Handler进行定义,在handleMessage(Message msg)中定义行为。
public void run() 再看这个方法里的内容是不是感到很熟悉,理解了Thread、Handler、Looper等概念后,是不是很容易就读懂了它的意思。对了,拓展HandlerThread时,如果要override run方法一定要记得调用父类的run() 。
对于其他的方法,在这里就不赘述了,每个方法的前面的注释就详细说明了它们的作用。
3)一个简单的示例:
还是一样的,我用一个示例来说明HandlerThread的用法。还是一样的开启线程,等到接收到主线程发来的消息,然后打印打印日志。
布局:
1 <TextView 2 android:layout_width="wrap_content" 3 android:layout_height="wrap_content" 4 android:layout_centerHorizontal="true" 5 android:text="HandlerThread"/> 6 7 <Button 8 android:id="@+id/button" 9 android:layout_width="match_parent" 10 android:layout_height="wrap_content" 11 android:layout_alignParentBottom="true" 12 android:text="send message"/>
拓展的HandlerThread类:
1 public class MyThread extends HandlerThread { 2 3 private static final String TAG = "MyThread"; 4 private Handler mHandler; 5 6 public MyThread() { 7 super(TAG); 8 } 9 10 @Override 11 protected void onLooperPrepared() { 12 super.onLooperPrepared(); 13 mHandler = new Handler(){ 14 @Override 15 public void handleMessage(Message msg) { 16 super.handleMessage(msg); 17 if(msg.what == MainActivity.MSG_MAIN){ 18 handlerRequest(msg.obj); 19 } 20 } 21 }; 22 return; 23 } 24 25 private void handlerRequest(Object obj){ 26 Log.d(TAG, "handlerRequest:" + obj + ",thread:" + Thread.currentThread().getName()); 27 Looper looper = Looper.getMainLooper(); 28 Handler handler = new Handler(looper); 29 handler.post(new Runnable() { 30 @Override 31 public void run() { 32 Log.d(TAG,"message is handled,thread:"+Thread.currentThread().getName()); 33 return; 34 } 35 }); 36 return; 37 } 38 39 public Handler getHandler() { 40 return mHandler; 41 } 42 }
这次我使用了post方法很主线程进行通信。
Activity代码:
1 public class MainActivity extends AppCompatActivity { 2 3 public static final int MSG_MAIN = 100; 4 5 @Override 6 protected void onCreate(Bundle savedInstanceState) { 7 super.onCreate(savedInstanceState); 8 setContentView(R.layout.activity_main); 9 10 final MyThread thread = new MyThread(); 11 thread.start(); 12 thread.getLooper(); 13 14 final Button sendButton = (Button) findViewById(R.id.button); 15 sendButton.setOnClickListener(new View.OnClickListener() { 16 @Override 17 public void onClick(View view) { 18 Handler handler = thread.getHandler(); 19 Message msg = handler.obtainMessage(); 20 msg.what = MainActivity.MSG_MAIN; 21 msg.obj="testing HandlerThread"; 22 handler.sendMessage(msg); 23 return; 24 } 25 }); 26 } 27 }
Logcat打印日志:
10-08 11:45:47.152 13949-14004/comfallblank.github.handlerthread D/MyThread: handlerRequest:testing HandlerThread,thread:MyThread
10-08 11:45:47.162 13949-13949/comfallblank.github.handlerthread D/MyThread: message is handled,thread:main
这次我在日志中加入了线程名称,这样就可以看出任务执行的线程了。
到这里,关于Android线程的内容算写完了,本来打算在国庆期间写完了,最后拖拖拉拉延迟了一天。还有国庆长假后第一天上课好累啊!就这样吧!下一篇关于如何快速更新sdk努力在这周写出来。
最后,欢迎大家交流,指正我不正确的地方。
邮箱:fallblank525@gmail.com QQ:1054746297