成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

Android異步消息機(jī)制

blair / 2258人閱讀

摘要:在子線程中發(fā)送消息,主線程接受到消息并且處理邏輯。子線程往消息隊(duì)列發(fā)送消息,并且往管道文件寫數(shù)據(jù),主線程即被喚醒,從管道文件讀取數(shù)據(jù),主線程被喚醒只是為了讀取消息,當(dāng)消息讀取完畢,再次睡眠。

目錄介紹

1.Handler的常見的使用方式

2.如何在子線程中定義Handler

3.主線程如何自動(dòng)調(diào)用Looper.prepare()

4.Looper.prepare()方法源碼分析

5.Looper中用什么存儲(chǔ)消息

6.Handler發(fā)送消息如何運(yùn)作

7.Looper.loop()方法源碼分析

8.runOnUiThread如何實(shí)現(xiàn)子線程更新UI

9.Handler的post方法和view的post方法

10.主線程中Looper的輪詢死循環(huán)為何沒阻塞主線程

11.得出部分結(jié)論

好消息

01.基礎(chǔ)組件(9篇)

02.IPC機(jī)制(0篇)

03.View原理(7篇)

04.動(dòng)畫機(jī)制(2篇)

05.View事件(9篇)

06.消息機(jī)制(6篇)

07.多媒體(9篇)

08.View事件(4篇)

09.多線程(4篇)

10.Window(11篇)

11.WebView(4篇)

12.網(wǎng)絡(luò)相關(guān)(7篇)

13.注解(14篇)

14.音視頻(13篇)

15.優(yōu)化相關(guān)(8篇)

16.設(shè)計(jì)模式(4篇)

20.零碎筆記(12篇)

21.kotlin學(xué)習(xí)(1篇)

22.源碼分析(11篇)

23.架構(gòu)技術(shù)(13篇)

25.RecyclerView(21篇)

博客筆記大匯總【16年3月到至今】,包括Java基礎(chǔ)及深入知識(shí)點(diǎn),Android技術(shù)博客,Python學(xué)習(xí)筆記等等,還包括平時(shí)開發(fā)中遇到的bug匯總,當(dāng)然也在工作之余收集了大量的面試題,長期更新維護(hù)并且修正,持續(xù)完善……開源的文件是markdown格式的!同時(shí)也開源了生活博客,從12年起,積累共計(jì)N篇[近100萬字,陸續(xù)搬到網(wǎng)上],轉(zhuǎn)載請注明出處,謝謝!

鏈接地址:https://github.com/yangchong2...

如果覺得好,可以star一下,謝謝!當(dāng)然也歡迎提出建議,萬事起于忽微,量變引起質(zhì)變!

1.Handler的常見的使用方式

handler機(jī)制大家都比較熟悉呢。在子線程中發(fā)送消息,主線程接受到消息并且處理邏輯。如下所示

一般handler的使用方式都是在主線程中定義Handler,然后在子線程中調(diào)用mHandler.sendXx()方法,這里有一個(gè)疑問可以在子線程中定義Handler嗎?

public class MainActivity extends AppCompatActivity {

    private TextView tv ;

    /**
     * 在主線程中定義Handler,并實(shí)現(xiàn)對應(yīng)的handleMessage方法
     */
    public static Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == 101) {
                Log.i("MainActivity", "接收到handler消息...");
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.tv);
        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread() {
                    @Override
                    public void run() {
                        // 在子線程中發(fā)送異步消息
                        mHandler.sendEmptyMessage(1);
                    }
                }.start();
            }
        });
    }
}

2.如何在子線程中定義Handler

直接在子線程中創(chuàng)建handler,看看會(huì)出現(xiàn)什么情況?

運(yùn)行后可以得出在子線程中定義Handler對象出錯(cuò),難道Handler對象的定義或者是初始化只能在主線程中?其實(shí)不是這樣的,錯(cuò)誤信息中提示的已經(jīng)很明顯了,在初始化Handler對象之前需要調(diào)用Looper.prepare()方法

tv.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        new Thread() {
            @Override
            public void run() {
                Handler mHandler = new Handler() {
                    @Override
                    public void handleMessage(Message msg) {
                        if (msg.what == 1) {
                            Log.i(TAG, "在子線程中定義Handler,接收并處理消息");
                        }
                    }
                };
            }
        }.start();
    }
});

如何正確運(yùn)行。在這里問一個(gè)問題,在子線程中可以吐司嗎?答案是可以的,只不過又條件,詳細(xì)可以看這篇文章02.Toast源碼深度分析

這樣程序已經(jīng)不會(huì)報(bào)錯(cuò),那么這說明初始化Handler對象的時(shí)候我們是需要調(diào)用Looper.prepare()的,那么主線程中為什么可以直接初始化Handler呢?難道是主線程創(chuàng)建handler對象的時(shí)候,會(huì)自動(dòng)調(diào)用Looper.prepare()方法的嗎?

tv.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        new Thread() {
            @Override
            public void run() {
                Looper.prepare();
                Handler mHandler = new Handler() {
                    @Override
                    public void handleMessage(Message msg) {
                        if (msg.what == 1) {
                            Log.i(TAG, "在子線程中定義Handler,接收并處理消息");
                        }
                    }
                };
                Looper.loop();
            }
        }.start();
    }
});
3.主線程如何自動(dòng)調(diào)用Looper.prepare()

首先直接可以看在App初始化的時(shí)候會(huì)執(zhí)行ActivityThread的main方法中的代碼,如下所示

可以看到Looper.prepare()方法在這里調(diào)用,所以在主線程中可以直接初始化Handler了。

public static void main(String[] args) {
    //省略部分代碼
    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"));
    }
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

并且可以看到還調(diào)用了:Looper.loop()方法,可以知道一個(gè)Handler的標(biāo)準(zhǔn)寫法其實(shí)是這樣的

Looper.prepare();
Handler mHandler = new Handler() {
   @Override
   public void handleMessage(Message msg) {
      if (msg.what == 101) {
         Log.i(TAG, "在子線程中定義Handler,并接收到消息");
       }
   }
};
Looper.loop();

4.Looper.prepare()方法源碼分析

源碼如下所示

可以看到Looper中有一個(gè)ThreadLocal成員變量,熟悉JDK的同學(xué)應(yīng)該知道,當(dāng)使用ThreadLocal維護(hù)變量時(shí),ThreadLocal為每個(gè)使用該變量的線程提供獨(dú)立的變量副本,所以每一個(gè)線程都可以獨(dú)立地改變自己的副本,而不會(huì)影響其它線程所對應(yīng)的副本。

public static void prepare() {
    prepare(true);
}

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

思考:Looper.prepare()能否調(diào)用兩次或者多次

如果運(yùn)行,則會(huì)報(bào)錯(cuò),并提示prepare中的Excetion信息。由此可以得出在每個(gè)線程中Looper.prepare()能且只能調(diào)用一次

//這里L(fēng)ooper.prepare()方法調(diào)用了兩次
Looper.prepare();
Looper.prepare();
Handler mHandler = new Handler() {
   @Override
   public void handleMessage(Message msg) {
       if (msg.what == 1) {
          Log.i(TAG, "在子線程中定義Handler,并接收到消息。。。");
       }
   }
};
Looper.loop();

5.Looper中用什么存儲(chǔ)消息

先看一下下面得源代碼

看Looper對象的構(gòu)造方法,可以看到在其構(gòu)造方法中初始化了一個(gè)MessageQueue對象。MessageQueue也稱之為消息隊(duì)列,特點(diǎn)是先進(jìn)先出,底層實(shí)現(xiàn)是單鏈表數(shù)據(jù)結(jié)構(gòu)

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

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

得出結(jié)論

Looper.prepare()方法初始話了一個(gè)Looper對象并關(guān)聯(lián)在一個(gè)MessageQueue對象,并且一個(gè)線程中只有一個(gè)Looper對象,只有一個(gè)MessageQueue對象。

6.Handler發(fā)送消息如何運(yùn)作

首先看看構(gòu)造方法

可以看出在Handler的構(gòu)造方法中,主要初始化了一下變量,并判斷Handler對象的初始化不應(yīng)再內(nèi)部類,靜態(tài)類,匿名類中,并且保存了當(dāng)前線程中的Looper對象。

public Handler(Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
        final Class 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;
}

看handler.sendMessage(msg)方法

關(guān)于下面得源碼,是步步追蹤,看enqueueMessage這個(gè)方法,原來msg.target就是Handler對象本身;而這里的queue對象就是我們的Handler內(nèi)部維護(hù)的Looper對象關(guān)聯(lián)的MessageQueue對象。

handler.sendMessage(message);

//追蹤到這一步
public final boolean sendMessage(Message msg){
    return sendMessageDelayed(msg, 0);
}


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

看MessageQueue對象的enqueueMessage方法

看到這里MessageQueue并沒有使用列表將所有的Message保存起來,而是使用Message.next保存下一個(gè)Message,從而按照時(shí)間將所有的Message排序

boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }
    if (msg.isInUse()) {
        throw new IllegalStateException(msg + " This message is already in use.");
    }

    synchronized (this) {
        if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, e.getMessage(), e);
            msg.recycle();
            return false;
        }

        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        if (p == null || when == 0 || when < p.when) {
            // New head, wake up the event queue if blocked.
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            // Inserted within the middle of the queue.  Usually we don"t have to wake
            // up the event queue unless there is a barrier at the head of the queue
            // and the message is the earliest asynchronous message in the queue.
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }

        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

7.Looper.loop()方法源碼分析

看看里面得源碼,如下所示

看到Looper.loop()方法里起了一個(gè)死循環(huán),不斷的判斷MessageQueue中的消息是否為空,如果為空則直接return掉,然后執(zhí)行queue.next()方法

public static void loop() {
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn"t called on this thread.");
    }
    final MessageQueue queue = me.mQueue;
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();
    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }
        // This must be in a local variable, in case a UI event sets the logger
        final Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(">>>>> Dispatching to " + msg.target + " " +
                    msg.callback + ": " + msg.what);
        }
        final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
        final long traceTag = me.mTraceTag;
        if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
            Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
        }
        final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
        final long end;
        try {
            msg.target.dispatchMessage(msg);
            end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        if (slowDispatchThresholdMs > 0) {
            final long time = end - start;
            if (time > slowDispatchThresholdMs) {
                Slog.w(TAG, "Dispatch took " + time + "ms on "
                        + Thread.currentThread().getName() + ", h=" +
                        msg.target + " cb=" + msg.callback + " msg=" + msg.what);
            }
        }
        if (logging != null) {
            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
        }
        // Make sure that during the course of dispatching the
        // identity of the thread wasn"t corrupted.
        final long newIdent = Binder.clearCallingIdentity();
        if (ident != newIdent) {
            Log.wtf(TAG, "Thread identity changed from 0x"
                    + Long.toHexString(ident) + " to 0x"
                    + Long.toHexString(newIdent) + " while dispatching to "
                    + msg.target.getClass().getName() + " "
                    + msg.callback + " what=" + msg.what);
        }
        msg.recycleUnchecked();
    }
}

看queue.next()方法源碼

大概的實(shí)現(xiàn)邏輯就是Message的出棧操作,里面可能對線程,并發(fā)控制做了一些限制等。獲取到棧頂?shù)腗essage對象之后開始執(zhí)行:msg.target.dispatchMessage(msg)

Message next() {
    // Return here if the message loop has already quit and been disposed.
    // This can happen if the application tries to restart a looper after quit
    // which is not supported.
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }

    int pendingIdleHandlerCount = -1; // -1 only during first iteration
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }

        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
            // Try to retrieve the next message.  Return if found.
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {
                // Stalled by a barrier.  Find the next asynchronous message in the queue.
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                if (now < msg.when) {
                    // Next message is not ready.  Set a timeout to wake up when it is ready.
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // Got a message.
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    return msg;
                }
            } else {
                // No more messages.
                nextPollTimeoutMillis = -1;
            }

            // Process the quit message now that all pending messages have been handled.
            if (mQuitting) {
                dispose();
                return null;
            }

            // If first time idle, then get the number of idlers to run.
            // Idle handles only run if the queue is empty or if the first message
            // in the queue (possibly a barrier) is due to be handled in the future.
            if (pendingIdleHandlerCount < 0
                    && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                // No idle handlers to run.  Loop and wait some more.
                mBlocked = true;
                continue;
            }

            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }

        // Run the idle handlers.
        // We only ever reach this code block during the first iteration.
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; // release the reference to the handler

            boolean keep = false;
            try {
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }

            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }

        // Reset the idle handler count to 0 so we do not run them again.
        pendingIdleHandlerCount = 0;

        // While calling an idle handler, a new message could have been delivered
        // so go back and look again for a pending message without waiting.
        nextPollTimeoutMillis = 0;
    }
}

那么msg.target是什么呢?通過追蹤可以知道就是定義的Handler對象,然后查看一下Handler類的dispatchMessage方法:

可以看到,如果我們設(shè)置了callback(Runnable對象)的話,則會(huì)直接調(diào)用handleCallback方法

在初始化Handler的時(shí)候設(shè)置了callback(Runnable)對象,則直接調(diào)用run方法。

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

private static void handleCallback(Message message) {
    message.callback.run();
}

8.runOnUiThread如何實(shí)現(xiàn)子線程更新UI

看看源碼,如下所示

如果msg.callback為空的話,會(huì)直接調(diào)用我們的mCallback.handleMessage(msg),即handler的handlerMessage方法。由于Handler對象是在主線程中創(chuàng)建的,所以handler的handlerMessage方法的執(zhí)行也會(huì)在主線程中。

在runOnUiThread程序首先會(huì)判斷當(dāng)前線程是否是UI線程,如果是就直接運(yùn)行,如果不是則post,這時(shí)其實(shí)質(zhì)還是使用的Handler機(jī)制來處理線程與UI通訊。

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

@Override
public final void runOnUiThread(Runnable action) {
    if (Thread.currentThread() != mUiThread) {
        mHandler.post(action);
    } else {
        action.run();
    }
}

9.Handler的post方法和view的post方法

Handler的post方法實(shí)現(xiàn)很簡單,如下所示

mHandler.post(new Runnable() {
    @Override
    public void run() {

    }
});

public final boolean post(Runnable r){
   return  sendMessageDelayed(getPostMessage(r), 0);
}

view的post方法也很簡單,如下所示

可以發(fā)現(xiàn)其調(diào)用的就是activity中默認(rèn)保存的handler對象的post方法

public boolean post(Runnable action) {
    final AttachInfo attachInfo = mAttachInfo;
    if (attachInfo != null) {
        return attachInfo.mHandler.post(action);
    }
    ViewRootImpl.getRunQueue().post(action);
    return true;
}

public void post(Runnable action) {
    postDelayed(action, 0);
}

public void postDelayed(Runnable action, long delayMillis) {
    final HandlerAction handlerAction = new HandlerAction(action, delayMillis);

    synchronized (this) {
        if (mActions == null) {
            mActions = new HandlerAction[4];
        }
        mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction);
        mCount++;
    }
}

10.主線程中Looper的輪詢死循環(huán)為何沒阻塞主線程

造成ANR的原因

造成ANR的原因一般有兩種:

當(dāng)前的事件沒有機(jī)會(huì)得到處理(即主線程正在處理前一個(gè)事件,沒有及時(shí)的完成或者looper被某種原因阻塞住了)

當(dāng)前的事件正在處理,但沒有及時(shí)完成

為了避免ANR異常,android使用了Handler消息處理機(jī)制。讓耗時(shí)操作在子線程運(yùn)行。

問題描述

在處理消息的時(shí)候使用了Looper.loop()方法,并且在該方法中進(jìn)入了一個(gè)死循環(huán),同時(shí)Looper.loop()方法是在主線程中調(diào)用的,那么為什么沒有造成阻塞呢?

ActivityThread中main方法

ActivityThread類的注釋上可以知道這個(gè)類管理著我們平常所說的主線程(UI線程)

首先 ActivityThread 并不是一個(gè) Thread,就只是一個(gè) final 類而已。我們常說的主線程就是從這個(gè)類的 main 方法開始,main 方法很簡短

public static final void main(String[] args) {
    ...
    //創(chuàng)建Looper和MessageQueue
    Looper.prepareMainLooper();
    ...
    //輪詢器開始輪詢
    Looper.loop();
    ...
}

Looper.loop()方法無限循環(huán)

看看Looper.loop()方法無限循環(huán)部分的代碼

while (true) {
   //取出消息隊(duì)列的消息,可能會(huì)阻塞
   Message msg = queue.next(); // might block
   ...
   //解析消息,分發(fā)消息
   msg.target.dispatchMessage(msg);
   ...
}

為什么這個(gè)死循環(huán)不會(huì)造成ANR異常呢?

因?yàn)锳ndroid 的是由事件驅(qū)動(dòng)的,looper.loop() 不斷地接收事件、處理事件,每一個(gè)點(diǎn)擊觸摸或者說Activity的生命周期都是運(yùn)行在 Looper.loop() 的控制之下,如果它停止了,應(yīng)用也就停止了。只能是某一個(gè)消息或者說對消息的處理阻塞了 Looper.loop(),而不是 Looper.loop() 阻塞它。

處理消息handleMessage方法

如下所示

可以看見Activity的生命周期都是依靠主線程的Looper.loop,當(dāng)收到不同Message時(shí)則采用相應(yīng)措施。

如果某個(gè)消息處理時(shí)間過長,比如你在onCreate(),onResume()里面處理耗時(shí)操作,那么下一次的消息比如用戶的點(diǎn)擊事件不能處理了,整個(gè)循環(huán)就會(huì)產(chǎn)生卡頓,時(shí)間一長就成了ANR。

public void handleMessage(Message msg) {
    if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
    switch (msg.what) {
        case LAUNCH_ACTIVITY: {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
            final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
            r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);
            handleLaunchActivity(r, null);
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        }
        break;
        case RELAUNCH_ACTIVITY: {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
            ActivityClientRecord r = (ActivityClientRecord) msg.obj;
            handleRelaunchActivity(r);
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        }
        break;
        case PAUSE_ACTIVITY:
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
            handlePauseActivity((IBinder) msg.obj, false, (msg.arg1 & 1) != 0, msg.arg2, (msg.arg1 & 2) != 0);
            maybeSnapshot();
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            break;
        case PAUSE_ACTIVITY_FINISHING:
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
            handlePauseActivity((IBinder) msg.obj, true, (msg.arg1 & 1) != 0, msg.arg2, (msg.arg1 & 1) != 0);
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            break;
        ...........
    }
}

loop的循環(huán)消耗性能嗎?

主線程Looper從消息隊(duì)列讀取消息,當(dāng)讀完所有消息時(shí),主線程阻塞。子線程往消息隊(duì)列發(fā)送消息,并且往管道文件寫數(shù)據(jù),主線程即被喚醒,從管道文件讀取數(shù)據(jù),主線程被喚醒只是為了讀取消息,當(dāng)消息讀取完畢,再次睡眠。因此loop的循環(huán)并不會(huì)對CPU性能有過多的消耗。

得出結(jié)論

簡單的來說:ActivityThread的main方法主要就是做消息循環(huán),一旦退出消息循環(huán),那么你的程序也就可以退出了。

11.得出部分結(jié)論

得出得結(jié)論如下所示

1.主線程中定義Handler對象,ActivityThread的main方法中會(huì)自動(dòng)創(chuàng)建一個(gè)looper,并且與其綁定。如果是子線程中直接創(chuàng)建handler對象,則需要手動(dòng)創(chuàng)建looper。不過手動(dòng)創(chuàng)建不太友好,需要手動(dòng)調(diào)用quit方法結(jié)束looper。這個(gè)后面再說

2.一個(gè)線程中只存在一個(gè)Looper對象,只存在一個(gè)MessageQueue對象,可以存在N個(gè)Handler對象,Handler對象內(nèi)部關(guān)聯(lián)了本線程中唯一的Looper對象,Looper對象內(nèi)部關(guān)聯(lián)著唯一的一個(gè)MessageQueue對象。

3.MessageQueue消息隊(duì)列不是通過列表保存消息(Message)列表的,而是通過Message對象的next屬性關(guān)聯(lián)下一個(gè)Message從而實(shí)現(xiàn)列表的功能,同時(shí)所有的消息都是按時(shí)間排序的。

其他介紹 01.關(guān)于博客匯總鏈接

1.技術(shù)博客匯總

2.開源項(xiàng)目匯總

3.生活博客匯總

4.喜馬拉雅音頻匯總

5.其他匯總

02.關(guān)于我的博客

github:https://github.com/yangchong211

知乎:https://www.zhihu.com/people/...

簡書:http://www.jianshu.com/u/b7b2...

csdn:http://my.csdn.net/m0_37700275

喜馬拉雅聽書:http://www.ximalaya.com/zhubo...

開源中國:https://my.oschina.net/zbj161...

泡在網(wǎng)上的日子:http://www.jcodecraeer.com/me...

郵箱:yangchong211@163.com

阿里云博客:https://yq.aliyun.com/users/a... 239.headeruserinfo.3.dT4bcV

segmentfault頭條:https://segmentfault.com/u/xi...

掘金:https://juejin.im/user/593943...

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/74519.html

相關(guān)文章

  • Android異步消息機(jī)制

    摘要:在子線程中發(fā)送消息,主線程接受到消息并且處理邏輯。也稱之為消息隊(duì)列,特點(diǎn)是先進(jìn)先出,底層實(shí)現(xiàn)是單鏈表數(shù)據(jù)結(jié)構(gòu)得出結(jié)論方法初始話了一個(gè)對象并關(guān)聯(lián)在一個(gè)對象,并且一個(gè)線程中只有一個(gè)對象,只有一個(gè)對象。 目錄介紹 1.Handler的常見的使用方式 2.如何在子線程中定義Handler 3.主線程如何自動(dòng)調(diào)用Looper.prepare() 4.Looper.prepare()方法源碼分析...

    王晗 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<