Android Handler机制

      • handler是如何创建的?
      • handler机制是如何运转的?
      • Android 系统中的Handler是如何应用的?
      • 总结

行到水穷处,坐看云起时。–>王维

handler是如何创建的?

  1. 我们先在子线程中创建一个handler,代码如下:
new Thread(new Runnable() {            @Override            public void run() {                Handler handler = new Handler();            }        }).start();

运行会抛出

Can’t create handler inside thread Thread[Thread-2,5,main] that has
not called Looper.prepare()

异常。跟踪到handler的构造方法里发现

public Handler(@Nullable 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());            }        }//取存储在sThreadLocal中的looper()对象        mLooper = Looper.myLooper();        if (mLooper == null) {            throw new RuntimeException(                "Can't create handler inside thread " + Thread.currentThread()                        + " that has not called Looper.prepare()");        }        mQueue = mLooper.mQueue;        mCallback = callback;        mAsynchronous = async;    }

当你new handler()的时候,并没有Looper,导致抛出了异常。

new Thread(new Runnable() {            @Override            public void run() {            //先通过这个静态方法创建looper,并存储在sThreadLocal中.                Looper.prepare();                Handler handler = new Handler();            }        }).start();
  • 在Looper.prepare()方法调用时,创建looper,并存储在sThreadLocal中。
  • 在looper构造方法中,又创建了MessageQueue。
private Looper(boolean quitAllowed) {        mQueue = new MessageQueue(quitAllowed);        mThread = Thread.currentThread();    }

以上我们就创建好了messageQueue,Looper和Handler,可以愉快的玩耍了。

handler机制是如何运转的?

1.调用Looper.loop();开启循环,消息机制开始运转

 new Thread(new Runnable() {            @Override            public void run() {                Looper.prepare();                mHandler = new Handler(){                    @Override                    public void handleMessage(@NonNull Message msg) {//                        super.handleMessage(msg);                        if (msg.what ==1){                            Toast.makeText(MainActivity.this,msg.obj.toString(),Toast.LENGTH_SHORT).show();                        }                    }                };                Looper.loop();            }        }).start();
  1. 发送一条消息到消息队列
  Message message = Message.obtain();        message.what = 1;        message.obj = "haha";        mHandler.sendMessage(message);
  1. 消息流转过程如图:
Handler MessageQueue Looper sendMessage发送消息 调用enqueueMessage,把消息加入到消息队列 loop()方法循环取消息队列中的消息 调用msg.target.dispatchMessage(msg)分发消息 handleMessage处理消息 Handler MessageQueue Looper

最后调用handleMessage处理消息

/**     * Handle system messages here.     */    public void dispatchMessage(@NonNull Message msg) {        if (msg.callback != null) {            handleCallback(msg);        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            handleMessage(msg);        }    }

Android 系统中的Handler是如何应用的?

  1. Android 的主线程就是ActivityThread,主线程的入口方法为main
public static void main(String[] args) {        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");        // CloseGuard defaults to true and can be quite spammy.  We        // disable it here, but selectively enable it later (via        // StrictMode) on debug builds, but using DropBox, not logs.        CloseGuard.setEnabled(false);        Environment.initForCurrentUser();        // Set the reporter for event logging in libcore        EventLogger.setReporter(new EventLoggingReporter());        // Make sure TrustedCertificateStore looks in the right place for CA certificates        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());        TrustedCertificateStore.setDefaultUserDirectory(configDir);        Process.setArgV0("");        Looper.prepareMainLooper();        // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.        // It will be in the format "seq=114"        long startSeq = 0;        if (args != null) {            for (int i = args.length - 1; i >= 0; --i) {                if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {                    startSeq = Long.parseLong(                            args[i].substring(PROC_START_SEQ_IDENT.length()));                }            }        }        ActivityThread thread = new ActivityThread();        thread.attach(false, startSeq);        if (sMainThreadHandler == null) {            sMainThreadHandler = thread.getHandler();        }        if (false) {            Looper.myLooper().setMessageLogging(new                    LogPrinter(Log.DEBUG, "ActivityThread"));        }        // End of event ActivityThreadMain.        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);        Looper.loop();        throw new RuntimeException("Main thread loop unexpectedly exited");    }

通过Looper.prepareMainLooper()来创建主线程的Looper以及MessageQueue,并通过Looper.loop();来开启主线程的消息循环。

  1. ActivityThread内部类H继承了Handler,负责处理一些系统消息。
class H extends Handler {        public static final int BIND_APPLICATION        = 110;        @UnsupportedAppUsage        public static final int EXIT_APPLICATION        = 111;        @UnsupportedAppUsage        public static final int RECEIVER                = 113;        @UnsupportedAppUsage        public static final int CREATE_SERVICE          = 114;        ...  }

总结

  1. MessageQueue叫消息队列,但内部实现并不是队列,是由单链表数据结构,插入和删除快。
  2. handler可以创建多个,但Looper一个线程只有一个,由sThreadLocal存储。
private static void prepare(boolean quitAllowed) {        if (sThreadLocal.get() != null) {            throw new RuntimeException("Only one Looper may be created per thread");        }        sThreadLocal.set(new Looper(quitAllowed));    }
  1. loop方法是一个死循环,只有当MessageQueue的next方法返回null,才会终止循环。当Looper的quit方法被调用时,通知消息队列退出,然后next方法返回null,才会终止循环。
  2. 当没有消息时,next方法会一直阻塞在那里,直到有新的消息来。
  3. 使用Message.obtain()来创建消息,因为内部有个对象池,能够复用,避免大量创建对象

更多相关文章

  1. Android屏幕元素层次结构
  2. Android系统启动
  3. Android(安卓)的消息队列模型
  4. Android(安卓)SearchView详细使用
  5. Android(安卓)入门教程:安装 Android(安卓)Studio
  6. View类xml属性、方法
  7. android 获取路径目录方法以及判断目录是否存在,创建目录
  8. android 实用代码片段整理
  9. Android之Handler用法总结

随机推荐

  1. Android中常用adb命令及Log使用
  2. textView写点击选中和没选中效果
  3. mac下android studio安装plantuml插件
  4. 谁是最受欢迎的Linux发行版?
  5. Android理解Fragment生命周期,fragment和
  6. Android(安卓)HIDL 中 hidl-gen使用
  7. 一个WebView Native Crash分析过程,居然是
  8. 大神博客资源
  9. Android(安卓)Studio无法使用Apache的Htt
  10. Android(安卓)环境搭建