Android多线程--HandlerThread的使用以及原理
来源:互联网 发布:360软件管理下载 编辑:程序博客网 时间:2024/05/22 04:57
如果已经理解了Android的消息机制(Handler、Looper、Message、MessageQueue),再来看HandlerThread就很容易了,参考如下:
http://blog.csdn.net/kitty_landon/article/details/53410183
源码解析
最直观的方法就是分析源码,先把源码贴出来。
/** * 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.HandlerThread可以创建拥有Looper的线程,这个Looper能够创建Handler类 */public class HandlerThread extends Thread { int mPriority;//线程优先级 int mTid = -1; Looper mLooper;//当前线程持有的Looper对象 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.可以重写,但是在Looper循环之前。 */ protected void onLooperPrepared() { } @Override public void run() {//创建HandlerThread对象后,必须调用start()方法,调用start()方法后,表示线程启动了,也就会调用线程的run()方法; mTid = Process.myTid(); Looper.prepare();//创建Looper对象,并绑定当前线程 synchronized (this) { mLooper = Looper.myLooper();//获取Looper对象 notifyAll();//唤醒等待线程 } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop();//循环 mTid = -1; } /** * This method returns the Looper associated with this thread. 返回与该线程相关联的Looper对象。If this thread not been started * or for any reason is isAlive() returns false, this method will return null. (如果线程没有开启,或者isAlive()返回false,getLooper()返 回null)。If this thread * has been started, this method will block until the looper has been initialized. 开启了线程,这个方法将会阻塞,直到Looper初始化 * @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; }}
从getLooper()方法实现源码上可以看出外部在通过getLooper()方法获取Looper对象时,会先判断当前线程是否启动了,如果线程已经启动,那么将会进入同步语句并判断Looper是否为null,为null则代表Looper对象还没有被赋值,也就是还没被创建,此时当前调用线程进入等待状态,知道Looper对象被创建并通过notifyAll()方法唤醒等待线程,最后才返回Looper对象。之所以需要等待唤醒机制,是因为Looper的创建是在子线程中执行的,而调用getLooper方法则是在主线程进行的,这样我们就无法保障我们在调用getLooper方法时Looper已经被创建,到这里我们也就明白了在获取mLooper对象时会存在一个同步的问题,只有当线程创建成功并且Looper对象也创建成功之后才能获得mLooper的值,HandlerThread内部则通过等待唤醒机制解决了同步问题。
从源码可以看出当我们调用quit方法时,其内部实际上是调用Looper的quit方法而最终执行的则是MessageQueue中的removeAllMessagesLocked方法(Handler消息机制知识点),该方法主要是把MessageQueue消息池中所有的消息全部清空,无论是延迟消息(延迟消息是指通过sendMessageDelayed或通过postDelayed等方法发送)还是非延迟消息。
从源码中我们可以看出HandlerThread有几个特点:
(1)、HandlerThread本质上是一个线程类,它继承了Thread;
(2)、HandlerThread有自己的内部Looper对象,可以进行loop循环;
(3)、通过获取HandlerThread的Looper对象传递给Handler对象,可以在handleMessage()方法中执行异步任务;
(4)、创建HandlerThread后必须先调用HandlerThread.start()方法,Thread会先调用run()方法,创建Looper对象。
HandlerThread常规使用步骤
方案一:利用Handler(Looper looper, Callback callback)
1、创建HandlerThread实例对象
HandlerThread mMainJobThread = new HandlerThread("qscan");
传入参数的作用主要是标记当前线程的名字,可以是任意字符串。
2、启动HandlerThread线程
mMainJobThread.start();
到此,我们创建完HandlerThread并启动了线程。那么我们怎么将一个耗时的异步任务投放到HandlerThread线程中去执行呢?接下来看下面步骤:
3、构建循环消息处理机制
/** * 该callback运行于子线程 */ class ChildCallback implements Handler.Callback { @Override public boolean handleMessage(Message msg) { //在子线程中进行相应的网络请求 //通知主线程去更新UI mUIHandler.sendMessage(msg1); return false; } }
4、构建异步Handler
Handler mMainJobHandler = new Handler(mMainJobThread.getLooper(), new ChildCallback());
第3步和第4步是构建一个可以用于异步操作的handler,并将前面创建的HandlerThread的Looper对象以及Callback接口类作为参数传递给当前的handler,这样当前的异步handler就拥有了HandlerThread的Looper对象,由于HandlerThread本身是异步线程,因此Looper也与异步线程绑定,从而handlerMessage方法也就可以异步处理耗时任务了,这样我们的Looper+Handler+MessageQueue+Thread异步循环机制构建完成,来看看一个完整的使用案例。
方案二:利用Handler(Looper looper)
步骤一和步骤二是相同的;
3、构建循环消息处理机制
private class MainJobHandler extends Handler { public MainJobHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { Log.e(TAG, "MainJobHandler() -> msg.what = " + msg.what); ...... } }
4、构建异步Handler
MainJobHandler mMainJobHandler = new MainJobHandler(mMainJobThread.getLooper());
使用案例
public class HandlerThreadActivity extends Activity { /** * 图片地址集合 */ private String url[]={ "http://img.blog.csdn.net/20160903083245762", "http://img.blog.csdn.net/20160903083252184", "http://img.blog.csdn.net/20160903083257871", "http://img.blog.csdn.net/20160903083257871", "http://img.blog.csdn.net/20160903083311972", "http://img.blog.csdn.net/20160903083319668", "http://img.blog.csdn.net/20160903083326871" }; private ImageView imageView; private Handler mUIHandler = new Handler(){ @Override public void handleMessage(Message msg) { LogUtils.e("次数:"+msg.what); ImageModel model = (ImageModel) msg.obj; imageView.setImageBitmap(model.bitmap); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_handler_thread); imageView= (ImageView) findViewById(R.id.image); //创建异步HandlerThread HandlerThread handlerThread = new HandlerThread("downloadImage"); //必须先开启线程 handlerThread.start(); //子线程Handler Handler childHandler = new Handler(handlerThread.getLooper(),new ChildCallback()); for(int i=0;i<7;i++){ //每个1秒去更新图片 childHandler.sendEmptyMessageDelayed(i,1000*i); } } /** * 该callback运行于子线程 */ class ChildCallback implements Handler.Callback { @Override public boolean handleMessage(Message msg) { //在子线程中进行网络请求 Bitmap bitmap=downloadUrlBitmap(url[msg.what]); ImageModel imageModel=new ImageModel(); imageModel.bitmap=bitmap; imageModel.url=url[msg.what]; Message msg1 = new Message(); msg1.what = msg.what; msg1.obj =imageModel; //通知主线程去更新UI mUIHandler.sendMessage(msg1); return false; } } private Bitmap downloadUrlBitmap(String urlString) { HttpURLConnection urlConnection = null; BufferedInputStream in = null; Bitmap bitmap=null; try { final URL url = new URL(urlString); urlConnection = (HttpURLConnection) url.openConnection(); in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024); bitmap=BitmapFactory.decodeStream(in); } catch (final IOException e) { e.printStackTrace(); } finally { if (urlConnection != null) { urlConnection.disconnect(); } try { if (in != null) { in.close(); } } catch (final IOException e) { e.printStackTrace(); } } return bitmap; }}
在这个案例中,我们创建了两个Handler,一个用于更新UI线程的mUIHandler和一个用于异步下载图片的childHandler。最终的结果是childHandler会每个隔1秒钟通过sendEmptyMessageDelayed方法去通知ChildCallback的回调函数handleMessage方法去下载图片并告诉mUIHandler去更新UI界面,以上便是HandlerThread常规使用。
实际上在android比较典型的应用是IntentService。
- Android多线程--HandlerThread的使用以及原理
- HandlerThread的使用以及原理
- Android多线程开发之HandlerThread的使用
- Android HandlerThread 的使用
- android HandlerThread的使用
- android-----HandlerThread的使用
- Android HandlerThread的使用
- Android HandlerThread 的使用
- android HandlerThread的使用
- Android HandlerThread的使用
- Android多线程:HandlerThread使用&源码解析
- Android HandlerThread使用及原理分析
- android的HandlerThread的使用
- Android中HandlerThread的使用
- Android多线程--HandlerThread用法
- Android多线程之HandlerThread
- Android多线程之HandlerThread
- Android多线程之HandlerThread
- Spring源码解析——如何阅读源码
- React之智能组件和木偶组件
- 金额计算
- 715. Range Module
- c#观察者模式和事件委托的联合使用
- Android多线程--HandlerThread的使用以及原理
- asp.net 程序 Respons.redirect("XXXXXX")无法跳转
- 解决python-opencv中路径不能读中文的问题
- android handler Looper MessageQueue源码分析
- CCF 201703-1 分蛋糕
- PostgreSQL java连接SQL(七)
- 获取IP地址
- 编译contrib时遇到的问题
- MFC按钮美化