Android(安卓)Handler机制
16lz
2021-12-04
Android Handler机制
- handler是如何创建的?
- handler机制是如何运转的?
- Android 系统中的Handler是如何应用的?
- 总结
行到水穷处,坐看云起时。–>王维
handler是如何创建的?
- 我们先在子线程中创建一个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();
- 发送一条消息到消息队列
Message message = Message.obtain(); message.what = 1; message.obj = "haha"; mHandler.sendMessage(message);
- 消息流转过程如图:
最后调用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是如何应用的?
- 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();来开启主线程的消息循环。
- 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; ... }
总结
- MessageQueue叫消息队列,但内部实现并不是队列,是由单链表数据结构,插入和删除快。
- 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)); }
- loop方法是一个死循环,只有当MessageQueue的next方法返回null,才会终止循环。当Looper的quit方法被调用时,通知消息队列退出,然后next方法返回null,才会终止循环。
- 当没有消息时,next方法会一直阻塞在那里,直到有新的消息来。
- 使用Message.obtain()来创建消息,因为内部有个对象池,能够复用,避免大量创建对象
更多相关文章
- Android屏幕元素层次结构
- Android系统启动
- Android(安卓)的消息队列模型
- Android(安卓)SearchView详细使用
- Android(安卓)入门教程:安装 Android(安卓)Studio
- View类xml属性、方法
- android 获取路径目录方法以及判断目录是否存在,创建目录
- android 实用代码片段整理
- Android之Handler用法总结