一.Handler机制
安卓把UI和耗时操作分在不同线程的原因:
- 为了保证UI线程流程性
- 手机显示的刷新频路:60Hz,即1秒60次,每16.67毫秒刷一次,为了不丢帧,那么主线程处理代码最好不要超过16毫秒.
- 当子线程处理完耗时才走后,为了防止UI线程处理逻辑的混乱,就通过Handler来充当主线程和子线程间的桥梁.
逻辑:
- 1.Handler在主线程Activity
- 2.复写Handler的HandlerMessage方法
- 3.子线程通过调用handler.sendMessage(),主线程就会执行HandlderMessage方法
完整的Handler机制,参数的讲解:
- 1.除了Handler,Message,还有隐藏的Looper和MessageQueue对象
- 2.主线程默认调用Looper.preper()方法;
- 目的:在Looper里创建MessageQueue成员变量,且吧Looper对象绑定到当前线程
- 当调用Handler 的sendMessage(对象)方法,就将Message对象添加到了Looper创建的MessageQueue队列中,同时给Message指定了target 对象.
(PS:target对象就是 Handler 对象)
- 3.主线程也默认执行Looper.looper()方法,该方法从Looper成员变量的MessageQueue中取出Message
- 然后调用Message的targe对象的handleMessage()方法
可以再谈一下消息的回收机制
二.事件分发机制
这个是面试必问的,也是我们必懂的,请大家点击专题访问学习.
(点击访问专题)
三.主线程如何向子线程发送Message消息?
法1:使用IntentService
- 写一个类继承Intent服务,然后重写onHandleIntent(Intent intent)方法即可,该类中该方法是在子线程中.
- 启动服务并传过来就是在子线程中获取信息了,然后还可再往当前主线程发消息谈Toast;
(点击链接访问专题)
法2:通过Handler和Looper发送
- 既然我们说Hander是主线程和子线程沟通的桥梁,那么Handler肯定有办法也能主传给子.
具体逻辑是(和我们平时的正好相反,并且多加了Looper的3个方法):
子线程:
- 1.Looper准备
- 2.新建Hander对象
- (Looper.myLooper()为的是外部调用后能跳出消息循环)
- 3.Looper让消息循环
onStart开启线程,然后点击1的时候主线程就往里发消息,点击2和销毁的时候跳出消息循环,预防内存泄露
代码如下:
public class MainActivity2 extends Activity {
private Handler mMySubHandler;
private Looper myLooper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
}
@Override
protected void onStart() {
super.onStart();
/**
* 当Activity启动的时候创建一个子线程,并启动
*/
MyThread myThread = new MyThread();
myThread.start();
}
/**
* 绑定布局中的点击按钮,点击后给子线程发送消息
* @param view
*/
public void click(View view) {
Message msg = new Message();
msg.obj = "MainActivity";
mMySubHandler.sendMessage(msg);
}
/**
* 按钮2,关闭子线程,让子线程退出
* 即让子线程的Looper对象退出即可,因为Looper.loop();是"线程阻塞"
*/
public void click2(View view) {
if (myLooper != null) {//不是空证明还有,但要退出了
myLooper.quit();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//退出的时候也要释放,不然可能内存泄露
if (myLooper != null) {
myLooper.quit();
}
}
//子线程
class MyThread extends Thread {
@Override
public void run() {
//1.创建一个Looper对象
//(内部创建了MessageQueue,并将MessageQueue作为Looper对象的成员,然后将Looper对象绑定到ThreadLocal中,Handler思维)
Looper.prepare();
//创建Handler
mMySubHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
//处理主线程发送的消息
System.out.println("接收到主线程发来的消息 : " + msg.obj);
}
};
//2.获取当前的Looper对象,myLooper为的是外部调用后能跳出消息循环
myLooper = Looper.myLooper();
//3.让消息循环起来
Looper.loop();
System.out.println("子线程退出");
}
}
}
- 运行结果:
点击1时
I/System.out: 接收到主线程发来的消息 : MainActivity
点击2时:
I/System.out: 子线程退出