防止android應用程序無響應ANR(Application Not Responding)

在android中應用被單個線程操作:主線程,或者叫做UI線程。

一:什麼是ANR

ANR:Application Not Responding,即應用無響應

 

二:ANR的類型

ANR一般有三種類型:

1KeyDispatchTimeout(5 seconds) --主要類型

按鍵或觸摸事件在特定時間內無響應

2BroadcastTimeout(10 seconds)

BroadcastReceiver在特定時間內無法處理完成

3ServiceTimeout(20 seconds) --小概率類型

Service在特定的時間內無法處理完成

五:如何避免KeyDispatchTimeout

1UI線程儘量只做跟UI相關的工作

2:耗時的工作(比如數據庫操作,I/O,連接網絡或者別的有可能阻礙UI線程的操作)把它放入單獨的線程處理

3:儘量用Handler來處理UIthread和別的thread之間的交互

 

六:UI線程

說了那麼多的UI線程,那麼哪些屬於UI線程呢?

UI線程主要包括如下:

  1. Activity:onCreate(), onResume(), onDestroy(), onKeyDown(), onClick(),etc

  2. AsyncTask: onPreExecute(), onProgressUpdate(), onPostExecute(), onCancel,etc

  3. Mainthread handler: handleMessage(), post*(runnable r), etc

  4. other

:如何去分析ANR

先看個LOG:

04-01 13:12:11.572 I/InputDispatcher( 220): Application is not responding:Window{2b263310com.android.email/com.android.email.activity.SplitScreenActivitypaused=false}.  5009.8ms since event, 5009.5ms since waitstarted

04-0113:12:11.572 I/WindowManager( 220): Input event dispatching timedout sending tocom.android.email/com.android.email.activity.SplitScreenActivity

04-01 13:12:14.123 I/Process(  220): Sending signal. PID: 21404 SIG: 3---發生ANR的時間和生成trace.txt的時間

04-01 13:12:14.123 I/dalvikvm(21404):threadid=4: reacting to signal 3 

……

04-0113:12:15.872 E/ActivityManager(  220): ANR in com.android.email(com.android.email/.activity.SplitScreenActivity)

04-0113:12:15.872 E/ActivityManager(  220): Reason:keyDispatchingTimedOut

04-0113:12:15.872 E/ActivityManager(  220): Load: 8.68 / 8.37 / 8.53

04-0113:12:15.872 E/ActivityManager(  220): CPUusage from 4361ms to 699ms ago ----CPUANR發生前的使用情況

 

04-0113:12:15.872 E/ActivityManager(  220):   5.5%21404/com.android.email: 1.3% user + 4.1% kernel / faults: 10 minor

04-0113:12:15.872 E/ActivityManager(  220):   4.3%220/system_server: 2.7% user + 1.5% kernel / faults: 11 minor 2 major

04-0113:12:15.872 E/ActivityManager(  220):   0.9%52/spi_qsd.0: 0% user + 0.9% kernel

04-0113:12:15.872 E/ActivityManager(  220):   0.5%65/irq/170-cyttsp-: 0% user + 0.5% kernel

04-0113:12:15.872 E/ActivityManager(  220):   0.5%296/com.android.systemui: 0.5% user + 0% kernel

04-0113:12:15.872 E/ActivityManager(  220): 100%TOTAL: 4.8% user + 7.6% kernel + 87% iowait

04-0113:12:15.872 E/ActivityManager(  220): CPUusage from 3697ms to 4223ms later:-- ANRCPU的使用量

04-0113:12:15.872 E/ActivityManager(  220):   25%21404/com.android.email: 25% user + 0% kernel / faults: 191 minor

04-0113:12:15.872 E/ActivityManager(  220):    16% 21603/__eas(par.hakan: 16% user + 0% kernel

04-0113:12:15.872 E/ActivityManager(  220):    7.2% 21406/GC: 7.2% user + 0% kernel

04-0113:12:15.872 E/ActivityManager(  220):    1.8% 21409/Compiler: 1.8% user + 0% kernel

04-0113:12:15.872 E/ActivityManager(  220):   5.5%220/system_server: 0% user + 5.5% kernel / faults: 1 minor

04-0113:12:15.872 E/ActivityManager(  220):    5.5% 263/InputDispatcher: 0% user + 5.5% kernel

04-0113:12:15.872 E/ActivityManager(  220): 32%TOTAL: 28% user + 3.7% kernel

 

LOG可以看出ANR的類型,CPU的使用情況,如果CPU使用量接近100%,說明當前設備很忙,有可能是CPU飢餓導致了ANR

如果CPU使用量很少,說明主線程被BLOCK

如果IOwait很高,說明ANR有可能是主線程在進行I/O操作造成的

除了看LOG,解決ANR還得需要trace.txt文件,

如何獲取呢?可以用如下命令獲取

  1. $chmod 777 /data/anr

  2. $rm /data/anr/traces.txt

  3. $ps

  4. $kill -3 PID

  5. adbpull data/anr/traces.txt ./mytraces.txt

trace.txt文件,看到最多的是如下的信息:

-----pid 21404 at 2011-04-01 13:12:14 -----  
Cmdline: com.android.email

DALVIK THREADS:
(mutexes: tll=0tsl=0 tscl=0 ghl=0 hwl=0 hwll=0)
"main" prio=5 tid=1NATIVE
  | group="main" sCount=1 dsCount=0obj=0x2aad2248 self=0xcf70
  | sysTid=21404 nice=0 sched=0/0cgrp=[fopen-error:2] handle=1876218976
  atandroid.os.MessageQueue.nativePollOnce(Native Method)
  atandroid.os.MessageQueue.next(MessageQueue.java:119)
  atandroid.os.Looper.loop(Looper.java:110
)
 at android.app.ActivityThread.main(ActivityThread.java:3688)
 at java.lang.reflect.Method.invokeNative(Native Method)
  atjava.lang.reflect.Method.invoke(Method.java:507)
  atcom.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:624)
 at dalvik.system.NativeStart.main(Native Method)

說明主線程在等待下條消息進入消息隊列

:STRICTMODE

這個工具會檢測發生在主線程上的磁盤或者網絡操作並且會採取行動來警告開發者(包括日誌記錄和應用程序崩潰)

StrictMode.setThreadPolicy(new StrictMode.VmPolicy.Builder()
            .detectAll()
            .penaltyLog()
            .penaltyDialog()
            .build());(monitor specific thread)


StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
            .detectAll()
            .penaltyLog()
            .penaltyDeath()
            .build());(monitor all threads)


只在調試模式下啓動StrictMode

如何檢測:

public class Util {
    public static boolean isDebugMode(Context context) {
        PackageManager pm = context.getPackageManager();
        try {
            ApplicationInfo info = pm.getApplicationInfo(context.getPackageName(), 0);
            return (info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
        } catch (NameNotFoundException e) {
        }
        return true;
    }
    
    public static boolean useStrictMode(Context context) {
        return isDebugMode(context) && Build.VERSION SDK_INT >= 9;
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章