之前也是由于周末通宵看TI3比赛,一直没找到时间写博客,导致已经有好久没更新了。惭愧!后面还会 恢复进度,尽量保证每周都写吧。这里也是先恭喜一下来自瑞典的Alliance战队夺得了TI3的冠军,希望明年 中国战队能够虎起!
开始进入正题,我们都知道,Android UI是线程不安全的,如果在子线程中尝试 进行UI操作,程序就有可能会崩溃。相信大家在日常的工作当中都会经常遇到这个问题,解决的方案应该也 是早已烂熟于心,即创建一个Message对象,然后借助Handler发送出去,之后在Handler的handleMessage() 方法中获得刚才发送的Message对象,然后在这里进行UI操作就不会再出现崩溃了。
这种处理方式被 称为异步消息处理线程,虽然我相信大家都会用,可是你知道它背后的原理是什么样的吗?今天我们就来一 起深入探究一下Handler和Message背后的秘密。
首先来看一下如何创建Handler对象。你可能 会觉得挺纳闷的,创建Handler有什么好看的呢,直接new一下不就行了?确实,不过即使只是简单new一下, 还是有不少地方需要注意的,我们尝试在程序中创建两个Handler对象,一个在主线程中创建,一个在子线程 中创建,代码如下所示:
public class MainActivity extends Activity { private Handler handler1; private Handler handler2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); handler1 = new Handler(); new Thread(new Runnable() { @Override public void run() { handler2 = new Handler(); } }).start(); } }
如果现在运行一下程序,你会发现,在子线程中创建的Handler是会导致程序崩溃的,提示的错误 信息为 Can't create handler inside thread that has not called Looper.prepare() 。说是不能在 没有调用Looper.prepare() 的线程中创建Handler,那我们尝试在子线程中先调用一下Looper.prepare()呢 ,代码如下所示:
new Thread(new Runnable() { @Override public void run() { Looper.prepare(); handler2 = new Handler(); } }).start();
果然这样就不会崩溃了,不过只满足于此显然是不够的,我们来看下Handler的源码, 搞清楚为什么不调用Looper.prepare()就不行呢。Handler的无参构造函数如下所示:
public Handler() { if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; mCallback = null; }
可以看到,在第10行调用了Looper.myLooper()方法获取了一个Looper对象,如果Looper对象为空 ,则会抛出一个运行时异常,提示的错误正是 Can't create handler inside thread that has not called Looper.prepare()!那什么时候Looper对象才可能为空呢?这就要看看Looper.myLooper()中的代码 了,如下所示:
public static final Looper myLooper() { return (Looper)sThreadLocal.get(); }
以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索线程
, new
, handler
, 中创
, prepare
, Looper
, looper.prepare
Handler+线程
handler message、messagehandler、handler message 传值、handlermessage、安卓 handler message,以便于您获取更多的相关知识。