在前面2篇内容中针对Java中的多线程已经做了详细的介绍,本篇将针对在Android中多线程这块Google已经为我们封装好了的API的介绍和使用
多线程编程基础之 wait()、notify()、sleep()、join()、yield()、synchronized关键字Lock锁等
多线程编程之 Runnable、Callable、Future、FutureTask和AsyncTask源码分析
HandlerThread
HandlerThread本质上是一个线程类,继承自Thread类,但是HandlerThread有自己的Looper对象,可以进行looper循环,不断从MessageQueue中取消息,可以处理多个任务,从而达到开启一个线程起到多个线程的作用。
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
HandlerThread fetchThread = new HandlerThread("fetching_thread");
Handler fetchHandler;
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
//启动线程
fetchThread.start();
//通过fetchHandler发送的消息,会被fetchThread线程创建的轮询器拉取到
fetchHandler = new Handler(fetchThread.getLooper()){
@Override
public void handleMessage(Message msg) {
//模拟访问网络延迟
SystemClock.sleep(1000);
runOnUiThread(new Runnable() {
@Override
public void run() {
double value = new Random().nextDouble() * 10;
String price = xiaoshuToString(value);
tv.setText("美元汇率:"+price);
Log.e(TAG, "美元汇率:"+price);
}
});
//循环执行
fetchHandler.sendEmptyMessage(1);
}
};
}
public static String xiaoshuToString(double f) {
DecimalFormat df = new DecimalFormat("0.0");//格式化小数
String priceF = df.format(f);//返回的是String类型
return priceF;
}
@Override
protected void onResume() {
super.onResume();
fetchHandler.sendEmptyMessage(1);
}
@Override
protected void onStop() {
super.onStop();
fetchThread.quit(); //取消
}
MainActivity: 美元汇率:4.6
MainActivity: 美元汇率:3.6
MainActivity: 美元汇率:7.3
MainActivity: 美元汇率:6.3
MainActivity: 美元汇率:9.0
MainActivity: 美元汇率:8.0
上面案例模拟了需要不断的从网络获取数据,下面重源码的角度局分析HandlerThread工作机制
-
创建HandlerThread
HandlerThread fetchThread = new HandlerThread("fetching_thread");
HT01
上图可以看到HandlerThread继承了Thread 并且在初始化的时候 赋值了线程名称和线程优先级(默认为0) 当然可以还自定义线程优先级new HandlerThread(String name, int priority)
-
启动HandlerThread线程
fetchThread.start();//启动线程
TH02
在Thread中调用start()方法就会将run()方法在分线程中去调用执行 HandlerThread在调用start()方法时 在run()方法中创建了Looper对象 并且开启的Looper轮询器Looper.loop()不断的将消息取出 交由发送消息的Handler去处理消息 而这些操作都是在分线程run()方法中执行的(如果有对Handler消息机制不了解的 可以去看看Handler消息机制)
-
获取HandlerThread中的Looper对象创建Handler
HandlerThread fetchThread = new HandlerThread("fetching_thread");
Handler fetchHandler;
fetchHandler = new Handler(fetchThread.getLooper());
TH03
上图是通过new Handler(Looper looper)创建的Handler对象 其作用是需要获取该Looper对象下的MessageQueue对象 这样Handler发送消息的时候 将该消息插入到MessageQueue队列中 Looper就能够从该队列中不断的取消息 再交由Handler处理 如下图:
TH05
- 清空消息
HandlerThread fetchThread = new HandlerThread("fetching_thread");
@Override
protected void onStop() {
super.onStop();
fetchThread.quit();
}
TH06
关于MessageQueue是怎么清空消息的 需要自行对照源码去分析 这里就不多做介绍
最后:
关于HandlerThread和Handler的结合使用就介绍完了 其核心就是在HandlerThread的run()执行了 Looper对象的创建 以及开启Looper.loop()轮询器 在HandlerThread调用start()方法时 run()方法就会在分线程中执行 就导致了Handler在handleMessage(Message msg)处理消息的时候在分线程中执行。