您的位置:首页 > 移动开发 > Android开发

Android在子线创建Handler出现异常的原因及解决办法

2018-04-11 20:58 309 查看
在日常的代码编写中,Handler主要是用来进行线程间通信的一种手段,或者说一种工具来使用,一般我们都会将handler写在主线程中,然后开启一个Thread,在里面进行post或者sendMessage,将Message从MessageQueue中送给Handler,然后我们获取数据进行UI更新。
但是这是为什么呢?其实每一个Handler都会有一个MessageQueue,而MessageQueue是被封装在Looper中的,而Looper又会关联一个线程,最后就相当于一个MessageQueue关联了线程,一个线程只有一个MessageQueue,一个Looper,之后在通过Message来打到线程间通信。
默认情况下,只有一个MessageQueue就是主线程会通过Looper.java中的prepareMainLooper()方法来创建出来,也就是Looper的生成时,会自动产生一个MessageQueue。
但是有一点要注意子线程默认情况下是没有Looper的更不会有MessageQueue;
那么Looper是怎么创建的呢,Looper在主线程中,是通过prepareMainLooper()这个方法中的prepare()创建的源码如下:/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
public static void prepare() {
prepare(true);
}

private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {     //如果looper的线程不唯一,抛出异常,looper已经在该线程被创建了
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed)); //否则,创建一个looper 并且绑定到创建Looper的线程
}

/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself.  See also: {@link #prepare()}
*/
创建了MessageQueue之后,Looper就要绑定到创建Looper的线程,同时进行死循环,不断传递MessageQueue中的Message给Handler,让handler处理。
下面我们看一段部分源码 这段源码的主要功能就是死循环不断传递MessageQueue中的Message给Handler public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
        for (;;) {
Message msg = queue.next();     //MessageQueue是一个队列结构 不断地调用.next传递Message
if (msg == null) { //这里可以看出Message是可以为空的。
// No message indicates that the message queue is quitting.
return;
}

通常我们会认为子线程是不能创建handler的,但是这是为什么呢,我们先开启一个子线程,在里面创建一个handler看看会发生什么吧。public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(){
Handler handler = null;
@Override
public void run() {
handler = new Handler();
}
}.start();

}
}
我们的程序崩溃了,同时抛出了Can't create handler inside thread that has not called Looper.prepare()的异常,这个异常的意思为,我们不能在子线程创建hadnler,因为无法调用Looper.prepare()方法,

所以我们无法使用Handler的原因就是Looper.prepare()是用来创建Looper的,因为子线程默认不会产生Looper,所以也没办法产生MessageQueue,也不能发送Message来进行通信了,
解决办法很简单,只要我们手动执行Looper的prepare方法创建一个Looper,在执行prepare的时候,Looper会自动创建一个MessageQueue,并且绑定到Looper所在的线程,
然后通过调用loop方法,开启无限循环就可以正常的在子线程执行Handler了代码如下:

public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(){
Handler handler = null;
@Override
public void run() {
Looper.prepare(); //创建一个Looper,同时创建了MessageQueue,并且绑定了线程
handler = new Handler();
Looper.loop();//开启Looper的循环

}
}.start();

}

}


总结:
1.子线程是可以创建Handler的,不能创建的原因是因为子线程默认不会创建Looper,当Looper为空就会抛出上述异常,导致程序崩溃掉。
2.Looper.prepare()方法会创建一个Looper对象,并且创建的同时通过sThreadLocal.set(new Looper(quitAllowed)); 这行代码来为创建的Looper绑定线程,同时Looper创建的同时会产生一个MessageQueue。
3.Looper.loop()方法会开启死循环,不断地遍历MessageQueue。
4.解决办法子线程不能创建Handler的方法 手动调用Looper.prepare()方法创建一个Looper并且调用Looper.loop()开启循环就可以了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  源码 Android
相关文章推荐