Handler和线程通过Looper挂钩;所有在UI线程中创建的Handler不需要指定Looper,默认设置了MainLooper;所有在子线程中创建的Handler需要通过Loop.prepare()和Loop.loop()来设置子线程的Looper;一个线程只有一个Looper。
创建一个子线程的Handler示例代码如下:
public class MainActivity extends AppCompatActivity {
private String TAG = "testHandler";
private Button testBtn;
class MyThread extends Thread {
public Handler myThreadHandler;
@Override
public void run() {
super.run();
Looper.prepare();
myThreadHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e(TAG, "msg.what:" + msg.what);
}
};
Looper.loop();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
testBtn = (Button) findViewById(R.id.sample_text);
//创建子线程并启动
final MyThread myThread = new MyThread();
myThread.start();
testBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
for (int i = 0; i < 60; i++) {
//使用子线程中的Handler发送消息
myThread.myThreadHandler.sendEmptyMessageDelayed(i, i * 1000);
}
}
});
}
}
先看如下代码:
public class MainActivity extends AppCompatActivity {
private String TAG = "testHandler";
private Handler myHandler;
class MyThread extends Thread {
public Looper myThreadLooper;
@Override
public void run() {
super.run();
Looper.prepare();
myThreadLooper = Looper.myLooper();
Looper.loop();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建子线程并启动
final MyThread myThread = new MyThread();
myThread.start();
//将子线程的Looper对象赋给myHandler
myHandler = new Handler(myThread.myThreadLooper) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e(TAG, "msg what:" + msg.what);
}
};
myHandler.sendEmptyMessage(2);
}
}
在上述代码中涉及到两个线程:UI线程和一个子线程;在UI线程中试图将子线程的Looper对象赋给Handler对象,在子线程运行的时候获取自己的Looper对象。
上述代码运行的时候会报如下错误:
Caused by: java.lang.NullPointerException: Attempt to read from field 'android.os.MessageQueue android.os.Looper.mQueue' on a null object reference
at android.os.Handler.(Handler.java:236)
at android.os.Handler.(Handler.java:140)
at com.cloudecg.jgc.test.androidrestudy.MainActivity$1.(MainActivity.java:46)
at com.cloudecg.jgc.test.androidrestudy.MainActivity.onCreate(MainActivity.java:46)
at android.app.Activity.performCreate(Activity.java:6910)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
即Looper对象为空。
产生上述错误的原因在于多线程并发,当UI线程执行到赋值操作的时候,子线程中的Looper对象还没有创建成功。
使用HandlerThread可以很方便的避免上述多线程并发带来的问题。
将上述代码改为HandlerThread的方式,如下:
public class MainActivity extends AppCompatActivity {
private String TAG = "testHandler";
private Handler myHandler;
private HandlerThread myThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建子线程并启动
myThread = new HandlerThread("MyThreadHandler");
myThread.start();
//将子线程的Looper对象赋给myHandler
myHandler = new Handler(myThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e(TAG, "msg what:" + msg.what);
}
};
myHandler.sendEmptyMessage(2);
}
}
将Thread改为HandlerThread之后就不会产生之前的多线程并发问题了。
原因是在HandlerThread的getLooper()方法中已经做了相关处理,查看源代码如下:
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;
}
在HandlerThread中如果Looper对象没有创建成功,则当前线程一直处于等待状态。
HandlerThread的唤醒源代码如下:
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
在HandlerThread的run方法中如果Looper对象创建成功,则唤醒所有等待线程。