當前位置:首頁 » 安卓系統 » android阻塞

android阻塞

發布時間: 2023-10-05 22:00:49

Ⅰ Android如何阻塞一個線程讓其等待一個時間發生之後再繼續執行

你所謂的線程阻塞是指的ui線程嗎?這應該是從你在開發的經驗以及測試當中去體驗的,如果你說是用代碼去判斷線程阻塞的話,估計比較復雜,也沒那個必要,android的機制在出現ui線程阻塞的話會出現anr給予用戶提示,出現這樣的情況是開發者在開發過程中就得去避免的!

Ⅱ Android廣播阻塞、延遲問題

        最近項目中,多次碰到app研發人員反饋廣播從發送到接收器接收,間隔時間太長,要求系統進行優化,特別是開機階段。對此,專門閱讀了一下廣播從發送到接收這個流程的源碼,以徹底搞明白怎樣讓自己發送的廣播盡快到達接收器。

涉及到的源碼類不多,主要就是ActivityManagerService.java 和 BroadcastQueue.java。發送廣播進程調用發送介面,通過IPC到達AMS,AMS根據Intent是否配置Intent.FLAG_RECEIVER_FOREGROUND,選擇當前廣播加入前台廣播隊列還是後台廣播隊列。根據當前廣播是否有序,將廣播加入廣播隊列的串列列表還是並行列表。廣播隊列和廣播隊列中的廣播列表是影響廣播接收時間的主要因素。

BroadcastQueue廣播隊列,負責將廣播發送給廣播接收器。AMS中有兩個成員變數, 

BroadcastQueue mFgBroadcastQueue;//前台廣播隊列

BroadcastQueue mBgBroadcastQueue;//後台廣播隊列

前台廣播隊列和後台廣播隊列的區別有兩處:1 超時時間,前台10s,後台60s. 2 是否延遲廣播等待前一個廣播進程完成。這兩個區別已經說明前台廣播對廣播接收器要求更高,響應時間更短,如果廣播要排隊,時間上前台廣播更短。同時系統默認使用後台廣播隊列,所以前台廣播隊列處理的廣播要少,避免了可能的大量廣播排隊情況。

廣播隊列中的列表

//存放無序並發送給動態廣播接收器的廣播任務

final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<BroadcastRecord>();

//存放無序發送給靜態廣播接收器的廣播任務或者存放有序廣播任務

final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<BroadcastRecord>();

mParallelBroadcasts 此列表中存放的是無序廣播動態廣播接收器任務,廣播隊列會在處理任務時通過嵌套循環,把每個廣播通過ipc發送到關注它的所有進程。所有無序廣播+動態廣播接收器,廣播不需要排隊。這種情況是最快能讓廣播到達目標進程的方式。

mOrderedBroadcasts存放的廣播任務特點:廣播有序,或者廣播接收器是靜態注冊的。此種類型的廣播全部要在mOrderedBroadcasts中排隊,廣播之間按時間先後,同一個廣播不同廣播接收器按優先順序。mOrderedBroadcasts存放的廣播必須等一個廣播任務處理完畢才能處理下一個,中間可能包含進程的啟動等。

由此可見,廣播最快的情況是前台廣播、無序廣播、動態注冊廣播接收器。最糟糕的情況是:後台廣播、有序或靜態注冊廣播接收器、廣播接收器優先順序低。如果一個應用只是簡單的靠注冊一個靜態廣播接收器拉起進程,對應的正是最糟糕的情況。如果又發生在開機階段,自然延遲嚴重。

如果必須注冊靜態廣播接收器,縮短時間的辦法為:配置Intent.FLAG_RECEIVER_FOREGROUND,加入前台廣播隊列,設置廣播優先順序

源碼:

廣播發送:Context .sendBroadcast ->ActivityManagerNative.broadcastIntent->ActivityManagerService.broadcastIntent->ActivityManagerService.broadcastIntentLocked.到此階段,跟發送廣播的進程通信結束。此階段AMS完成的工作主要是根據Intent查找該廣播對應的動態廣播接收器、靜態廣播接收器、以此發送該廣播使用的廣播隊列。

private final int broadcastIntentLocked(

......//許可權檢查

......//特殊系統廣播進行必要處理

if (sticky) {//粘性廣播處理

......

//查找靜態注冊的接收器

receivers = collectReceiverComponents(intent, resolvedType, users);

if (intent.getComponent() == null) {

    // 查找動態廣播接收器

            registeredReceivers = mReceiverResolver.queryIntent(intent,

                    resolvedType, false, userId);

        }

//動態廣播接收器

        int NR = registeredReceivers != null ? registeredReceivers.size() : 0;

        if (!ordered && NR > 0) { 

//確定隊列

            final BroadcastQueue queue = broadcastQueueForIntent(intent);

//創建廣播任務BroadcastRecord

            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,

                    callerPackage, callingPid, callingUid, resolvedType, requiredPermission,

                    appOp, registeredReceivers, resultTo, resultCode, resultData, map,

                    ordered, sticky, false, userId);

......

//廣播任務加入並行列表中

                queue.(r);

//啟動非同步發送廣播任務

                queue.scheleBroadcastsLocked();

registeredReceivers = null;

            NR = 0;

......

while (it < NT && ir < NR) {

......

//根據優先順序排序

          if (curt == null) {

                    curt = (ResolveInfo)receivers.get(it);

                }

                if (curr == null) {

                    curr = registeredReceivers.get(ir);

                }

                if (curr.getPriority() >= curt.priority) {

                    // Insert this broadcast record into the final list.

                    receivers.add(it, curr);

//獲取廣播隊列

            BroadcastQueue queue = broadcastQueueForIntent(intent);

//創建廣播任務

            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,

                    callerPackage, callingPid, callingUid, resolvedType,

                    requiredPermission, appOp, receivers, resultTo, resultCode,

                    resultData, map, ordered, sticky, false, userId);

//加入到廣播隊列串列列表中

                queue.enqueueOrderedBroadcastLocked(r);

//啟動非同步發送任務

                queue.scheleBroadcastsLocked();

廣播隊列處理廣播:

final void processNextBroadcast(boolean fromMsg) {

......

//並行列表,遍歷廣播任務

            while (mParallelBroadcasts.size() > 0) {

final int N = r.receivers.size();

//遍歷接收器

                for (int i=0; i<N; i++) {

//IPC調用發送給目標進程

(r, (BroadcastFilter)target, false);

}

}

//有串列廣播任務正在執行

if (mPendingBroadcast != null) {

             //接收廣播的目標進程正常

                if (!isDead) {

                    // It's still alive, so keep waiting 繼續等待目前進程反饋

                    return;

                }

}

             //取出第一個廣播

                r = mOrderedBroadcasts.get(0);//判斷是否超時,

                    if ((numReceivers > 0) && 

                            (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {

                         //廣播超時

                          broadcastTimeoutLocked(false);//超時處理,終止當前廣播,啟動下一個任務。

                          }

                if (r.receivers == null || r.nextReceiver >= numReceivers

                        || r.resultAbort || forceReceive) {

                 //所有廣播任務執行完畢

}

int recIdx = r.nextReceiver++;//下一個廣播接收器

r.dispatchTime = r.receiverTime;//設置派發時間

setBroadcastTimeoutLocked(timeoutTime);//啟動超時計時

if (nextReceiver instanceof BroadcastFilter){//動態廣播接收器

(r, filter, r.ordered);//發送

return;

}

.//靜態廣播

            ResolveInfo info =

                (ResolveInfo)nextReceiver;

......

//檢查進程是否已啟動

            ProcessRecord app = mService.getProcessRecordLocked(targetProcess,

                    info.activityInfo.applicationInfo.uid, false);

            if (app != null && app.thread != null) { /進程啟動

               processCurBroadcastLocked(r, app);//發送靜態廣播

               return;

            }

     if ((r.curApp=mService.startProcessLocked(targetProcess,//啟動進程

                    info.activityInfo.applicationInfo, true,

                    r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,

                    "broadcast", r.curComponent,

                    (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))

                            == null) {

                      //進程啟動失敗

                  }

             //標志正在發送的串列廣播

            mPendingBroadcast = r;

            mPendingBroadcastRecvIndex = recIdx;//正在發送的廣播任務對應的接收器索引

}

Ⅲ 如何判斷android 線程阻塞

你所謂的線程阻塞是指的UI線程嗎?這應該是從你在開發的經驗以及測試當中去體驗的,如果你說是用代碼去判斷線程阻塞的話,估計比較復雜,也沒那個必要,android的機制在出現UI線程阻塞的話會出現ANR給予用戶提示,出現這樣的情況是開發者在開發過程中就得去避免的!

熱點內容
雲通信伺服器 發布:2024-05-22 10:12:10 瀏覽:400
job調用存儲過程 發布:2024-05-22 10:01:46 瀏覽:390
jsp導入java 發布:2024-05-22 10:00:50 瀏覽:180
2020年大眾探岳有什麼配置 發布:2024-05-22 10:00:50 瀏覽:121
李姓三才如何配置 發布:2024-05-22 10:00:07 瀏覽:748
七牛雲存儲圖片 發布:2024-05-22 09:57:09 瀏覽:753
java來源 發布:2024-05-22 09:37:44 瀏覽:677
linux查看桌面 發布:2024-05-22 09:16:47 瀏覽:252
伺服器災難如何恢復 發布:2024-05-22 09:16:02 瀏覽:695
設置mysql資料庫字元集 發布:2024-05-22 09:07:25 瀏覽:905