Android之HandlerThread源码分析和简单使用(主线程和子线程通信、子线程和子线程通信)
来源:互联网 发布:软件招商加盟政策 编辑:程序博客网 时间:2024/06/01 08:04
1、先熟悉handler方式实现主线程和子线程互相通信方式,子线程和子线程的通信方式
如果不熟悉或者忘记了,请参考我的这篇博客 Android之用Handler实现主线程和子线程互相通信以及子线程和子线程之间的通信 http://blog.csdn.net/u011068702/article/details/75577005
2、贴上简单HandlerThread简单使用(主线程和子线程通信、子线程和子线程通信)的例子
1、activity_main.xml文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.handler.MainActivity1" > <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="ParentToChile" /> <Button android:layout_below="@+id/button1" android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="ChileToParent" /> <Button android:layout_below="@+id/button2" android:id="@+id/button3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="ChileToChile" /></RelativeLayout>
2、MainActivity.java文件
package com.example.handler;import android.os.Bundle;import android.os.Handler;import android.os.HandlerThread;import android.os.Looper;import android.os.Message;import android.support.v7.app.ActionBarActivity;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;public class MainActivity extends ActionBarActivity {public static final String TAG = "HandlerTest";public HandlerThread mHandlerThread;public Handler mChileHandler;public Handler mHandlerCToP = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);int id = (int) Thread.currentThread().getId();Log.d(TAG, "mHandlerCToP currentThread id is:" + id);}};public Button mButtonPtoC;public Button mButtonCtoP;public Button mButtonCtoC;public Handler mHandler = new Handler();public Handler mHandlerCtoC = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);int id = (int) Thread.currentThread().getId();Log.d(TAG, "onCreate currentThread id is:" + id);initUIAndThread();}public void initUIAndThread() {mHandlerThread = new HandlerThread("chenyu");mHandlerThread.start();mHandler = new Handler(mHandlerThread.getLooper()) { @Override public void handleMessage(Message msg) { int id = (int) Thread.currentThread().getId(); Log.d(TAG, "initThread() mHandler handleMessage currentThread id is:" + id); switch(msg.what) {case 0:mHandlerCToP.post(new Runnable(){@Overridepublic void run() {int id = (int) Thread.currentThread().getId(); Log.d(TAG, "initThread() mHandlerCToP post currentThread id is:" + id);mButtonPtoC.setText("chenyu");}});break;case 1:mHandlerCToP.post(new Runnable(){@Overridepublic void run() {int id = (int) Thread.currentThread().getId(); Log.d(TAG, "initThread() mHandlerCToP post currentThread id is:" + id);mButtonCtoC.setText("chenyu");}});default:break; } } }; mButtonPtoC = (Button)findViewById(R.id.button1);mButtonCtoP = (Button)findViewById(R.id.button2);mButtonCtoC = (Button)findViewById(R.id.button3);mButtonPtoC.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v) {int id = (int) Thread.currentThread().getId(); Log.d(TAG, "mButtonPtoC currentThread id is:" + id);Log.d(TAG, "mHandlerPToc msg.what is 0");mHandler.sendEmptyMessage(0);}});mButtonCtoP.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v) {int id = (int) Thread.currentThread().getId(); Log.d(TAG, "mButtonCtoP currentThread id is:" + id);Log.d(TAG, "mHandlerPToc msg.what is 0");mHandlerCToP.sendEmptyMessage(0);}});mButtonCtoC.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v) {new Thread(new Runnable(){@Overridepublic void run() {int id = (int) Thread.currentThread().getId(); Log.d(TAG, "mButtonCtoC currentThread id is:" + id);Log.d(TAG, "mHandlerCToc msg.what is 1");mHandler.sendEmptyMessage(1);}}).start();}});} @Override protected void onDestroy() { super.onDestroy(); mHandlerThread.quit(); } }
3、简单分析例子
1)、原始页面效果
2)、控制台初始化打印的线程ID
分析:在onCreate方法里面打印的主线程的Id为1,有3个按钮,分别是主线程向子线程发消息,子线程向主线程发消息,子线程和子线程发送消息,我们一开始就是对HandlerThread进程初始化,其实它就是一个线程,后面会分析,然后执行了start方法,我们把HandlerThread的looper对象传递给了Handler,之前的文章已分析,一个线程只能有一个looper对象,Handler拥有了HandlerThread的looper对象,就相当于这个Handler在HandlerThread线程同样的线程Id,可以理解为Handler 在子线程里面构建,为什么我这里还有其它的Handler构建,因为想搞清楚在哪里构建属于哪个线程以及子线程的handler是否可以更新UI,主线程构建的handler是否可以更新UI,
3)、依次点击3个按钮后控制台打印的日志
我们可以看到在onCreate方法里面始化handler的时候传递了一个HandlerThread的looper对象,点击第一个按钮后后没有开启线程,当前线程依然是主线程,handler发送了一个消息,然后初始化的handlMessage收到消息了,也就完成了主线程到子线程的通信,当收到消息的时候,我们发现线程的id是6314,所以这个时候虽然是在onCreate里面构建的handler里面的handlerMessage方法,但是线程Id是和HandlerThread线程Id是一样的,然后初始化handler去更新界面,我们代码是用mHandlerCtopP去更新的,因为它的初始化是在主线程构建的,所以可以post可以更新UI,但是这个时候用拥有HandlerThread的looper对象的handler更新界面就会出问题,和子线程里面的handler去更新界面异常一样,如下图
然后点击第二个按钮,是现实子线程向主线程通信,我们发现点击时间里面的线程Id,和handler收到消息的 handleMessage方法里面的线程id, 都是一样,和主线程Id一样,所以我们可以用这个handler直接post来更新UI,
点击第三个按钮,是实现子线程和子线程的通信,执行点击方法,我们开启了一个线程,自然线程Id会和主线程的不一样,为6318, handler收到消息的 handleMessage方法里面的线程id为6314,所以这里可以理解为为子线程线程里面构建了handler,然后用主线程构建的handler更新ui
4)、依次点击3个按钮后手机效果
4、HandlerThread.java源码分析
1、上源代码
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; int mTid = -1; 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. */ 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; } public boolean quit() { Looper looper = getLooper(); if (looper != null) { looper.quit(); return true; } return false; } 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; }}
1、我们知道这个类在android.os目录下,然后继承了Thread,也就是一个线程
2、构造方法会传一个字符串,这里可以随便写,只作为一个标识而已,初始化的时候会调用start方法,然后会执行run()方法
@Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; }
先执行了Looper,prepare(),然后给当前mLooper赋值,然后进行Looper.loop(),进行轮寻,这个代码和标准的子线程用handler的方式差不多,也可以理解为这种方式的封装,所以才能显示子线程和子线程和主线程之间的通信,原理都是一样。
3、getLooper()中有个wait(),这有什么用呢?因为的mLooper在一个线程中执行创建,而我们的handler是在UI线程中调用getLooper()初始化的,必须等到mLooper创建完成,才能正确的返回。getLooper();wait(),notify()就是为了解决这两个线程的同步问题。
4、这里有个退出的方法是
public boolean quit() { Looper looper = getLooper(); if (looper != null) { looper.quit(); return true; } return false; }
我之前写代码的时候,以为停止线程就调用了,mHandlerThread.stop()方法,后面没发现什么问题,直到我们有个功能需要,从控制台下发消息让手机恢复默认出场,函数执行到了这里,导致进程崩溃了,然后就发现这里有问题,需要调用mHandlerThread.quit()方法正常退出。
5、总结
有时还需要频繁更新UI,或则主线程向子线程通信,以及子线程和子线程经常通信的时候,我们可以使用HandlerThread,如果哪里没说清楚,或则讲得有问题,欢迎点评
- Android之HandlerThread源码分析和简单使用(主线程和子线程通信、子线程和子线程通信)
- Android 主线程和子线程通信问题
- Android之用Handler实现主线程和子线程互相通信以及子线程和子线程之间的通信
- 内部通信:主线程和子线程之间的通信
- 子线程和主线程的通信问题
- Handler,Looper用法和主线程子线程间通信
- android开发步步为营之1:Handler让主线程和子线程进行通信
- 线程使用教程 四 主线程和子线程的通信
- Android子线程与主线程通信
- android 主线程与子线程通信
- 主线程和子线程
- 主线程和子线程
- 主线程和子线程
- Android--Handler(承担着子线程和主线程之间的通信)
- Android UI主线程和子线程
- 理解android主线程和子线程
- Android分析主线程与子线程,以及子线程之间相互通信
- Android使用Handler实现子线程与子线程、主线程之间通信
- C primer plus(编程练习)file-4.8-5
- 官方历程 调试STM32F407 VCP例程未知设备问题
- android 自定义 View
- HD 2063 增广路径求二分图最大匹配(匈牙利算法)
- C primer plus(编程练习)file-4.8-6
- Android之HandlerThread源码分析和简单使用(主线程和子线程通信、子线程和子线程通信)
- 【无源汇上下界可行流】ZOJ2314[Reactor Cooling]题解
- [论文笔记]Modeling Interestingness with Deep Neural Networks
- OSG学习:裁剪变换(1)
- 栈的顺序存储结构的相关操作(数据结构)
- StatusBarUtil 状态栏工具类(实现沉浸式状态栏/变色状态栏)
- io-5-netty-工作原理
- C primer plus(编程练习)file-4.8-7
- 字符串分割