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 Selector和Shape的使用方法
  2. View类xml属性、方法
  3. 【Android 开发】:UI控件之显示图片控件 ImageView 的使用方法
  4. Android与JavaScript方法相互调用!
  5. Android 系统音量最大值的定义位置以及默认值的修改方法
  6. Android AlertDialog的基本使用方法

随机推荐

  1. Mysql数据库设计三范式实例解析
  2. mysql数据类型和字段属性原理与用法详解
  3. 简单了解MYSQL数据库优化阶段
  4. Windows下MySQL主从复制的配置方法
  5. MySQL开启慢查询方法及实例
  6. MySQL5.6 GTID模式下同步复制报错不能跳
  7. mysql学习笔记之完整的select语句用法实
  8. mysql数据表的基本操作之表结构操作,字段
  9. mysql数据库常见基本操作实例分析【创建
  10. mysql事务管理操作详解