<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
相信很多人對這個問題不陌生,但是大家回答的都比較簡單,如談到app啟動流程有人就會是app的生命週期去了,談到訊息機制有人就會說looper迴圈訊息進行分發,如果是面試可能面試官不會滿意,今天我們搞一篇完善的原始碼解析來進行闡述上面的問題
什麼是ThreadLocal呢,專業的來講,ThreadLocal 是一個執行緒內部的資料儲存類,通過它可以在指定的執行緒中儲存資料,資料儲存以後,只有再指定執行緒中可以獲取到儲存的資料,對於其他執行緒來說則無法獲取到資料,是共用資料變數儲存,通俗的來講,就是儲存每個執行緒的資料,肯定大家都沒聽懂,沒事的,接下來我們通過程式碼來解釋ThreadLocal的具體作用
首先看一個例子
public static void main(String[] args) throws InterruptedException { ThreadLocal<String> threadLocal = new ThreadLocal<String>(){ @Override protected String initialValue() { return "data--1"; } }; System.out.println("1主執行緒--> "+threadLocal.get()); Thread t1 = new Thread(()->{ }); t1.start(); threadLocal.set("data--2"); System.out.println("2主執行緒--> "+threadLocal.get()); Thread t2 = new Thread(()->{ System.out.println("執行緒2---> "+threadLocal.get()); }); t2.start(); Thread t3 = new Thread(()->{ threadLocal.set("data-->3"); System.out.println("執行緒3---> "+threadLocal.get()); }); t3.start(); System.out.println("3主執行緒--> "+threadLocal.get()); Thread.sleep(1000); }
列印結果
1主執行緒--> data--1
2主執行緒--> data--2
執行緒2---> data--1
3主執行緒--> data--2
執行緒3---> data-->3
從上面的例子我們可以看到,ThreadLocal儲存一個String這個變數,這個變數初始化會有一個值,在接下來的執行緒種,每個執行緒都會擁有一個初始值,這個初始值在主執行緒中,一旦這個初始值發生改變,如果是在主執行緒種改變如進行set,則後面的子執行緒獲取的都是這個改變後的值,但是如果子執行緒種也改變了這個值,則只在當前子執行緒種有此值 沒其子執行緒還是獲取的主執行緒種那個值,我們來簡單畫個圖給大家
ThreadLocal種的三個重要方法
//預設情況下initialValue是返回為空的 protected T initialValue() { return null; } //在get的時候如果沒有呼叫set方法 getMap(t);是返回為空的,所以,返回的是setInitialValue(),這些方法請看後面的介紹,而setInitialValue方法返回的其實就是初始值 public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); } //這個方法在在呼叫的時候實際上getMap(t)是為空的,所以就會呼叫createMap,這個方法會把當前的執行緒作為值,保證getMap再呼叫就不會為空 public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; } public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); } ThreadLocalMap getMap(Thread t) { return t.threadLocals; } void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
簡單來講,就是自己有的,用自己的,自己沒有就用初始化的,初始化改變了,後面的也改變,但是自己設定的,還是用自己的,就這麼簡單,好了,接下來進行下一步
我們看下Android的原始碼
//這是main函數的入口 public static void main(String[] args) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain"); SamplingProfilerIntegration.start(); // 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("<pre-initialized>"); Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); 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();
這個方法
/** * Initialize the current thread as a looper, marking it as an * application's main looper. The main looper for your application * is created by the Android environment, so you should never need * to call this function yourself. See also: {@link #prepare()} */ public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }
我們再點選去看,myLooper
/** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. */ public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
很驚訝的看見了 sThreadLocal
,這裡是呼叫get方法
// sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
這裡我們可以看到ThreadLocal儲存的是Looper這個物件
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)); }
這裡呼叫了set方法,建立了一個全域性唯一的Looper
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
建立了一個全域性唯一的主執行緒訊息佇列
private Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } };
Message message = new Message(); handler.sendMessage(message); //點選去 public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } //點選去 public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }
//繼續看sendMessageAtTime public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); } private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
//我們看到了enqueueMessage,我們看這個queue在哪裡獲取的 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; }
到這裡我們明白了,也就是再app啟動後那個唯一的Queue,好了我們整理下Handler的訊息機制
hander傳送訊息的時候,呼叫sendMessage方法,handler種會講訊息放到全域性的訊息佇列中queue.enqueueMessage(msg, uptimeMillis)
接著就會在MessageQueue種賦值全域性訊息
訊息處理
訊息消費
以上就是Android開發App啟動流程與訊息機制詳解的詳細內容,更多關於Android App啟動流程訊息機制的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45