android 实现主线程、子线程双向通信
16lz
2021-01-26
在 android 中,不可以在子线程中更新 UI 的操作,否则会报错或者异常信息。
在这种情况下,我们会使用 Handler(在 UI 线程创建该对象) 接收子线程的消息更新 UI.
可以看出,这是子线程通知主线程,而主线程没有直接通知子线程,那麽我们如何做到这一点?这样有什么好处?
好处,很明显。主线程中如果有些耗时的操作,我们可以让子线程去做,这时,主线程就可以通知子线程了!
实现这种操作的方式有很多,今天主要想说说 HandlerThread 与 Handler 的配合使用方法。
在主线程中,可以创建 HandlerThread 对象:
view plain print ?
- HandlerThreadmHandlerThread=newHandlerThread("sub_thread");
- mHandlerThread.start();
这样,就开启了一个子线程,该线程的名字就是 sub_thread.
然后,我们实现一个继承自 Handler 的 MyHandler 类:
view plain print ?
- classMyHandlerextendsHandler{
- publicMyHandler(){
- super();
- }
- publicMyHandler(Looperlooper){
- super(looper);
- }
- @Override
- publicvoidhandleMessage(Messagemsg){
- //super.handleMessage(msg);
- if(msg.what==MSG_WHAT){
- Bundlebundle=msg.getData();
- Stringinfo=bundle.getString("main");
- Log.d("mark","我接受任务:"+info);
- }
- }
- }
最后,使用 Message 来传递消息,MyHandler 会根据情况处理 Message.
完整代码:
view plain print ?
- packagemark.zhang;
- importandroid.app.Activity;
- importandroid.os.Bundle;
- importandroid.os.Handler;
- importandroid.os.HandlerThread;
- importandroid.os.Looper;
- importandroid.os.Message;
- importandroid.util.Log;
- publicclassHandlerThreadActivityextendsActivity{
- privatestaticfinalintMSG_WHAT=1;
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- //创建对象,并启动该线程
- HandlerThreadmHandlerThread=newHandlerThread("sub_thread");
- mHandlerThread.start();
- //获取Looper对象
- MyHandlermHandler=newMyHandler(mHandlerThread.getLooper());
- //创建Bundle对象,传递数据
- Bundlebundle=newBundle();
- bundle.putString("main","我这边事情太多,麻烦你帮忙处理一下!");
- //发送消息
- Messagemsg=newMessage();
- msg.what=MSG_WHAT;
- msg.setData(bundle);
- msg.setTarget(mHandler);
- msg.sendToTarget();
- Log.d("mark","UI----"+"threadName:"+Thread.currentThread().getName()+",threadId:"+Thread.currentThread().getId());
- }
- /**
- *该Handler调用handleMessage方法运行在子线程
- *
- *@authormark
- */
- classMyHandlerextendsHandler{
- publicMyHandler(){
- super();
- }
- /*这个构造方法必须有*/
- publicMyHandler(Looperlooper){
- super(looper);
- }
- @Override
- publicvoidhandleMessage(Messagemsg){
- if(msg.what==MSG_WHAT){
- Bundlebundle=msg.getData();
- //接收消息
- Stringinfo=bundle.getString("main");
- Log.d("mark","handleMessage---"+"threadName:"+Thread.currentThread().getName()+",threadId:"+Thread.currentThread().getId());
- Log.d("mark","我接受任务:"+info);
- }
- }
- }
- }
这里,我们思考一个问题,代码:
view plain print ?
- //获取Looper对象
- MyHandlermHandler=newMyHandler(mHandlerThread.getLooper());
获取 Looper 对象,使用的是 HandlerThread 对象的 getLooper 对象。为什么不直接这样:
view plain print ?
- //获取Looper对象
- MyHandlermHandler=newMyHandler(getMainLooper());
如果这样做的话,打印信息如下:
view plain print ?
- D/mark(21852):UI----threadName:main,threadId:1
- D/mark(21852):handleMessage---threadName:main,threadId:1
- D/mark(21852):我接受任务:我这边事情太多,麻烦你帮忙处理一下!
可见,此时的 handleMessage 是在主线程中运行的。每个主线程默认有一个 Looper,也就是说在主线程中,下面代码是等效的:
view plain print ?
- MyHandlermHandler=newMyHandler(getMainLooper());
- MyHandlermHandler=newMyHandler();
但是子线程需要手动获取如:
view plain print ?
- MyHandlermHandler=newMyHandler(mHandlerThread.getLooper());
实现主线程、子线程双向通信可以在各自的线程中分别是用 Handler 来传递信息和处理消息。
更多相关文章
- Android中需要手动关闭的地方总结
- 十大技巧优化Android(安卓)App性能
- android手机开发课小结
- 从架构师的角度分析Android(安卓)Handler 源码的正确姿势
- 《第一行代码》学习笔记之服务
- Android中Handler,Looper,MessageQueue和Thread
- Android(安卓)中使用 dlib+opencv 实现动态人脸检测
- Android内存泄漏检测及修复(转载)
- Android消息机制之HandlerThread