简介
在 Android 中,只有主线程才能操作 UI,但是主线程不能进行耗时操作,否则会阻塞线程,产生 ANR 异常,所以常常把耗时操作放到其它子线程进行。如果在子线程中需要更新 UI,一般是通过 Handler
发送消息,主线程接受消息并且进行相应的逻辑处理。除了直接使用 Handler
,还可以通过 View 的 post
方法以及 Activity 的 runOnUiThread
方法来更新 UI,它们内部也是利用了 Handler
。在上一篇文章 Android AsyncTask源码分析 中也讲到,其内部使用了 Handler
把任务的处理结果传回 UI 线程。
本文深入分析 Android 的消息处理机制,了解 Handler
的工作原理。
Handler
先通过一个例子看一下 Handler
的用法。
public class MainActivity extends AppCompatActivity { private static final int MESSAGE_TEXT_VIEW = 0; private TextView mTextView; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_TEXT_VIEW: mTextView.setText("UI成功更新"); default: super.handleMessage(msg); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); mTextView = (TextView) findViewById(R.id.text_view); new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } mHandler.obtainMessage(MESSAGE_TEXT_VIEW).sendToTarget(); } }).start(); } }
上面的代码先是新建了一个 Handler
的实例,并且重写了 handleMessage
方法,在这个方法里,便是根据接受到的消息的类型进行相应的 UI 更新。那么看一下 Handler
的构造方法的源码:
public Handler(Callback callback, boolean async) { 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 = callback; mAsynchronous = async; }
在构造方法中,通过调用 Looper.myLooper()
获得了 Looper
对象。如果 mLooper
为空,那么会抛出异常:”Can’t create handler inside thread that has not called Looper.prepare()”,意思是:不能在未调用 Looper.prepare()
的线程创建 handler
。上面的例子并没有调用这个方法,但是却没有抛出异常。其实是因为主线程在启动的时候已经帮我们调用过了,所以可以直接创建 Handler
。如果是在其它子线程,直接创建 Handler
是会导致应用崩溃的。
在得到 Handler
之后,又获取了它的内部变量 mQueue
, 这是 MessageQueue
对象,也就是消息队列,用于保存 Handler
发送的消息。
到此,Android 消息机制的三个重要角色全部出现了,分别是 Handler
、Looper
以及 MessageQueue
。 一般在代码我们接触比较多的是 Handler
,但 Looper
与 MessageQueue
却是 Handler
运行时不可或缺的。
Looper
上一节分析了 Handler
的构造,其中调用了 Looper.myLooper()
方法,下面是它的源码:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
共同學習,寫下你的評論
評論加載中...
作者其他優質文章