2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > HandlerThread原理 使用实例 源码详细解析

HandlerThread原理 使用实例 源码详细解析

时间:2024-04-21 05:31:41

相关推荐

HandlerThread原理 使用实例 源码详细解析

0、目录

一、HandlerThread简介

二、HandlerThread原理

三、HandlerThread使用实例

四、HandlerThread源码分析

五、总结

一、HandlerThread简介

HandlerThread是一个轻量级的异步类,可以实现多线程,并且可以实现线程间的通信(HandlerThread主要应用是实现主线程到子线程的通信,子线程到主线程通信可以通过Handler机制)。

二、HandlerThread原理

既然已经有Handler可以实现线程间通信,为什么又设计了HandlerThread?

HandlerThread通过字面意思我们可以看到,它是Handler+Thread,那么我们猜测它应该实现了Handler和Thread功能,到底是不是呢,我们向下看。

首先,HandlerThread继承了Thread类,也就是说HandlerThread可以创建一个新的线程。

其次,HandlerThread内封装了Handler类,并自动创建了Looper和MessageQueue,也就是说我们使用HandlerThread线程时,不需要手动创建Looper。

优点:

之前我们使用Handler时,必须自己创建线程,并且自己创建Looper等相关的功能,而HandlerThread则提供了一种方便的方式,相当于内部已经集成了这些功能,不需要我们再手动创建Looper。

三、HandlerThread使用实例

使用步骤:

使用步骤://1、创建HandlerThread对象,即创建了一个新的线程,参数为线程名,仅仅是标记线程用的HandlerThread mHandlerThread = new HandlerThread("mHandlerThread");//2、开启线程,第一步创建了一个新的线程,此处开启线程。mHandlerThread.start();//3、创建Handler,并重写handleMessage()方法//new Handler(mHandlerThread.getLooper()),即把该Handler绑定到mHandlerThread线程的Looper,//进而绑定到了线程mHandlerThreadHandler mHandlerInHandlerThread = new Handler(mHandlerThread.getLooper()){@Overridepublic void handleMessage(Message msg) {//对信息的相关处理操作//在子线程mHandlerThread中运行 super.handleMessage(msg);}};//4、创建消息并发送消息//在主线程中Message msg = Message.obtain();//主线程向子线程mHandlerThread发送消息通信mHandlerInHandlerThread.sendMessage(msg);//5、结束线程。之前开启线程,当工作结束不再使用该线程时,应该结束该线程//即停止了线程的消息循环mHandlerThread.quit();

通过使用步骤我们可以看到,HandlerThread实现的功能主要就是主线程向子线程通信,另外可以在使用Handler实现子线程到主线程的通信,进而就可以实现主线程到子线程间的双向通信.

使用实例:

使用实例://功能介绍:点击按钮实现延时操作,延时时间到后更新UI。public class MainActivity extends AppCompatActivity {TextView mTxtShowTest;Button mBtnInnerClass ,mBtnHandlerThread, mBtnQuit;//1、创建HandlerThread对象,即创建了一个新的线程,参数为线程名,仅仅是标记线程用的HandlerThread mHandlerThread = new HandlerThread("mHandlerThread");//匿名内部类,用于子线程向主线程通信用private Handler mhandlerInnerClass = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what){case 1://执行的UI操作mTxtShowTest.setText("点击了mBtnInnerClass");break;case 2://执行的UI操作mTxtShowTest.setText("来自于mHandlerInHandlerThread的请求更新");break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mTxtShowTest = (TextView) findViewById(R.id.mTxtShowTest); mBtnInnerClass = (Button) findViewById(R.id.mBtnInnerClass); mBtnHandlerThread = (Button) findViewById(R.id.mBtnHandlerThread);mBtnQuit = (Button) findViewById(R.id.mBtnQuit);//2、开启线程,第一步创建了一个新的线程,此处开启线程。mHandlerThread.start();//3、创建Handler,并重写handleMessage()方法//new Handler(mHandlerThread.getLooper()),即把该Handler绑定//到了mHandlerThread线程的Looper,进而绑定到了线程mHandlerThreadfinal Handler mHandlerInHandlerThread = new Handler(mHandlerThread.getLooper()){@Overridepublic void handleMessage(Message msg) {//已经是在子线程mHandlerThread中运行了//可以进行一些耗时等操作try{Thread.sleep(10000); //延时操作}catch (Exception e){e.getMessage();}//子线程向主线程通信Message msg1 = Message.obtain(); msg1.what = 2;mhandlerInnerClass.sendMessage(msg1);super.handleMessage(msg);}};mBtnInnerClass.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {new Thread(new Runnable() {@Overridepublic void run() { Message msg = Message.obtain(); msg.what = 1;mhandlerInnerClass.sendMessage(msg);} }).start();}});mBtnHandlerThread.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//4、创建消息并发送消息//主线程中Message msg = Message.obtain();//主线程向子线程发送信息,通信mHandlerInHandlerThread.sendMessage(msg);}});mBtnQuit.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//5、结束线程。之前开启线程,当工作结束不再使用该线程时,应该结束该线程//即停止了线程的消息循环mHandlerThread.quit();}});}}

注意:

当连续多次点击按钮mBtnHandlerThread是,mTxtShowTest中显示,并不是同时显示的,而是先显示第一次,间隔延时10s(这个10s是在复写handleMessage()方法时自己写的 Thread.sleep(10000))后显示第二次,再间隔延时的10s显示第三次。当我们连续多次点击mBtnHandlerThread按钮时,消息入队列,取出消息执行时,有一个延时10s,之后更新UI,这个消息才算执行完成,然后从消息队列中取出下一个消息,同样有一个延时10s,之后才是更新UI,所以即便时快速连续多次点击按钮,但是执行时每次都间隔一个延时10s.

总结:

以上就是HandlerThread的使用步骤和使用实例,已经测试过可以使用。首先点击按钮mBtnInnerClass, mTxtShowTest显示"点击了mBtnInnerClass",之后再点击按钮mBtnHandlerThread,十秒之后,mTxtShowTest显示"来自于mHandlerInHandlerThread的请求更新"。多次点击按钮mBtnHandlerThread,然后点击mBtnInnerClass,mTxtShowTest显示"点击了mBtnInnerClass",10s后mTxtShowTest显示"来自于mHandlerInHandlerThread的请求更新",之后再点击mBtnInnerClass,mTxtShowTest显示"点击了mBtnInnerClass",10s后又会mTxtShowTest显示"来自于mHandlerInHandlerThread的请求更新",即可证明前面注意中说明的问题。

四、HandlerThread源码分析

在第三部分使用实例中的使用步骤可以看到,使用HandlerThread大概需要5步,具体如下:

使用步骤://1、创建HandlerThread对象,即创建了一个新的线程,参数为线程名,仅仅是标记线程用的HandlerThread mHandlerThread = new HandlerThread("mHandlerThread");//2、开启线程,第一步创建了一个新的线程,此处开启线程。mHandlerThread.start();//3、创建Handler,并重写handleMessage()方法//new Handler(mHandlerThread.getLooper()),即把该Handler绑定到mHandlerThread线程的Looper,//进而绑定到了线程mHandlerThreadHandler mHandlerInHandlerThread = new Handler(mHandlerThread.getLooper()){@Overridepublic void handleMessage(Message msg) {//对信息的相关处理操作//在子线程mHandlerThread中运行 super.handleMessage(msg);}};//4、创建消息并发送消息//在主线程中Message msg = Message.obtain();//主线程向子线程mHandlerThread发送消息通信mHandlerInHandlerThread.sendMessage(msg);//5、结束线程。之前开启线程,当工作结束不再使用该线程时,应该结束该线程//即停止了线程的消息循环mHandlerThread.quit();

我们根据使用步骤 ,一步一步的去看源码。

步骤1、创建HandlerThread对象

源码分析:HandlerThread mHandlerThread = new HandlerThread("mHandlerThread");/*** 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 的定义,其继承Thread ,可知HandlerThread 就是个线程public class HandlerThread extends Thread {int mPriority;//优先级int mTid = -1;Looper mLooper;//当前线程的Looperprivate @Nullable Handler mHandler;public HandlerThread(String name) {super(name);mPriority = Process.THREAD_PRIORITY_DEFAULT;}public HandlerThread(String name, int priority) {super(name);mPriority = priority;}...}

总结:

HandlerThread就是个线程,继承了Thread。创建HandlerThread 时,就相当于创建了一个新的线程,并设置了该线程的优先级。

步骤二、开启线程 mHandlerThread.start();

源码分析://Causes this thread to begin execution; the Java Virtual Machine//calls the run method of this thread.public synchronized void start() {...}//调用mHandlerThread的start(),最终将调用mHandlerThread的run()方法。@Overridepublic void run() {mTid = Process.myTid();//获取当前线程的IDLooper.prepare();//创建Looper和MessageQueue//通过锁机制,获取当前线程的Looper对象synchronized (this) {//获取当前线程的Looper对象mLooper = Looper.myLooper();//发送通知,已经获取当前线程的Looper对象//主要是在第三步创建Handler中的mHandlerThread.getLooper()内使用notifyAll();}Process.setThreadPriority(mPriority);//设置线程的优先级//主要是做一些开启消息循环前的准备工作 -->>分析1onLooperPrepared();//开启消息循环Looper.loop();mTid = -1;}分析1: onLooperPrepared()/*** Call back method that can be explicitly overridden if needed to execute some* setup before Looper loops.*/protected void onLooperPrepared() {}

总结:

第一步创建了线程,第二步开启该线程。开启线程时,会创建Looper和MessageQueue,成功后线程会进入消息循环,不断从消息队列中取出消息并分发消息。

步骤三、创建Handler,并重写handleMessage()方法

使用方法: Handler mHandlerInHandlerThread = new Handler(mHandlerThread.getLooper()){@Overridepublic void handleMessage(Message msg) {//对信息的相关处理操作//在子线程mHandlerThread中运行 super.handleMessage(msg);}};//创建Handler时传入Looper对象,此时Handler就与该Looper绑定,进而与Looper所在的线程也绑定//获取当前线程(即mHandlerThread线程)的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 {//等待,直到mHandlerThread的run()方法创建了Looper//并 notifyAll()发送通知wait();} catch (InterruptedException e) {}}}return mLooper;}

总结:

复写handleMessage()方法,该方法是在子线程mHandlerThread中运行 ,而非主线程,要注意。因为是在子线程中,所以可以进行一些耗时相关的操作。另外,通过Handler机制,可以实现该子线程与主线程的通信,进而更新UI。

步骤四、创建消息并发送消息

//在主线程中Message msg = Message.obtain();//主线程向子线程mHandlerThread发送消息通信mHandlerInHandlerThread.sendMessage(msg);//与Handler中的使用方法一样,就不多做介绍了。

步骤五、结束线程

//之前开启线程,当工作结束不再使用该线程时,应该结束该线程//即停止了线程的消息循环//源码分析:mHandlerThread.quit();public boolean quit() {//获取当前LooperLooper looper = getLooper();if (looper != null) {//调用Looper的quit()方法 -->>分析1looper.quit();return true;}return false;}//分析1: looper.quit();public void quit() {//调用MessageQueue的quit()方法 -->>分析2mQueue.quit(false);}//通过looper.quit()退出是一种不安全的退出方法,//还有一种安全的退出方法,即looper.quitSafely();public boolean quitSafely() {Looper looper = getLooper();if (looper != null) {looper.quitSafely();//-->>分析areturn true;}return false;}//分析a looper.quitSafely()的源码实现:public void quitSafely() {//通过源码,截至到目前可以看出,安全不安全主要是mQueue.quit()方法//内的boolean变量是true还是false mQueue.quit(true);// -->>分析2}分析2: mQueue.quit(false);void quit(boolean safe) { synchronized (this) {if (mQuitting) {return;}mQuitting = true;if (safe) {//安全的退出方式removeAllFutureMessagesLocked();// -->>分析4(请先看分析3)} else {//非安全的退出方式removeAllMessagesLocked();// -->>分析3}// We can assume mPtr != 0 because mQuitting was previously false.nativeWake(mPtr);}}//分析3、 removeAllMessagesLocked()//不管该消息是否在使用,把消息队列中的所有消息都回收private void removeAllMessagesLocked() {Message p = mMessages;while (p != null) {Message n = p.next;//Recycles a Message that may be in-use.//这里,不管Message是否在使用,都回收销毁,//所以也就决定了它肯定是不安全的p.recycleUnchecked();p = n;}mMessages = null;}//分析4、 removeAllFutureMessagesLocked()//首先判断是否有消息再使用中,如果没有就按照分析3的方法全部回收,//如果有消息正在使用中,这个使用的消息不做回收,它依然能够正常执行完成,//而其他的所有的没有正在执行的全部回收private void removeAllFutureMessagesLocked() {//Returns milliseconds since boot, not counting time spent in deep sleep.final long now = SystemClock.uptimeMillis();Message p = mMessages;if (p != null) {if (p.when > now) {//判断消息队列现在是否正在处理消息,如果没有则直接把所有消息回收//通过时间来判定的removeAllMessagesLocked();} else {//有正在处理的消息,则处理完成后再退出Message n;for (;;) {n = p.next;if (n == null) {return;}if (n.when > now) {break;}p = n;}p.next = null;do {p = n;n = p.next;p.recycleUnchecked();} while (n != null);}}}

总结:

所谓的安全与否,关键是对正在使用中的消息如何处理来判断的,如果直接回收消息就是不安全,等待它处理完成就是安全的。

五、总结

本文对HandlerThread做了全部分析,从原理、使用实例,到源码分析,希望对您有帮助。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。