医疗器械公司网站建设,建站公司 商城,网站建设基础问题,微信网页手机登录入口官网平时#xff0c;我们一般都是在子线程中向主线程发送消息#xff08;要在主线程更新UI#xff09;#xff0c;从而完成请求的处理。那么如果需要主线程来向子线程发送消息#xff0c;希望子线程来完成什么任务。该怎么做#xff1f;这就是这篇文章将要讨论的内容。
一、…
平时我们一般都是在子线程中向主线程发送消息要在主线程更新UI从而完成请求的处理。那么如果需要主线程来向子线程发送消息希望子线程来完成什么任务。该怎么做这就是这篇文章将要讨论的内容。
一、HandlerThread类 主线程发送消息给子线程通常思维逻辑就是创建子线程在主线程中实例化一个与子线程Looper相关联的Handler这样handler处理的消息就是该子线程中的消息队列而处理的逻辑都是在该子线程中执行的不会占用主线程的时间。
实践一下。新建项目修改它的MainActivity的代码如下即可
public class ThreadHandlerActivity extends Activity{//创建子线程class MyThread extends Thread{private Looper looper;//取出该子线程的LooperOverridepublic void run() {Looper.prepare();//创建该子线程的Looperlooper Looper.myLooper();//取出该子线程的LooperLooper.loop();//只要调用了该方法才能不断循环取出消息}}private TextView tv;private MyThread thread;private Handler mHandler;//将mHandler指定轮询的Looperprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);tv new TextView(this);tv.setText(Handler实验);setContentView(tv);thread new MyThread();thread.start();//千万别忘记开启这个线程//下面是主线程发送消息mHandler new Handler(thread.looper){Overridepublic void handleMessage(android.os.Message msg) {Log.d(当前子线程是-----, Thread.currentThread());};};mHandler.sendEmptyMessage(1);}}
现在运行该程序。并没有得到预期的结果呢报错误如下 这是一个空指针错误。当主线程走到mHandler new Handler(thread.looper)此时子线程的Looper对象还没有被创建出来那么此时thread.looper肯定为空了。
当然了你可以让主线程休眠2秒后再执行后面的代码但是如果有很多个子线程都需要主线程类给其分配任务怎么办那简直要乱套了。所以需要一个更好的解决方式。Android显然也考虑到了这个问题于是它我们提供了一个HandlerThread类。这个类是专门处理这个问题的。
当主线程中有耗时的操作时需要在子线程中完成通常我们就把这个逻辑放在HandlerThread的对象中执行该对象就是一个子线程一下就可以了。下面我们就修改上面的代码看一看如何使用HandlerThread这个类。修改MainActivity中的代码如下
public class ThreadHandlerActivity extends Activity{private TextView tv;private Handler mHandler;//将mHandler指定轮询的Looperprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);tv new TextView(this);tv.setText(Handler实验);setContentView(tv);//实例化一个特殊的线程HandlerThread必须给其指定一个名字HandlerThread thread new HandlerThread(handler thread);thread.start();//千万不要忘记开启这个线程//将mHandler与thread相关联mHandler new Handler(thread.getLooper()){public void handleMessage(android.os.Message msg) {Log.d(当前子线程是-----, Thread.currentThread());};};mHandler.sendEmptyMessage(1);//发送消息}} 运行程序打印的结果如下 从打印结果来看当前子线程的名字正是我们所起的那个名字“handler thread。 你会有疑问表面上看HandlerThread并没有创建自己的Looper啊而且既然是一个线程那么我们肯定也能重写它的run方法吧。在解答你的疑问之前我们不妨重写它的run方法来看一看会有什么结果。将代码修改如下
public class ThreadHandlerActivity extends Activity{private TextView tv;private Handler mHandler;//将mHandler指定轮询的Looperprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);tv new TextView(this);tv.setText(Handler实验);setContentView(tv);//实例化一个特殊的线程HandlerThread必须给其指定一个名字HandlerThread thread new HandlerThread(handler thread){Overridepublic void run() {for(int i0;i3;i){Log.d(handler thread run ,i);}}};
// HandlerThread thread new HandlerThread(handler thread);thread.start();//千万不要忘记开启这个线程//将mHandler与thread相关联mHandler new Handler(thread.getLooper()){public void handleMessage(android.os.Message msg) {Log.d(当前子线程是-----, Thread.currentThread());};};mHandler.sendEmptyMessage(1);//发送消息}} 红色部分就是我们重写了它的run方法。再云运行程序打印的结果如下 for循环的打印结果正常但是为什么没有打印出”当前子线程“呢。其实这正是我们要解释的地方。查看HandlerThread的源代码找到它的run方法如下
Overridepublic void run() {mTid Process.myTid();Looper.prepare();synchronized (this) {mLooper Looper.myLooper();notifyAll();}Process.setThreadPriority(mPriority);onLooperPrepared();Looper.loop();mTid -1;}
可以知道在run方法中实例化自己的Looper如果继续追踪源代码翻看其getLooper方法你会发现如果一个Handler在与HandlerThread进行绑定时发现Looper为空Handler则会一直等待直到Looper被创建出来为止然后才继续执行后续的代码。所以我们重写了HandlerThread的run方法肯定就不会去创建Looper对象那么绑定的Handler就会永远处于等待状态自然而然就不会打印出”当前子线程“信息了。这也是为什么我们要使用HandlerThread这个特殊的线程因为使用这个我们不必关心多线程会混乱Looper会为空等一系列问题只要去关心我们要实现的逻辑就行了。
好了现在做一下简单的总结吧。
1. Handler与哪个线程的Looper相关联那么它的消息处理逻辑就在与之相关的线程中执行相应的消息的走向也就在相关联的MessageQueue中。最常见的就是Handler与主线程关联那么接收Looper回传的消息后的逻辑就会在主线程中执行2. 当主线程中需要与子线程进行通信时比如将耗时操作放在子线程中建议使用HandlerThread。同时要注意千万不要去重写它的run方法。
二、一个主线程与子线程互相通信的例子 知识点都说完了。下面我们来写一个具体的例子实践一下吧。新建一个项目修改它的MainActivity代码如下
public class ThreadHandlerActivity extends Activity{private TextView tv;private Handler mHandler;//与子线程关联的Handlerprivate Handler handler;//与主线程关联的Handlerprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);tv new TextView(this);tv.setText(Handler实验);setContentView(tv);//实例化一个特殊的线程HandlerThread必须给其指定一个名字HandlerThread thread new HandlerThread(handler thread);thread.start();//千万不要忘记开启这个线程//将mHandler与thread相关联mHandler new Handler(thread.getLooper()){public void handleMessage(android.os.Message msg) {Log.d(我是子线程-----, Thread.currentThread());handler.sendEmptyMessage(1);//发送消息给主线程};};handler new Handler(){public void handleMessage(android.os.Message msg) {Log.d(我是主线程-----, Thread.currentThread());mHandler.sendEmptyMessage(1);//发送消息给子线程};};mHandler.sendEmptyMessage(1);//发送消息handler.sendEmptyMessage(1);//发送消息}}
注释很详细不解释 了。运行程序结果如下 这样子就会一直循环下去轮流打印出主线程和子线程。