本文將從介紹什么是ANR,給出anr產生的幾種觸發(fā)點,分析這幾種情況下是怎么產生anr的鞭呕,然后給出優(yōu)化的方法這幾個方面進行討論赏淌。
1.什么是ANR
ANR定義:在Android上靶擦,如果你的應用程序有一段時間響應不夠靈敏,系統(tǒng)會向用戶顯示一個對話框忘巧,這個對話框稱作應用程序無響應(ANR:Application Not Responding)對話框。
大致的原因就是在特定的時間沒有完成任務
它是通過ActivityManager和WindowManager系統(tǒng)服務監(jiān)視的睦刃。
細分可以分從兩部分分:
- 1.內部:阻塞了主進程砚嘴,IOwait等
- 2.外部:當前應用進程調用請求進程,其他進程長時間無反饋涩拙。
其他進程的CPU占用率高际长,使當前應用無法搶占CPU時間片。
2.ANR觸發(fā)點
- Service TimeOut:前臺服務20s兴泥,后臺200s
- BroadcastReceiver TimeOut : 前臺廣播10s后臺廣播20s
- ContentProvider TimeOut:內容提供者不超過10s
- 按鍵或觸發(fā)時間超時:5s
3.ANR觸發(fā)點原理分析
3.1. Service Timeout
Service Timeout觸發(fā)時機工育,簡單說就是AMS中的mHandler收到SERVICE_TIMEOUT_MSG消息時觸發(fā)。
那我們需要知道這個消息是什么時候開始初始的傅事,如果沒有timeout是怎么處理這個消息的凡泣。timeout又做了什么操作。
Service startService開始一個service最終都會調用ActiveServices.java的realStartServiceLocked方法
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
...
//A.發(fā)送delay消息(SERVICE_TIMEOUT_MSG)初始化
bumpServiceExecutingLocked(r, execInFg, "create");
try {
...
//最終執(zhí)行服務的onCreate()方法
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
} catch (DeadObjectException e) {
...
} finally {
if (!created) {
//B.當service啟動完畢瘩将,則remove SERVICE_TIMEOUT_MSG消息
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
...
}
}
}
流程為:首先發(fā)送一個超時消息怔接,然后出來onCrete(),最后如果創(chuàng)建成功結束消息
A.bumpServiceExecutingLocked最終調用到延時發(fā)送消息流程如下:
這里設置了前臺和后臺超時的時間
// How long we wait for a service to finish executing.
static final int SERVICE_TIMEOUT = 20*1000;
// How long we wait for a service to finish executing.
static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;
B.service啟動完畢調用serviceDoneExecutingLocked結束消息
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
boolean finishing) {
...
if (r.executeNesting <= 0) {
if (r.app != null) {
r.app.execServicesFg = false;
r.app.executingServices.remove(r);
if (r.app.executingServices.size() == 0) {
//當前服務所在進程中沒有正在執(zhí)行的service
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
...
}
...
}
C.AMS中會處理SERVICE_TIMEOUT_MSG (如果產生了超時)
final class MainHandler extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case SERVICE_TIMEOUT_MSG: {
...
mServices.serviceTimeout((ProcessRecord)msg.obj);
} break;
...
}
...
}
}
D.ActivityService.java 調用serviceTimeout(最終調用 appNotResponding)
void serviceTimeout(ProcessRecord proc) {
String anrMessage = null;
synchronized(mAm) {
if (proc.executingServices.size() == 0 || proc.thread == null) {
return;
}
final long now = SystemClock.uptimeMillis();
final long maxTime = now -
(proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
ServiceRecord timeout = null;
long nextTime = 0;
for (int i=proc.executingServices.size()-1; i>=0; i--) {
ServiceRecord sr = proc.executingServices.valueAt(i);
if (sr.executingStart < maxTime) {
timeout = sr;
break;
}
if (sr.executingStart > nextTime) {
nextTime = sr.executingStart;
}
}
if (timeout != null && mAm.mLruProcesses.contains(proc)) {
Slog.w(TAG, "Timeout executing service: " + timeout);
StringWriter sw = new StringWriter();
PrintWriter pw = new FastPrintWriter(sw, false, 1024);
pw.println(timeout);
timeout.dump(pw, " ");
pw.close();
mLastAnrDump = sw.toString();
mAm.mHandler.removeCallbacks(mLastAnrDumpClearer);
mAm.mHandler.postDelayed(mLastAnrDumpClearer, LAST_ANR_LIFETIME_DURATION_MSECS);
anrMessage = "executing service " + timeout.shortName;
} else {
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
mAm.mHandler.sendMessageAtTime(msg, proc.execServicesFg
? (nextTime+SERVICE_TIMEOUT) : (nextTime + SERVICE_BACKGROUND_TIMEOUT));
}
}
if (anrMessage != null) {
mAm.mAppErrors.appNotResponding(proc, null, null, false, anrMessage);
}
}
3.2 BroadcastQueue Timeout
廣播機制是用于進程/線程間通信的搪泳。分兩類:
- 靜態(tài)廣播接收者(AndroidManifest.xml標簽定義的)
- 動態(tài)廣播接收者(通過AMS.registerReceiver())
廣播最終存放在如下隊列中:
mParallelBroadcasts(并行隊列)mOrderedBroadcasts(串行隊列)
類型 | 方法 | ordered | sticky |
---|---|---|---|
普通廣播 | sendBroadcast | false | false |
有序廣播 | sendOrderedBroadcast | true | false |
Sticky廣播 | sendStickyBroadcast | false | true |
廣播的發(fā)送方式:
類型 | 方法 | ordered | sticky |
---|---|---|---|
普通廣播 | sendBroadcast | false | false |
有序廣播 | sendOrderedBroadcast | true | false |
Sticky廣播 | sendStickyBroadcast | false | true |
- 當發(fā)送串行廣播(ordered=true)的情況下:
- 靜態(tài)注冊的廣播接收者(receivers),采用串行處理
- 動態(tài)注冊的廣播接收者(registeredReceivers)蜕提,采用串行處理
- 當發(fā)送并行廣播(ordered=false)的情況下:
- 靜態(tài)注冊的廣播接收者(receivers)森书,依然采用串行處理
- 動態(tài)注冊的廣播接收者(registeredReceivers),采用并行處理
為什么討論這個內容了谎势?
只有串行廣播才需要考慮超時凛膏,因為接收者是串行處理的,前一個receiver處理慢脏榆,會影響后一個receiver猖毫;并行廣播 通過一個循環(huán)一次性向所有的receiver分發(fā)廣播事件,所以不存在彼此影響的問題须喂,則沒有廣播超時
簡單來說吁断,靜態(tài)注冊的receivers始終采用串行方式來處理(processNextBroadcast); 動態(tài)注冊的registeredReceivers處理方式是串行還是并行方式, 取決于廣播的發(fā)送方式(processNextBroadcast)坞生。
根據(jù)源碼分析:廣播最終是通過BroadcastQueue.java中的processNextBroadcast進行處理的仔役。
1.processNextBroadcast執(zhí)行過程分4步驟
- A. 處理并行廣播
- B. 處理當前有序廣播
- C. 獲取下條有序廣播
- D. 處理下條有序廣播
final void processNextBroadcast(boolean fromMsg) {
synchronized(mService) {
//A.處理并行廣播,忽略不需要處理超時
...
//B.處理當前有序廣播
do {
r = mOrderedBroadcasts.get(0);
//獲取所有該廣播所有的接收者
int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
if (mService.mProcessesReady && r.dispatchTime > 0) {
long now = SystemClock.uptimeMillis();
if ((numReceivers > 0) &&
(now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
//當廣播處理時間超時是己,則強制結束這條廣播
broadcastTimeoutLocked(false);
...
}
}
if (r.receivers == null || r.nextReceiver >= numReceivers
|| r.resultAbort || forceReceive) {
if (r.resultTo != null) {
//處理廣播消息消息
performReceiveLocked(r.callerApp, r.resultTo,
new Intent(r.intent), r.resultCode,
r.resultData, r.resultExtras, false, false, r.userId);
r.resultTo = null;
}
//取消BROADCAST_TIMEOUT_MSG消息
cancelBroadcastTimeoutLocked();
}
} while (r == null);
...
//C.獲取下條有序廣播
r.receiverTime = SystemClock.uptimeMillis();
if (!mPendingBroadcastTimeoutMessage) {
long timeoutTime = r.receiverTime + mTimeoutPeriod;
//設置廣播超時時間又兵,發(fā)送BROADCAST_TIMEOUT_MSG
setBroadcastTimeoutLocked(timeoutTime);
}
...
}
}
廣播處理時機:
- 1.在C的時候會setBroadcastTimeoutLocked(timeoutTime);
- 2.在B串行處理的時候。
A.當廣播接收者等待超時卒废,這調用broadcastTimeoutLocked(false) B.當處理結束的時候調用cancelBroadcastTimeoutLocked()
2.setBroadcastTimeoutLocked
final void setBroadcastTimeoutLocked(long timeoutTime) {
if (! mPendingBroadcastTimeoutMessage) {
Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
mHandler.sendMessageAtTime(msg, timeoutTime);
mPendingBroadcastTimeoutMessage = true;
}
}
long timeoutTime = r.receiverTime + mTimeoutPeriod
mTimeoutPeriod中的時間是通過注冊的是時候是前臺廣播或后臺廣播決定的沛厨。
static final int BROADCAST_FG_TIMEOUT = 10*1000;
static final int BROADCAST_BG_TIMEOUT = 60*1000;
3.cancelBroadcastTimeoutLocked
final void cancelBroadcastTimeoutLocked() {
if (mPendingBroadcastTimeoutMessage) {
mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
mPendingBroadcastTimeoutMessage = false;
}
}
4.BROADCAST_TIMEOUT_MSG處理
使用的內部定義的一個handle
private final class BroadcastHandler extends Handler {
public BroadcastHandler(Looper looper) {
super(looper, null, true);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case BROADCAST_INTENT_MSG: {
if (DEBUG_BROADCAST) Slog.v(
TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
processNextBroadcast(true);
} break;
case BROADCAST_TIMEOUT_MSG: {
synchronized (mService) {
broadcastTimeoutLocked(true);
}
} break;
}
}
}
5.broadcastTimeoutLocked
final void broadcastTimeoutLocked(boolean fromMsg) {
if (fromMsg) {
mPendingBroadcastTimeoutMessage = false;
}
if (mOrderedBroadcasts.size() == 0) {
return;
}
long now = SystemClock.uptimeMillis();
BroadcastRecord r = mOrderedBroadcasts.get(0);
if (fromMsg) {
if (mService.mDidDexOpt) {
//延遲timeouts直到dexopt結束
mService.mDidDexOpt = false;
long timeoutTime = SystemClock.uptimeMillis() + mTimeoutPeriod;
setBroadcastTimeoutLocked(timeoutTime);
return;
}
if (!mService.mProcessesReady) {
//當系統(tǒng)還沒有準備就緒時摔认,廣播處理流程中不存在廣播超時
return;
}
long timeoutTime = r.receiverTime + mTimeoutPeriod;
if (timeoutTime > now) {
//過早的timeout逆皮,重新設置廣播超時
setBroadcastTimeoutLocked(timeoutTime);
return;
}
}
BroadcastRecord br = mOrderedBroadcasts.get(0);
if (br.state == BroadcastRecord.WAITING_SERVICES) {
//廣播已經處理完成,但需要等待已啟動service執(zhí)行完成参袱。當?shù)却銐驎r間电谣,則處理下一條廣播。
br.curComponent = null;
br.state = BroadcastRecord.IDLE;
processNextBroadcast(false);
return;
}
r.receiverTime = now;
//當前BroadcastRecord的anr次數(shù)執(zhí)行加1操作
r.anrCount++;
if (r.nextReceiver <= 0) {
return;
}
ProcessRecord app = null;
String anrMessage = null;
Object curReceiver = r.receivers.get(r.nextReceiver-1);
//根據(jù)情況記錄廣播接收者丟棄的EventLog
logBroadcastReceiverDiscardLocked(r);
if (curReceiver instanceof BroadcastFilter) {
BroadcastFilter bf = (BroadcastFilter)curReceiver;
if (bf.receiverList.pid != 0
&& bf.receiverList.pid != ActivityManagerService.MY_PID) {
synchronized (mService.mPidsSelfLocked) {
app = mService.mPidsSelfLocked.get(
bf.receiverList.pid);
}
}
} else {
app = r.curApp;
}
if (app != null) {
anrMessage = "Broadcast of " + r.intent.toString();
}
if (mPendingBroadcast == r) {
mPendingBroadcast = null;
}
//繼續(xù)移動到下一個廣播接收者
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
if (anrMessage != null) {
mHandler.post(new AppNotResponding(app, anrMessage));
}
}
3.3 ContentProvider Timeout
AMS.appNotRespondingViaProvider
public void appNotRespondingViaProvider(IBinder connection) {
enforceCallingPermission(
android.Manifest.permission.REMOVE_TASKS, "appNotRespondingViaProvider()");
final ContentProviderConnection conn = (ContentProviderConnection) connection;
if (conn == null) {
return;
}
final ProcessRecord host = conn.provider.proc;
//無法找到provider所處的進程
if (host == null) {
return;
}
final long token = Binder.clearCallingIdentity();
try {
appNotResponding(host, null, null, false, "ContentProvider not responding");
} finally {
Binder.restoreCallingIdentity(token);
}
}
ContentProviderClient.NotRespondingRunnable.run
ContextImpl.ApplicationContentResolver.appNotRespondingViaProvider
ActivityThread.appNotRespondingViaProvider
AMP.appNotRespondingViaProvider
AMS.appNotRespondingViaProvider
** 3.4 inputDispatching Timeout 和 keyDispatching Timeout**
觸發(fā)點在硬件
1.InputManagerService.java 觸發(fā)點在
// Native callback.
private long notifyANR(InputApplicationHandle inputApplicationHandle,
InputWindowHandle inputWindowHandle, String reason) {
return mWindowManagerCallbacks.notifyANR(
inputApplicationHandle, inputWindowHandle, reason);
}
// mWindowManagerCallbacks為InputMonitor對象
2.InputMonitor
public long notifyANR(InputApplicationHandle inputApplicationHandle,
InputWindowHandle inputWindowHandle, String reason) {
AppWindowToken appWindowToken = null;
WindowState windowState = null;
boolean aboveSystem = false;
synchronized (mService.mWindowMap) {
if (inputWindowHandle != null) {
windowState = (WindowState) inputWindowHandle.windowState;
if (windowState != null) {
appWindowToken = windowState.mAppToken;
}
}
if (appWindowToken == null && inputApplicationHandle != null) {
appWindowToken = (AppWindowToken)inputApplicationHandle.appWindowToken;
}
//輸出input事件分發(fā)超時log
if (windowState != null) {
Slog.i(WindowManagerService.TAG, "Input event dispatching timed out "
+ "sending to " + windowState.mAttrs.getTitle()
+ ". Reason: " + reason);
int systemAlertLayer = mService.mPolicy.windowTypeToLayerLw(
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
aboveSystem = windowState.mBaseLayer > systemAlertLayer;
} else if (appWindowToken != null) {
Slog.i(WindowManagerService.TAG, "Input event dispatching timed out "
+ "sending to application " + appWindowToken.stringName
+ ". Reason: " + reason);
} else {
Slog.i(WindowManagerService.TAG, "Input event dispatching timed out "
+ ". Reason: " + reason);
}
mService.saveANRStateLocked(appWindowToken, windowState, reason);
}
if (appWindowToken != null && appWindowToken.appToken != null) {
// A keyDispatching Timeout 設置
boolean abort = appWindowToken.appToken.keyDispatchingTimedOut(reason);
if (! abort) {
return appWindowToken.inputDispatchingTimeoutNanos;
}
} else if (windowState != null) {
// B inputDispatching time out 設置
long timeout = ActivityManagerNative.getDefault().inputDispatchingTimedOut(
windowState.mSession.mPid, aboveSystem, reason);
if (timeout >= 0) {
return timeout * 1000000L; //轉化為納秒
}
}
return 0;
}
A.keyDispatching Timeout 設置
- ActivityRecord.Token.keyDispatchingTimedOut
@Override
public boolean keyDispatchingTimedOut(String reason, int windowPid) {
ActivityRecord anrActivity;
ProcessRecord anrApp;
boolean windowFromSameProcessAsActivity;
synchronized (service) {
anrActivity = getWaitingHistoryRecordLocked();
anrApp = app;
windowFromSameProcessAsActivity =
app == null || app.pid == windowPid || windowPid == -1;
}
if (windowFromSameProcessAsActivity) {
return service.inputDispatchingTimedOut(anrApp, anrActivity, this, false, reason);
} else {
// In this case another process added windows using this activity token. So, we call the
// generic service input dispatch timed out method so that the right process is blamed.
return service.inputDispatchingTimedOut(windowPid, false /* aboveSystem */, reason) < 0;
}
}
調用AMS.inputDispatchingTimedOut
B.inputDispatching time out 設置
1.調用的是AMS.inputDispatchingTimedOut
ublic long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
...
ProcessRecord proc;
long timeout;
synchronized (this) {
synchronized (mPidsSelfLocked) {
proc = mPidsSelfLocked.get(pid); //根據(jù)pid查看進程record
}
timeout = getInputDispatchingTimeoutLocked(proc);
}
if (!inputDispatchingTimedOut(proc, null, null, aboveSystem, reason)) {
return -1;
}
return timeout;
}
設置時間
// How long we wait until we timeout on key dispatching.
static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
public static long getInputDispatchingTimeoutLocked(ProcessRecord r) {
if (r != null && (r.instr != null || r.usingWrapper)) {
return INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT;
}
return KEY_DISPATCHING_TIMEOUT;
}
2.調用的是AMS.inputDispatchingTimedOut
public boolean inputDispatchingTimedOut(final ProcessRecord proc,
final ActivityRecord activity, final ActivityRecord parent,
final boolean aboveSystem, String reason) {
...
final String annotation;
if (reason == null) {
annotation = "Input dispatching timed out";
} else {
annotation = "Input dispatching timed out (" + reason + ")";
}
if (proc != null) {
...
mHandler.post(new Runnable() {
public void run() {
appNotResponding(proc, activity, parent, aboveSystem, annotation);
}
});
}
return true;
}
4.ANR工作
調用后都觸發(fā)了appNotResponding 下面來介紹下這個
ActivityManagerService appNotResponding
final void appNotResponding(ProcessRecord app, ActivityRecord activity,
ActivityRecord parent, boolean aboveSystem, final String annotation) {
ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20);
if (mController != null) {
try {
// 0 == continue, -1 = kill process immediately
int res = mController.appEarlyNotResponding(app.processName, app.pid, annotation);
if (res < 0 && app.pid != MY_PID) {
app.kill("anr", true);
}
} catch (RemoteException e) {
mController = null;
Watchdog.getInstance().setActivityController(null);
}
}
long anrTime = SystemClock.uptimeMillis();
if (MONITOR_CPU_USAGE) {
updateCpuStatsNow();
}
synchronized (this) {
// PowerManager.reboot() 會阻塞很長時間蓖柔,因此忽略關機時的ANR
if (mShuttingDown) {
Slog.i(TAG, "During shutdown skipping ANR: " + app + " " + annotation);
return;
} else if (app.notResponding) {
Slog.i(TAG, "Skipping duplicate ANR: " + app + " " + annotation);
return;
} else if (app.crashing) {
Slog.i(TAG, "Crashing app skipping ANR: " + app + " " + annotation);
return;
}
app.notResponding = true;
//記錄ANR
EventLog.writeEvent(EventLogTags.AM_ANR, app.userId, app.pid,
app.processName, app.info.flags, annotation);
// Dump thread traces as quickly as we can, starting with "interesting" processes.
firstPids.add(app.pid);
int parentPid = app.pid;
if (parent != null && parent.app != null && parent.app.pid > 0) parentPid = parent.app.pid;
if (parentPid != app.pid) firstPids.add(parentPid);
if (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID);
for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
ProcessRecord r = mLruProcesses.get(i);
if (r != null && r.thread != null) {
int pid = r.pid;
if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) {
if (r.persistent) {
firstPids.add(pid);
} else {
lastPids.put(pid, Boolean.TRUE);
}
}
}
}
}
//輸出ANR到main log.
StringBuilder info = new StringBuilder();
info.setLength(0);
info.append("ANR in ").append(app.processName);
if (activity != null && activity.shortComponentName != null) {
info.append(" (").append(activity.shortComponentName).append(")");
}
info.append("\n");
info.append("PID: ").append(app.pid).append("\n");
if (annotation != null) {
info.append("Reason: ").append(annotation).append("\n");
}
if (parent != null && parent != activity) {
info.append("Parent: ").append(parent.shortComponentName).append("\n");
}
final ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);
//dump棧信息
File tracesFile = dumpStackTraces(true, firstPids, processCpuTracker, lastPids,
NATIVE_STACKS_OF_INTEREST);
String cpuInfo = null;
if (MONITOR_CPU_USAGE) {
updateCpuStatsNow();
synchronized (mProcessCpuTracker) {
//輸出各個進程的CPU使用情況
cpuInfo = mProcessCpuTracker.printCurrentState(anrTime);
}
//輸出CPU負載
info.append(processCpuTracker.printCurrentLoad());
info.append(cpuInfo);
}
info.append(processCpuTracker.printCurrentState(anrTime));
Slog.e(TAG, info.toString());
if (tracesFile == null) {
//發(fā)送signal 3來dump棧信息
Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
}
//將anr信息添加到dropbox
addErrorToDropBox("anr", app, app.processName, activity, parent, annotation,
cpuInfo, tracesFile, null);
if (mController != null) {
try {
// 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
int res = mController.appNotResponding(app.processName, app.pid, info.toString());
if (res != 0) {
if (res < 0 && app.pid != MY_PID) {
app.kill("anr", true);
} else {
synchronized (this) {
mServices.scheduleServiceTimeoutLocked(app);
}
}
return;
}
} catch (RemoteException e) {
mController = null;
Watchdog.getInstance().setActivityController(null);
}
}
boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
synchronized (this) {
mBatteryStatsService.noteProcessAnr(app.processName, app.uid);
if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
app.kill("bg anr", true);
return;
}
// Set the app's notResponding state, and look up the errorReportReceiver
makeAppNotRespondingLocked(app,
activity != null ? activity.shortComponentName : null,
annotation != null ? "ANR " + annotation : "ANR",
info.toString());
//彈出ANR對話框
Message msg = Message.obtain();
HashMap<String, Object> map = new HashMap<String, Object>();
msg.what = SHOW_NOT_RESPONDING_MSG;
msg.obj = map;
msg.arg1 = aboveSystem ? 1 : 0;
map.put("app", app);
if (activity != null) {
map.put("activity", activity);
}
mUiHandler.sendMessage(msg);
}
}
5.優(yōu)化方法
1辰企、運行在主線程里的任何方法都盡可能少做事情。特別是况鸣,Activity應該在它的關鍵生命周期方法(如onCreate()和onResume())里盡可能少的去做創(chuàng)建操作牢贸。(可以采用重新開啟子線程的方式,然后使用Handler+Message的方式做一些操作镐捧,比如更新主線程中的ui等)
2潜索、應用程序應該避免在BroadcastReceiver里做耗時的操作或計算臭增。但也不要在子線程里做這些任務(因為 BroadcastReceiver的生命周期短),如果響應Intent廣播需要執(zhí)行一個耗時的動作的話,應用程序應該啟動一個 Service竹习。
3誊抛、避免在Intent Receiver里啟動一個Activity,因為它會創(chuàng)建一個新的畫面整陌,并從當前用戶正在運行的程序上搶奪焦點拗窃。如果你的應用程序在響應Intent廣播時需要向用戶展示什么,你應該使用Notification Manager來實現(xiàn)泌辫。
4.anr異常也是在程序中自己經常遇到的問題随夸,主要的解決辦法自己最常用的就是不要在主線程中做耗時的操作,而應放在子線程中來實現(xiàn)震放,比如采用Handler+mesage的方式宾毒,或者是有時候需要做一些和網(wǎng)絡相互交互的耗時操作就采用asyntask異步任務的方式(它的底層其實Handler+mesage有所區(qū)別的是它是線程池)等,在主線程中更新UI殿遂。