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介面,顯示處理執行緒異常終止的情況:
- publicclass UnCeHandler implements UncaughtExceptionHandler {
- private Thread.UncaughtExceptionHandler mDefaultHandler;
- publicstaticfinal String TAG = "CatchExcep";
- CatchExcep application;
- public UnCeHandler(CatchExcep application){
-
//獲取系統預設的UncaughtException處理器
- mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
- this.application = application;
- }
- @Override
- publicvoid uncaughtException(Thread thread, Throwable ex) {
- if(!handleException(ex) && mDefaultHandler != null){
- //如果使用者沒有處理則讓系統預設的異常處理器來處理
- mDefaultHandler.uncaughtException(thread, ex);
- }else{
- try{
- Thread.sleep(2000);
- }catch (InterruptedException e){
- Log.e(TAG, "error : ", e);
- }
- Intent intent = new Intent(application.getApplicationContext(), MainActivity.class);
- PendingIntent restartIntent = PendingIntent.getActivity(
- application.getApplicationContext(), 0, intent,
- Intent.FLAG_ACTIVITY_NEW_TASK);
- //退出程式
- AlarmManager mgr = (AlarmManager)application.getSystemService(Context.ALARM_SERVICE);
- mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000,
- restartIntent); // 1秒鐘後重啟應用
- application.finishActivity();
- }
- }
- /**
- * 自定義錯誤處理,收集錯誤資訊 傳送錯誤報告等操作均在此完成.
- *
- * @param ex
- * @return true:如果處理了該異常資訊;否則返回false.
- */
- privateboolean handleException(Throwable ex) {
- if (ex == null) {
- returnfalse;
- }
- //使用Toast來顯示異常資訊
- new Thread(){
- @Override
- publicvoid run() {
- Looper.prepare();
- Toast.makeText(application.getApplicationContext(), "很抱歉,程式出現異常,即將退出.",
- Toast.LENGTH_SHORT).show();
- Looper.loop();
- }
- }.start();
- returntrue;
- }
- }
通過在android Application 這個全域性類中處理異常,如果不知道Application的作用請檢視一下此連結:Application 詳解
- publicclass CatchExcep extends Application{
- ArrayList<Activity> list = new ArrayList<Activity>();
- publicvoid init(){
- //設定該CrashHandler為程式的預設處理器
- UnCeHandler catchExcep = new UnCeHandler(this);
- Thread.setDefaultUncaughtExceptionHandler(catchExcep);
- }
- /**
- * Activity關閉時,刪除Activity列表中的Activity物件*/
- publicvoid removeActivity(Activity a){
- list.remove(a);
- }
- /**
- * 向Activity列表中新增Activity物件*/
- publicvoid addActivity(Activity a){
- list.add(a);
- }
- /**
- * 關閉Activity列表中的所有Activity*/
- publicvoid finishActivity(){
- for (Activity activity : list) {
- if (null != activity) {
- activity.finish();
- }
- }
- //殺死該應用程序
- android.os.Process.killProcess(android.os.Process.myPid());
- }
- }
然後人為製造一個異常:
- Button btn;
- TextView tv;
- private CatchExcep application;
- @Override
- protectedvoid onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- btn = (Button)findViewById(R.id.btn);
- tv = (TextView)findViewById(R.id.tv);
- application = (CatchExcep)getApplication();
- application.init();
- application.addActivity(this);
- btn.setOnClickListener(this);
- }
- /**
- * 人為製造的異常*/
- publicvoid press(){
- new Thread(new Runnable() {
- @Override
- publicvoid run() {
- tv.setText("dfsd");
- }
- }).start();
- }
- @Override
- publicvoid onClick(View v) {
- press();
- }
- }
上訴程式碼就能夠實現 應用出現無法捕捉的異常時,殺死當前程序,重新啟動一個應用。
我之前困擾的地方:搜了很多資料,殺死異常程序,重新啟動應用,網上應用都是通過Application物件呼叫startActivity(intent),然後殺死異常程序。但是我怎樣試都不成功,
程序是殺死了,但是應用卻沒啟動起來,如果不將異常程序殺死,那麼關閉應用時就得關閉兩次,顯然不能夠接受。網上的一些方法都是錯誤的:如下幾篇部落格:
他們的方法能夠捕獲異常,殺死異常程序,但是卻不能夠重新啟動應用。
如何殺死異常程序,重啟應用,就得使用PendingIntent,這個類是android中對Intent類的包裝,具體瞭解我會在寫一篇部落格,自己也可以去檢視android API。
通過AlarmManager 啟動它,並且關閉開啟的Activity殺死異常程序就能夠實現重新啟動應用。
參考連結: