欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android開(kāi)發(fā)App啟動(dòng)流程與消息機(jī)制詳解

 更新時(shí)間:2022年08月24日 16:29:44   作者:好男人中國(guó)造  
這篇文章主要為大家介紹了Android開(kāi)發(fā)App啟動(dòng)流程與消息機(jī)制詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

相信很多人對(duì)這個(gè)問(wèn)題不陌生,但是大家回答的都比較簡(jiǎn)單,如談到app啟動(dòng)流程有人就會(huì)是app的生命周期去了,談到消息機(jī)制有人就會(huì)說(shuō)looper循環(huán)消息進(jìn)行分發(fā),如果是面試可能面試官不會(huì)滿(mǎn)意,今天我們搞一篇完善的源碼解析來(lái)進(jìn)行闡述上面的問(wèn)題

1、第一步了解 ThreadLocal

什么是ThreadLocal呢,專(zhuān)業(yè)的來(lái)講,ThreadLocal 是一個(gè)線程內(nèi)部的數(shù)據(jù)存儲(chǔ)類(lèi),通過(guò)它可以在指定的線程中存儲(chǔ)數(shù)據(jù),數(shù)據(jù)存儲(chǔ)以后,只有再指定線程中可以獲取到存儲(chǔ)的數(shù)據(jù),對(duì)于其他線程來(lái)說(shuō)則無(wú)法獲取到數(shù)據(jù),是共享數(shù)據(jù)變量存儲(chǔ),通俗的來(lái)講,就是保存每個(gè)線程的數(shù)據(jù),肯定大家都沒(méi)聽(tīng)懂,沒(méi)事的,接下來(lái)我們通過(guò)代碼來(lái)解釋ThreadLocal的具體作用

首先看一個(gè)例子

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);
    }

打印結(jié)果

1主線程-->  data--1
2主線程-->  data--2
線程2--->  data--1
3主線程-->  data--2
線程3--->  data-->3

從上面的例子我們可以看到,ThreadLocal保存一個(gè)String這個(gè)變量,這個(gè)變量初始化會(huì)有一個(gè)值,在接下來(lái)的線程種,每個(gè)線程都會(huì)擁有一個(gè)初始值,這個(gè)初始值在主線程中,一旦這個(gè)初始值發(fā)生改變,如果是在主線程種改變?nèi)邕M(jìn)行set,則后面的子線程獲取的都是這個(gè)改變后的值,但是如果子線程種也改變了這個(gè)值,則只在當(dāng)前子線程種有此值 沒(méi)其子線程還是獲取的主線程種那個(gè)值,我們來(lái)簡(jiǎn)單畫(huà)個(gè)圖給大家

ThreadLocal種的三個(gè)重要方法

//默認(rèn)情況下initialValue是返回為空的
    protected T initialValue() {
        return null;
    }
//在get的時(shí)候如果沒(méi)有調(diào)用set方法  getMap(t);是返回為空的,所以,返回的是setInitialValue(),這些方法請(qǐng)看后面的介紹,而setInitialValue方法返回的其實(shí)就是初始值   
    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();
    }
    //這個(gè)方法在在調(diào)用的時(shí)候?qū)嶋H上getMap(t)是為空的,所以就會(huì)調(diào)用createMap,這個(gè)方法會(huì)把當(dāng)前的線程作為值,保證getMap再調(diào)用就不會(huì)為空
    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);
    }

簡(jiǎn)單來(lái)講,就是自己有的,用自己的,自己沒(méi)有就用初始化的,初始化改變了,后面的也改變,但是自己設(shè)置的,還是用自己的,就這么簡(jiǎn)單,好了,接下來(lái)進(jìn)行下一步

2、App的啟動(dòng)流程

我們看下Android的源碼

//這是main函數(shù)的入口
 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("&lt;pre-initialized&gt;");
        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");
    }

我們重點(diǎn)看下 Looper.prepareMainLooper();這個(gè)方法

 /**
     * 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();
        }
    }

我們?cè)冱c(diǎn)擊去看,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();
    }

很驚訝的看見(jiàn)了 sThreadLocal,這里是調(diào)用get方法

  // sThreadLocal.get() will return null unless you've called prepare().
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

這里我們可以看到ThreadLocal保存的是Looper這個(gè)對(duì)象

    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));
    }

這里調(diào)用了set方法,創(chuàng)建了一個(gè)全局唯一的Looper

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

創(chuàng)建了一個(gè)全局唯一的主線程消息隊(duì)列

3、Activity中創(chuàng)建Handler

  • 創(chuàng)建一個(gè)handler,重寫(xiě)handleMessage方法
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    };
  • 發(fā)送消息
        Message message = new Message();
        handler.sendMessage(message);
	//點(diǎn)擊去
    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
	//點(diǎn)擊去
	    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis &lt; 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
//繼續(xù)看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,我們看這個(gè)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啟動(dòng)后那個(gè)唯一的Queue,好了我們整理下Handler的消息機(jī)制

hander發(fā)送消息的時(shí)候,調(diào)用sendMessage方法,handler種會(huì)講消息放到全局的消息隊(duì)列中queue.enqueueMessage(msg, uptimeMillis)接著就會(huì)在MessageQueue種賦值全局消息

消息處理

消息消費(fèi)

以上就是Android開(kāi)發(fā)App啟動(dòng)流程與消息機(jī)制詳解的詳細(xì)內(nèi)容,更多關(guān)于Android App啟動(dòng)流程消息機(jī)制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論