有時候由于測試不充分或者程序潛在的問題而導(dǎo)致程序異常崩潰,這個是令人無法接受的,在android中怎樣捕獲程序的異常崩潰,然后進(jìn)行一些必要的處理或重新啟動
應(yīng)用這個問題困惱了我很久,今天終于解決了該問題,寫篇文章記錄一下。
首先捕獲程序崩潰的異常就必須了解一下java中UncaughtExceptionHandler這個接口,android沿用了此接口,在android API中:
通過實(shí)現(xiàn)此接口,能夠處理線程被一個無法捕捉的異常所終止的情況。如上所述的情況,handler將會報告線程終止和不明原因異常這個情況,如果沒有自定義handler,
線程管理組就被默認(rèn)為報告異常的handler。
ThreadGroup 這個類就是實(shí)現(xiàn)了UncaughtExceptionHandler這個接口,如果想捕獲異常我們可以實(shí)現(xiàn)這個接口或者繼承ThreadGroup,并重載uncaughtException方法。
在java API中對該接口描述的更詳細(xì):
我就不翻譯了,太吃力了....%>_<%。在實(shí)現(xiàn)UncaughtExceptionHandler時,必須重載uncaughtException(Thread thread, Throwable ex) ,如果我們沒有實(shí)現(xiàn)該接口
也就是沒有顯示捕捉異常,則ex為空,否則ex不為空,thread 則為出異常的線程。
接下來上代碼,實(shí)現(xiàn)UncaughtExceptionHandler接口,顯示處理線程異常終止的情況:
- public class UnCeHandler implements UncaughtExceptionHandler {
-
- private Thread.UncaughtExceptionHandler mDefaultHandler;
- public static final String TAG = "CatchExcep";
- CatchExcep application;
-
- public UnCeHandler(CatchExcep application){
- //獲取系統(tǒng)默認(rèn)的UncaughtException處理器
- mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
- this.application = application;
- }
-
- @Override
- public void uncaughtException(Thread thread, Throwable ex) {
- if(!handleException(ex) && mDefaultHandler != null){
- //如果用戶沒有處理則讓系統(tǒng)默認(rèn)的異常處理器來處理
- 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秒鐘后重啟應(yīng)用
- application.finishActivity();
- }
- }
-
- /**
- * 自定義錯誤處理,收集錯誤信息 發(fā)送錯誤報告等操作均在此完成.
- *
- * @param ex
- * @return true:如果處理了該異常信息;否則返回false.
- */
- private boolean handleException(Throwable ex) {
- if (ex == null) {
- return false;
- }
- //使用Toast來顯示異常信息
- new Thread(){
- @Override
- public void run() {
- Looper.prepare();
- Toast.makeText(application.getApplicationContext(), "很抱歉,程序出現(xiàn)異常,即將退出.",
- Toast.LENGTH_SHORT).show();
- Looper.loop();
- }
- }.start();
- return true;
- }
- }
通過在android Application 這個全局類中處理異常,如果不知道Application的作用請查看一下此鏈接:Application 詳解
- public class CatchExcep extends Application{
-
- ArrayList<Activity> list = new ArrayList<Activity>();
-
- public void init(){
- //設(shè)置該CrashHandler為程序的默認(rèn)處理器
- UnCeHandler catchExcep = new UnCeHandler(this);
- Thread.setDefaultUncaughtExceptionHandler(catchExcep);
- }
-
- /**
- * Activity關(guān)閉時,刪除Activity列表中的Activity對象*/
- public void removeActivity(Activity a){
- list.remove(a);
- }
-
- /**
- * 向Activity列表中添加Activity對象*/
- public void addActivity(Activity a){
- list.add(a);
- }
-
- /**
- * 關(guān)閉Activity列表中的所有Activity*/
- public void finishActivity(){
- for (Activity activity : list) {
- if (null != activity) {
- activity.finish();
- }
- }
- //殺死該應(yīng)用進(jìn)程
- android.os.Process.killProcess(android.os.Process.myPid());
- }
- }
然后人為制造一個異常:
- Button btn;
- TextView tv;
- private CatchExcep application;
- @Override
- protected void 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);
- }
-
- /**
- * 人為制造的異常*/
- public void press(){
- new Thread(new Runnable() {
- @Override
- public void run() {
- tv.setText("dfsd");
- }
- }).start();
- }
- @Override
- public void onClick(View v) {
- press();
- }
- }
上訴代碼就能夠?qū)崿F(xiàn) 應(yīng)用出現(xiàn)無法捕捉的異常時,殺死當(dāng)前進(jìn)程,重新啟動一個應(yīng)用。
我之前困擾的地方:搜了很多資料,殺死異常進(jìn)程,重新啟動應(yīng)用,網(wǎng)上應(yīng)用都是通過Application對象調(diào)用startActivity(intent),然后殺死異常進(jìn)程。但是我怎樣試都不成功,
進(jìn)程是殺死了,但是應(yīng)用卻沒啟動起來,如果不將異常進(jìn)程殺死,那么關(guān)閉應(yīng)用時就得關(guān)閉兩次,顯然不能夠接受。網(wǎng)上的一些方法都是錯誤的:如下幾篇博客:
http://blog.csdn.net/xianming01/article/details/7711160
http://blog.csdn.net/ryantang03/article/details/9336295?reload
他們的方法能夠捕獲異常,殺死異常進(jìn)程,但是卻不能夠重新啟動應(yīng)用。
如何殺死異常進(jìn)程,重啟應(yīng)用,就得使用PendingIntent,這個類是android中對Intent類的包裝,具體了解我會在寫一篇博客,自己也可以去查看android API。
通過AlarmManager 啟動它,并且關(guān)閉打開的Activity殺死異常進(jìn)程就能夠?qū)崿F(xiàn)重新啟動應(yīng)用。
參考鏈接:
http://zheyiw./blog/1670990
|