1. 程式人生 > >android 中處理崩潰異常並重啟程式

android 中處理崩潰異常並重啟程式

有時候由於測試不充分或者程式潛在的問題而導致程式異常崩潰,這個是令人無法接受的,在Android中怎樣捕獲程式的異常崩潰,然後進行一些必要的處理或重新啟動

應用這個問題困惱了我很久,今天終於解決了該問題,寫篇文章記錄一下。

首先捕獲程式崩潰的異常就必須瞭解一下Java中UncaughtExceptionHandler這個介面,android沿用了此介面,在android API中:


通過實現此介面,能夠處理執行緒被一個無法捕捉的異常所終止的情況。如上所述的情況,handler將會報告執行緒終止和不明原因異常這個情況,如果沒有自定義handler,

執行緒管理組就被預設為報告異常的handler。

ThreadGroup 這個類就是實現了UncaughtExceptionHandler這個介面,如果想捕獲異常我們可以實現這個介面或者繼承ThreadGroup,並重載uncaughtException方法。

Java API中對該介面描述的更詳細:


我就不翻譯了,太吃力了....%>_<%。在實現UncaughtExceptionHandler時,必須過載uncaughtException(Thread thread, Throwable ex) ,如果我們沒有實現該介面

也就是沒有顯示捕捉異常,則ex為空,否則ex不為空,thread 則為出異常的執行緒。

接下來上程式碼,實現UncaughtExceptionHandler介面,顯示處理執行緒異常終止的情況:

  1. publicclass UnCeHandler implements UncaughtExceptionHandler {  
  2.     private Thread.UncaughtExceptionHandler mDefaultHandler;    
  3.     publicstaticfinal String TAG = "CatchExcep";  
  4.     CatchExcep application;  
  5.     public UnCeHandler(CatchExcep application){  
  6.          //獲取系統預設的UncaughtException處理器  
  7.          mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();  
  8.          this.application = application;  
  9.     }  
  10.     @Override
  11.     publicvoid uncaughtException(Thread thread, Throwable ex) {      
  12.         if(!handleException(ex) && mDefaultHandler != null){   
  13.             //如果使用者沒有處理則讓系統預設的異常處理器來處理  
  14.             mDefaultHandler.uncaughtException(thread, ex);                
  15.         }else{         
  16.             try{    
  17.                 Thread.sleep(2000);    
  18.             }catch (InterruptedException e){    
  19.                 Log.e(TAG, "error : ", e);    
  20.             }     
  21.             Intent intent = new Intent(application.getApplicationContext(), MainActivity.class);  
  22.             PendingIntent restartIntent = PendingIntent.getActivity(    
  23.                     application.getApplicationContext(), 0, intent,    
  24.                     Intent.FLAG_ACTIVITY_NEW_TASK);                                                 
  25.             //退出程式                                        
  26.             AlarmManager mgr = (AlarmManager)application.getSystemService(Context.ALARM_SERVICE);    
  27.             mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000,    
  28.                     restartIntent); // 1秒鐘後重啟應用 
  29.             application.finishActivity();  
  30.         }    
  31.     }  
  32.     /**  
  33.      * 自定義錯誤處理,收集錯誤資訊 傳送錯誤報告等操作均在此完成.  
  34.      *   
  35.      * @param ex  
  36.      * @return true:如果處理了該異常資訊;否則返回false.  
  37.      */
  38.     privateboolean handleException(Throwable ex) {    
  39.         if (ex == null) {    
  40.             returnfalse;    
  41.         }    
  42.         //使用Toast來顯示異常資訊  
  43.         new Thread(){    
  44.             @Override
  45.             publicvoid run() {    
  46.                 Looper.prepare();    
  47.                 Toast.makeText(application.getApplicationContext(), "很抱歉,程式出現異常,即將退出.",   
  48.                         Toast.LENGTH_SHORT).show();    
  49.                 Looper.loop();    
  50.             }   
  51.         }.start();    
  52.         returntrue;    
  53.     }    
  54. }  

通過在android Application 這個全域性類中處理異常,如果不知道Application的作用請檢視一下此連結:Application 詳解
  1. publicclass CatchExcep extends Application{  
  2.     ArrayList<Activity> list = new ArrayList<Activity>();  
  3.     publicvoid init(){  
  4.         //設定該CrashHandler為程式的預設處理器  
  5.         UnCeHandler catchExcep = new UnCeHandler(this);  
  6.         Thread.setDefaultUncaughtExceptionHandler(catchExcep);   
  7.     }  
  8.     /** 
  9.      * Activity關閉時,刪除Activity列表中的Activity物件*/
  10.     publicvoid removeActivity(Activity a){  
  11.         list.remove(a);  
  12.     }  
  13.     /** 
  14.      * 向Activity列表中新增Activity物件*/
  15.     publicvoid addActivity(Activity a){  
  16.         list.add(a);  
  17.     }  
  18.     /** 
  19.      * 關閉Activity列表中的所有Activity*/
  20.     publicvoid finishActivity(){  
  21.         for (Activity activity : list) {    
  22.             if (null != activity) {    
  23.                 activity.finish();    
  24.             }    
  25.         }  
  26.         //殺死該應用程序
  27.        android.os.Process.killProcess(android.os.Process.myPid());    
  28.     }  
  29. }  

然後人為製造一個異常:
  1.     Button btn;  
  2.     TextView tv;  
  3.     private CatchExcep application;  
  4.     @Override
  5.     protectedvoid onCreate(Bundle savedInstanceState) {  
  6.         super.onCreate(savedInstanceState);  
  7.         setContentView(R.layout.activity_main);  
  8.         btn = (Button)findViewById(R.id.btn);  
  9.         tv = (TextView)findViewById(R.id.tv);  
  10.         application = (CatchExcep)getApplication();  
  11.         application.init();  
  12.         application.addActivity(this);  
  13.         btn.setOnClickListener(this);         
  14.     }     
  15.     /** 
  16.      * 人為製造的異常*/
  17.     publicvoid press(){  
  18.         new Thread(new Runnable() {           
  19.             @Override
  20.             publicvoid run() {  
  21.                 tv.setText("dfsd");  
  22.             }  
  23.         }).start();  
  24.     }  
  25.     @Override
  26.     publicvoid onClick(View v) {  
  27.         press();  
  28.     }     
  29. }  

上訴程式碼就能夠實現 應用出現無法捕捉的異常時,殺死當前程序,重新啟動一個應用。

我之前困擾的地方:搜了很多資料,殺死異常程序,重新啟動應用,網上應用都是通過Application物件呼叫startActivity(intent),然後殺死異常程序。但是我怎樣試都不成功,

程序是殺死了,但是應用卻沒啟動起來,如果不將異常程序殺死,那麼關閉應用時就得關閉兩次,顯然不能夠接受。網上的一些方法都是錯誤的:如下幾篇部落格:

他們的方法能夠捕獲異常,殺死異常程序,但是卻不能夠重新啟動應用。

如何殺死異常程序,重啟應用,就得使用PendingIntent,這個類是android中對Intent類的包裝,具體瞭解我會在寫一篇部落格,自己也可以去檢視android API。

通過AlarmManager 啟動它,並且關閉開啟的Activity殺死異常程序就能夠實現重新啟動應用。

參考連結: