5 Handler与子线程
5-1 自定义与线程相关的Handler
1.在线程中通过Looper.prepare()方法创建一个与线程相关的Looper对象;
2. 在线程中通过Handler的new关键字,创建一个Handler对象,这个对象在创建的时候会关联上1中创建的Looper对象
3. 调用Looper对象的loop()方法去轮询它的MessageQueue
4. 通过其他的线程拿到这个线程的Handler对象之后调用sendMessage()之后,在这个线程中就可以进行Message的处理了。
我们一般是在主线程中创建Handler对象,在主线程中处理Message,在子线程中调用这个Handler对象的sendMessage()来发送message。所以Handler是在哪个线程创建就有哪个线程处理Message和轮询,而由别的线程负责给这个Handler发送Message。
1.注意:在主线程中创建的Handler的handleMessage()方法不要写耗时的操作,否则会导致UI卡死,因为这个handleMessage()方法是在UI线程中调用的。
package com.example.yzx; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.widget.TextView; public class SecondActivity extends Activity { private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { System.out.println("UI---------" + Thread.currentThread()); }; }; class MyThread extends Thread { public Handler handler; @Override public void run() { // TODO Auto-generated method stub Looper.prepare(); handler = new Handler() { @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub System.out.println("currentThead:" + Thread.currentThread()); } }; Looper.loop(); } } private MyThread thread; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); TextView textView = new TextView(this); textView.setText("hellow Handler"); setContentView(textView); thread = new MyThread(); thread.start(); try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } thread.handler.sendEmptyMessage(1); handler.sendEmptyMessage(1); } }
5-2 HanlderThread是什么 (11:51)
HandlerThread避免多线程导致空指针问题。
handlerthread 默认【创建一个looper然后和一handler关联,那么所有的handleMessage方法是在一个子线程中进行,可以用handlerthread模拟一个异步任务,将主线程的任务发送个子线程,处理一些比较耗时操作
-----------------------------------------------------------------------------------------
1.一个Handler的创建它就会被绑定到这个线程的消息队列中,如果是在主线程创建的,那就不需要写代码来创建消息队列了,默认的消息队列会在主线程被创建。但是如果是在子线程的话,就必须在创建Handler之前先初始化线程的消息队列
2.HandlerThread继承于Thread,所以它本质就是个Thread。与普通Thread的差别就在于,它有个Looper成员变量。这个Looper其实就是对消息队列以及队列处理逻辑的封装,简单说就是 消息队列+消息循环。
在其run()方法中,调用Looper.myLooper()获得一个looper对象。
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
在创建handler时使用getLooper()方法,其实现其实是一直等待looper对象的获得。
while (isAlive() && mLooper == null) {
try {
wait();
}
}
3.Handler在创建的时候可以指定Looper,这样通过Handler的sendMessage()方法发送出去的消息就会添加到指定Looper里面的MessageQueue里面去。在不指定Looper的情况下,Handler绑定的是创建它的线程的Looper。如果这个线程的Looper不存在,程序将抛出"Can't create handler inside thread that has not called Looper.prepare()"。
- 创建Handler的时指定的looper,可以是别的线程创建的。所以Handler中MessageQueue的轮询不一定非要是创建Handler的线程进行,还可以在别的线程中进行。
这个时候我们就需要使用HandlerThread这个类来创建这个Looper了,这样消息的处理就在新创建的HandlerThread中进行。(如图)
mThread = new HandlerThread("Handler Thread");
mHandler = new Handler(mThread.getLooper()){
public void handleMessage(android.os.Message msg) {
... };
};
两个线程切换的过程中,looper没有创建 会抛出控制异常
handlerThread用来避免这个异常
package com.example.yzx; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.widget.TextView; public class threeActivity extends Activity { private TextView text; private HandlerThread thread; private Handler handler; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); text = new TextView(this); text.setText("handler Thread"); setContentView(text); thread = new HandlerThread("handler thread"); thread.start(); handler = new Handler(thread.getLooper()) { @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub System.out.println("current thread---------->" + Thread.currentThread()); } }; handler.sendEmptyMessage(1); } }