? 最近項(xiàng)目中,多次碰到app研發(fā)人員反饋廣播從發(fā)送到接收器接收,間隔時(shí)間太長(zhǎng),要求系統(tǒng)進(jìn)行優(yōu)化,特別是開機(jī)階段。對(duì)此,專門閱讀了一下廣播從發(fā)送到接收這個(gè)流程的源碼,以徹底搞明白怎樣讓自己發(fā)送的廣播盡快到達(dá)接收器。

專注于為中小企業(yè)提供成都做網(wǎng)站、網(wǎng)站建設(shè)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)南木林免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了成百上千企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
涉及到的源碼類不多,主要就是ActivityManagerService.java 和?BroadcastQueue.java。發(fā)送廣播進(jìn)程調(diào)用發(fā)送接口,通過IPC到達(dá)AMS,AMS根據(jù)Intent是否配置Intent.FLAG_RECEIVER_FOREGROUND,選擇當(dāng)前廣播加入前臺(tái)廣播隊(duì)列還是后臺(tái)廣播隊(duì)列。根據(jù)當(dāng)前廣播是否有序,將廣播加入廣播隊(duì)列的串行列表還是并行列表。廣播隊(duì)列和廣播隊(duì)列中的廣播列表是影響廣播接收時(shí)間的主要因素。
BroadcastQueue廣播隊(duì)列,負(fù)責(zé)將廣播發(fā)送給廣播接收器。AMS中有兩個(gè)成員變量,?
BroadcastQueue mFgBroadcastQueue;//前臺(tái)廣播隊(duì)列
BroadcastQueue mBgBroadcastQueue;//后臺(tái)廣播隊(duì)列
前臺(tái)廣播隊(duì)列和后臺(tái)廣播隊(duì)列的區(qū)別有兩處:1 超時(shí)時(shí)間,前臺(tái)10s,后臺(tái)60s. 2 是否延遲廣播等待前一個(gè)廣播進(jìn)程完成。這兩個(gè)區(qū)別已經(jīng)說明前臺(tái)廣播對(duì)廣播接收器要求更高,響應(yīng)時(shí)間更短,如果廣播要排隊(duì),時(shí)間上前臺(tái)廣播更短。同時(shí)系統(tǒng)默認(rèn)使用后臺(tái)廣播隊(duì)列,所以前臺(tái)廣播隊(duì)列處理的廣播要少,避免了可能的大量廣播排隊(duì)情況。
廣播隊(duì)列中的列表
//存放無序并發(fā)送給動(dòng)態(tài)廣播接收器的廣播任務(wù)
final ArrayListBroadcastRecord mParallelBroadcasts = new ArrayListBroadcastRecord();
//存放無序發(fā)送給靜態(tài)廣播接收器的廣播任務(wù)或者存放有序廣播任務(wù)
final ArrayListBroadcastRecord mOrderedBroadcasts = new ArrayListBroadcastRecord();
mParallelBroadcasts 此列表中存放的是無序廣播動(dòng)態(tài)廣播接收器任務(wù),廣播隊(duì)列會(huì)在處理任務(wù)時(shí)通過嵌套循環(huán),把每個(gè)廣播通過ipc發(fā)送到關(guān)注它的所有進(jìn)程。所有無序廣播+動(dòng)態(tài)廣播接收器,廣播不需要排隊(duì)。這種情況是最快能讓廣播到達(dá)目標(biāo)進(jìn)程的方式。
mOrderedBroadcasts存放的廣播任務(wù)特點(diǎn):廣播有序,或者廣播接收器是靜態(tài)注冊(cè)的。此種類型的廣播全部要在mOrderedBroadcasts中排隊(duì),廣播之間按時(shí)間先后,同一個(gè)廣播不同廣播接收器按優(yōu)先級(jí)。mOrderedBroadcasts存放的廣播必須等一個(gè)廣播任務(wù)處理完畢才能處理下一個(gè),中間可能包含進(jìn)程的啟動(dòng)等。
由此可見,廣播最快的情況是前臺(tái)廣播、無序廣播、動(dòng)態(tài)注冊(cè)廣播接收器。最糟糕的情況是:后臺(tái)廣播、有序或靜態(tài)注冊(cè)廣播接收器、廣播接收器優(yōu)先級(jí)低。如果一個(gè)應(yīng)用只是簡(jiǎn)單的靠注冊(cè)一個(gè)靜態(tài)廣播接收器拉起進(jìn)程,對(duì)應(yīng)的正是最糟糕的情況。如果又發(fā)生在開機(jī)階段,自然延遲嚴(yán)重。
如果必須注冊(cè)靜態(tài)廣播接收器,縮短時(shí)間的辦法為:配置Intent.FLAG_RECEIVER_FOREGROUND,加入前臺(tái)廣播隊(duì)列,設(shè)置廣播優(yōu)先級(jí)
源碼:
廣播發(fā)送:Context .sendBroadcast -ActivityManagerNative.broadcastIntent-ActivityManagerService.broadcastIntent-ActivityManagerService.broadcastIntentLocked.到此階段,跟發(fā)送廣播的進(jìn)程通信結(jié)束。此階段AMS完成的工作主要是根據(jù)Intent查找該廣播對(duì)應(yīng)的動(dòng)態(tài)廣播接收器、靜態(tài)廣播接收器、以此發(fā)送該廣播使用的廣播隊(duì)列。
private final int broadcastIntentLocked(
......//權(quán)限檢查
......//特殊系統(tǒng)廣播進(jìn)行必要處理
if (sticky) {//粘性廣播處理
......
//查找靜態(tài)注冊(cè)的接收器
receivers = collectReceiverComponents(intent, resolvedType, users);
if (intent.getComponent() == null) {
// 查找動(dòng)態(tài)廣播接收器
? ? ? ? registeredReceivers = mReceiverResolver.queryIntent(intent,
? ? ? ? ? ? ? ? resolvedType, false, userId);
? ? }
//動(dòng)態(tài)廣播接收器
? ? int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
? ? if (!ordered NR 0) {?
//確定隊(duì)列
? ? ? ? final BroadcastQueue queue = broadcastQueueForIntent(intent);
//創(chuàng)建廣播任務(wù)BroadcastRecord
? ? ? ? BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
? ? ? ? ? ? ? ? callerPackage, callingPid, callingUid, resolvedType, requiredPermission,
? ? ? ? ? ? ? ? appOp, registeredReceivers, resultTo, resultCode, resultData, map,
? ? ? ? ? ? ? ? ordered, sticky, false, userId);
......
//廣播任務(wù)加入并行列表中
? ? ? ? ? ? queue.enqueueParallelBroadcastLocked(r);
//啟動(dòng)異步發(fā)送廣播任務(wù)
? ? ? ? ? ? queue.scheduleBroadcastsLocked();
registeredReceivers = null;
? ? ? ? NR = 0;
......
while (it NT ir NR) {
......
//根據(jù)優(yōu)先級(jí)排序
? ? ? 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);
//獲取廣播隊(duì)列
? ? ? ? BroadcastQueue queue = broadcastQueueForIntent(intent);
//創(chuàng)建廣播任務(wù)
? ? ? ? BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
? ? ? ? ? ? ? ? callerPackage, callingPid, callingUid, resolvedType,
? ? ? ? ? ? ? ? requiredPermission, appOp, receivers, resultTo, resultCode,
? ? ? ? ? ? ? ? resultData, map, ordered, sticky, false, userId);
//加入到廣播隊(duì)列串行列表中
? ? ? ? ? ? queue.enqueueOrderedBroadcastLocked(r);
//啟動(dòng)異步發(fā)送任務(wù)
? ? ? ? ? ? queue.scheduleBroadcastsLocked();
廣播隊(duì)列處理廣播:
final void processNextBroadcast(boolean fromMsg) {
......
//并行列表,遍歷廣播任務(wù)
? ? ? ? while (mParallelBroadcasts.size() 0) {
final int N = r.receivers.size();
//遍歷接收器
? ? ? ? ? ? for (int i=0; iN; i++) {
//IPC調(diào)用發(fā)送給目標(biāo)進(jìn)程
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
}
}
//有串行廣播任務(wù)正在執(zhí)行
if (mPendingBroadcast != null) {
? ? ? ? ?//接收廣播的目標(biāo)進(jìn)程正常
? ? ? ? ? ? if (!isDead) {
? ? ? ? ? ? ? ? // It's still alive, so keep waiting 繼續(xù)等待目前進(jìn)程反饋
? ? ? ? ? ? ? ? return;
? ? ? ? ? ? }
}
? ? ? ? ?//取出第一個(gè)廣播
? ? ? ? ? ? r = mOrderedBroadcasts.get(0);//判斷是否超時(shí),
? ? ? ? ? ? ? ? if ((numReceivers 0) ?
? ? ? ? ? ? ? ? ? ? ? ? (now r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
? ? ? ? ? ? ? ? ? ? ?//廣播超時(shí)
? ? ? ? ? ? ? ? ? ? ? broadcastTimeoutLocked(false);//超時(shí)處理,終止當(dāng)前廣播,啟動(dòng)下一個(gè)任務(wù)。
? ? ? ? ? ? ? ? ? ? ? }
if (r.receivers == null || r.nextReceiver = numReceivers
? ? ? ? ? ? ? ? ? ? || r.resultAbort || forceReceive) {
? ? ? ? ? ? ?//所有廣播任務(wù)執(zhí)行完畢
}
int recIdx = r.nextReceiver++;//下一個(gè)廣播接收器
r.dispatchTime = r.receiverTime;//設(shè)置派發(fā)時(shí)間
setBroadcastTimeoutLocked(timeoutTime);//啟動(dòng)超時(shí)計(jì)時(shí)
if (nextReceiver instanceof BroadcastFilter){//動(dòng)態(tài)廣播接收器
deliverToRegisteredReceiverLocked(r, filter, r.ordered);//發(fā)送
return;
}
.//靜態(tài)廣播
? ? ? ? ResolveInfo info =
? ? ? ? ? ? (ResolveInfo)nextReceiver;
......
//檢查進(jìn)程是否已啟動(dòng)
? ? ? ? ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
? ? ? ? ? ? ? ? info.activityInfo.applicationInfo.uid, false);
? ? ? ? if (app != null app.thread != null) { /進(jìn)程啟動(dòng)
? ? ? ? ? ?processCurBroadcastLocked(r, app);//發(fā)送靜態(tài)廣播
? ? ? ? ? ?return;
? ? ? ? }
?if ((r.curApp=mService.startProcessLocked(targetProcess,//啟動(dòng)進(jìn)程
? ? ? ? ? ? ? ? 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) {
? ? ? ? ? ? ? ? ? //進(jìn)程啟動(dòng)失敗
? ? ? ? ? ? ? }
? ? ? ? ?//標(biāo)志正在發(fā)送的串行廣播
? ? ? ? mPendingBroadcast = r;
? ? ? ? mPendingBroadcastRecvIndex = recIdx;//正在發(fā)送的廣播任務(wù)對(duì)應(yīng)的接收器索引
}
延時(shí)操作,可以用下列方案:
方案1:線程阻斷
try {
Thread.currentThread().sleep(2000);//阻斷2秒
} catch (InterruptedException e) {
e.printStackTrace();
}
方案2:使用Handler的postDelayed延遲操作。
mHandler .postDelayed(mRunnable, 3000); // 在Handler中執(zhí)行子線程并延遲3s。
private Runnable mRunnable = new Runnable() {
@Override
public void run() {
mHandler.sendEmptyMessage(1);
}
};
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//3s后執(zhí)行代碼
}
}。
這是安卓的缺陷。蘋果因?yàn)橄到y(tǒng)封閉,所有推送由蘋果自己負(fù)責(zé)統(tǒng)一推送,所以程序不需要后臺(tái),所有軟件都能及時(shí)推送。而安卓也有谷歌統(tǒng)一推送,但是由于一些因素國(guó)內(nèi)支持的很少,所以安卓很多軟件如果要及時(shí)推送就必須鎖定在后臺(tái),少數(shù)幾個(gè)還好,如果需要推送的多了都鎖定后臺(tái)對(duì)性能續(xù)航都會(huì)有比較大影響。
所以目前大多采用第三方消息推送平臺(tái),例如極光,個(gè)推等
文章題目:android延遲,Android延遲廣播
網(wǎng)址分享:http://chinadenli.net/article42/dsipphc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供移動(dòng)網(wǎng)站建設(shè)、企業(yè)網(wǎng)站制作、網(wǎng)站內(nèi)鏈、Google、關(guān)鍵詞優(yōu)化、App開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
營(yíng)銷型網(wǎng)站建設(shè)知識(shí)