Androidでクラッシュ異常を処理し、プログラムを再起動してページが重なる問題


Android開発ではプログラム異常に遭遇することが多いが、異常アプリが現れると自動的に再起動することが多い.ただ、プロジェクトにFragmentの切り替えを適用すると、移動ページが重なる現象がある.今日はこの問題を解決するためにたくさんの牛のブログを見ました.最後にやっと問題を解決したので、解決方法を紹介します.全体的な問題解決の方向性はクラッシュ異常を処理する方法である.まず私が前に試した成功しない方法を話します.一、クラス実装UncaughtExceptionHandlerインタフェースを書く

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;

/**
 * Created by willkong on 2016/12/14.
 */

public class UnCeHandler implements Thread.UncaughtExceptionHandler {
    private Thread.UncaughtExceptionHandler mDefaultHandler;
    public static final String TAG = "CatchExcep";
    MyApplication application;

    public UnCeHandler(MyApplication application){
        //       UncaughtException   
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        this.application = application;
    }

    @Override
    public void 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.
     */
    private boolean handleException(Throwable ex) {
        if (ex == null) {
            return false;
        }
        //  Toast       
        new Thread(){
            @Override
            public void run() {
                Looper.prepare();
                Toast.makeText(application.getApplicationContext(), "   ,      ,    .",
                        Toast.LENGTH_SHORT).show();
                Looper.loop();
            }
        }.start();
        return true;
    }
}

二、androidアプリケーションというグローバルクラスで異常を処理することで、一般的には自分たちのアプリケーション継承アプリケーションを書き換えることができます.

import android.app.Activity;
import android.app.Application;

import java.util.ArrayList;

/**
 * Created by willkong on 2016/12/14.
 */

public class MyApplication extends Application {
    ArrayList list = new ArrayList();

    @Override
    public void onCreate() {
        super.onCreate();
        //   CrashHandler         
        UnCeHandler catchExcep = new UnCeHandler(this);
        Thread.setDefaultUncaughtExceptionHandler(catchExcep);
    }

    /**
     * Activity   ,  Activity    Activity  */
    public void removeActivity(Activity a){
        list.remove(a);
    }

    /**
     *  Activity     Activity  */
    public void addActivity(Activity a){
        list.add(a);
    }

    /**
     *   Activity      Activity*/
    public void finishActivity(){
        for (Activity activity : list) {
            if (null != activity) {
                activity.finish();
            }
        }
        //       
        android.os.Process.killProcess(android.os.Process.myPid());
    }
}

人為的に異常を起こす

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    Button btn;
    TextView tv;
    private MyApplication 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 = (MyApplication) getApplication();
        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();
    }
}

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.testapplication.MainActivity">

    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

    <Button
        android:id="@+id/btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
LinearLayout>

試行2:汎用アプリケーション1、すべてのavtivityを収集してアプリケーションを完全に終了する2、クラッシュ異常をキャプチャし、エラーログを保存し、アプリケーションを再起動する
public class HKBaseApplication extends Application {  
    // activity    ,  activity      
    private List activityList;  
    //       
    protected boolean isNeedCaughtExeption = true;//           
    private PendingIntent restartIntent;  
    private MyUncaughtExceptionHandler uncaughtExceptionHandler;  
    private String packgeName;  

    @Override  
    public void onCreate() {  
        super.onCreate();  

        activityList = new ArrayList();  
        packgeName = getPackageName();  

        if (isNeedCaughtExeption) {  
            cauchException();  
        }  
    }  

    // -------------------    -----         -----------------//  

    private void cauchException() {  
        Intent intent = new Intent();  
        //   1:  ,  2:     activity  
        intent.setClassName(packgeName, packgeName + ".LoginActivity");  
        restartIntent = PendingIntent.getActivity(getApplicationContext(), -1, intent,  
                Intent.FLAG_ACTIVITY_NEW_TASK);  

        //            
        uncaughtExceptionHandler = new MyUncaughtExceptionHandler();  
        Thread.setDefaultUncaughtExceptionHandler(uncaughtExceptionHandler);  
    }  

    //               
    private class MyUncaughtExceptionHandler implements UncaughtExceptionHandler {  
        @Override  
        public void uncaughtException(Thread thread, Throwable ex) {  
            //         
            saveCatchInfo2File(ex);  

            // 1         
            AlarmManager mgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);  
            mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent);  

            //         
            finishAllActivity();  
            finishProgram();  
        }  
    };  
    /** 
     *            
     *  
     * @return        
     */  
    private String saveCatchInfo2File(Throwable ex) {  
        Writer writer = new StringWriter();  
        PrintWriter printWriter = new PrintWriter(writer);  
        ex.printStackTrace(printWriter);  
        Throwable cause = ex.getCause();  
        while (cause != null) {  
            cause.printStackTrace(printWriter);  
            cause = cause.getCause();  
        }  
        printWriter.close();  
        String sb = writer.toString();  
        try {  
            DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");  
            String time = formatter.format(new Date());  
            String fileName = time + ".txt";  
            System.out.println("fileName:" + fileName);  
            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {  
                String filePath = Environment.getExternalStorageDirectory() + "/HKDownload/" + packgeName  
                        + "/crash/";  
                File dir = new File(filePath);  
                if (!dir.exists()) {  
                    if (!dir.mkdirs()) {  
                        //       :      SD       
                        return "";  
                    }  
                }  
                System.out.println("filePath + fileName:" + filePath + fileName);  
                FileOutputStream fos = new FileOutputStream(filePath + fileName);  
                fos.write(sb.getBytes());  
                fos.close();  
                //        ,                 ,        ,         
            }  
            return fileName;  
        } catch (Exception e) {  
            System.out.println("an error occured while writing file..." + e.getMessage());  
        }  
        return null;  
    }  

    // ------------------------------activity  -----------------------//  

    // activity  :      activity  
    public void removeActivity(Activity activity) {  
        activityList.remove(activity);  
    }  

    // activity  :  activity     
    public void addActivity(Activity activity) {  
        activityList.add(activity);  
    }  

    // activity  :    activity  
    public void finishAllActivity() {  
        for (Activity activity : activityList) {  
            if (null != activity) {  
                activity.finish();  
            }  
        }  
    }  

    //     ,   finishAllActivity()      
    //   : finishAllActivity;finishProgram();  
    public void finishProgram() {  
        android.os.Process.killProcess(android.os.Process.myPid());  
    }  
} 

例外取得の簡単な使い方:
public class MyApplication extends Application implements  
        Thread.UncaughtExceptionHandler {  
    @Override  
    public void onCreate() {  
        super.onCreate();  
        //  Thread Exception Handler  
        Thread.setDefaultUncaughtExceptionHandler(this);  
    }  

    @Override  
    public void uncaughtException(Thread thread, Throwable ex) {  
        System.out.println("uncaughtException");  
        System.exit(0);  
        Intent intent = new Intent(this, MainActivity.class);  
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |  
        Intent.FLAG_ACTIVITY_NEW_TASK);  
        startActivity(intent);  
    }  

}  

以上の試みは成功しなかったが,次の方法は成功した.ステップ1.自分のアプリケーションクラスのonCreate()メソッドにコードを追加して異常をキャプチャし、異常を処理します.Thread.setDefaultUncaughtExceptionHandler(restartHandler);//プログラムクラッシュ時にトリガーされるスレッドの下には、プログラムクラッシュ異常をキャプチャするために使用されます.
@Override
    public void onCreate() {
        super.onCreate();
        Thread.setDefaultUncaughtExceptionHandler(restartHandler); //                        
        }

ステップ2、作成方法作成サービス崩壊異常をキャプチャし、処理する
//             
    private UncaughtExceptionHandler restartHandler = new UncaughtExceptionHandler() {
        public void uncaughtException(Thread thread, Throwable ex) {
            restartApp();//       ,    
        }
    };
    //  App
    public void restartApp(){
        Intent intent = new Intent(this,MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        this.startActivity(intent);
        android.os.Process.killProcess(android.os.Process.myPid());  //                             
    }

問題の解決に成功した.