如何让 App 在崩溃后自动重启

来源:互联网 发布:windows xp qq影音下载 编辑:程序博客网 时间:2024/05/17 06:39

最近公司的项目出现了一点棘手的问题,由于某种未知的原因,该 App 在网络连接上出现了问题,只能用轮询来进行网络请求。但是这种方式会使得 App 每隔半小时就崩溃一次,最后无奈之下,决定让 App 在崩溃后自动重启。
当然了,这只是无法可想之下的应急手段,如果可以解决网络推送的毛病就好了……
下面是对于网络上资料的总结。

捕捉异常处理类

网络上对于程序崩溃的处理已经说得很清楚了(虽然看起来都是同一个人写的代码),就是利用 Thread.UncaughtExceptionHandler 类,重写其中的 uncaughtException(Thread thread, Throwable ex) 方法。

自定义异常处理类

如上所述,关键在于重写 uncaughtException(Thread thread, Throwable ex):

@Override    public void uncaughtException(Thread thread, Throwable ex) {        if (!handleException(ex) && mUncaughtExceptionHandler != null) {            // 若是用户没有设置异常处理,则让系统默认的类来处理异常            mUncaughtExceptionHandler.uncaughtException(thread, ex);        } else {            // 进行自定义的方法            // 设置定时任务,1秒后重启此 App            Intent intent = new Intent(context, MainActivity.class);            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);            PendingIntent restartIntent = PendingIntent.getActivity(context, 0, intent, 0);            AlarmManager mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);            mAlarmManager.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent);            // 移除当前任务            myApplication.finishActivity();        }    }

其中有一个 handleException(Throwable ex) 方法,同样是自己定义的,意在对崩溃是抛出的异常进行处理,例如打印日志、上传崩溃信息等等。

private boolean handleException(Throwable ex) {        if (ex == null) {            return false;        }        // 此处可以进行一些更为复杂的请求,例如打印崩溃信息日志等        // 这里弹出提示信息        new Thread() {            @Override            public void run() {                Looper.prepare();                Toast.makeText(context, "很抱歉,程序崩溃了,一秒钟后重启。", Toast.LENGTH_SHORT).show();                Looper.loop();            }        }.start();        return true;    }

自定义 Application

异常处理类里需要用到的 Context 对象,应当为 Application。
网上很多的代码都是使用 getApplicationContext() 或是 Application.getBaseContext() ,但是我这里在创建 Toast 、Intent 的时候就会出现无法创建的情况,导致后续代码不能执行,异常处理类自然不能正常工作。
因此,建议在程序入口传入 Application 的 Context 对象,后续直接使用此对象。

@Override    public void onCreate() {        super.onCreate();        // 将自定义的异常处理类设为默认        MyUncaughtExceptionHandler catchException = new MyUncaughtExceptionHandler(getApplicationContext());        Thread.setDefaultUncaughtExceptionHandler(catchException);    }

自定义的 Application 很简单,声明了使用自定义的类来捕获崩溃异常。
最后,别忘了在 Manifest 里对 Application 进行初始化。

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.mouzhai.test">    <application        android:name=".MyApplication"        android:allowBackup="true"        android:icon="@mipmap/ic_launcher"        android:label="@string/app_name"        android:roundIcon="@mipmap/ic_launcher_round"        android:supportsRtl="true"        android:theme="@style/AppTheme">        <activity android:name=".MainActivity">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application></manifest>

完整代码

MainActivity.class

这里简单地设置了一个按钮,点击按钮就会使程序崩溃。

    private MyApplication myApplication;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        myApplication = new MyApplication();        myApplication.addActivity(this);        btnCrash = (Button) findViewById(R.id.btn_crash);        btnCrash.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                // 在子线程中改变 UI,会导致程序崩溃                new Thread(new Runnable() {                    @Override                    public void run() {                        btnCrash.setText("ccccccccccccccccc");                    }                }).start();            }        });    }    @Override    protected void onDestroy() {        super.onDestroy();        myApplication.removeActivity(this);    }

MyApplication.class

/** * 在此初始化一些必要的逻辑,并定义了一些管理 Activity 的方法 * 需要获取 Application 级别 Context 对象的方法可以设置在这里 * <p> * Created by Mouzhai on 2017/4/11. */public class MyApplication extends Application {    List<Activity> list = new ArrayList<>();    @Override    public void onCreate() {        super.onCreate();        // 将自定义的异常处理类设为默认        MyUncaughtExceptionHandler catchException = new MyUncaughtExceptionHandler(getApplicationContext());        Thread.setDefaultUncaughtExceptionHandler(catchException);    }    /**     * 当 Activity 结束时,从列表中移除     */    public void removeActivity(Activity a) {        list.remove(a);    }    /**     * 向列表中添加 Activity     */    public void addActivity(Activity a) {        list.add(a);    }    /**     * 结束列表中的所有 Activity     */    public void finishActivity() {        for (Activity activity : list) {            if (null != activity) {                activity.finish();            }        }        // 结束当前进程        android.os.Process.killProcess(android.os.Process.myPid());    }}

MyUncaughtExceptionHandler.class

/** * 自定义异常处理类 * <p> * Created by Mouzhai on 2017/4/11. */public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {    private Context context;    private Thread.UncaughtExceptionHandler mUncaughtExceptionHandler;    private MyApplication myApplication;    public MyUncaughtExceptionHandler(Context context) {        this.context = context;        mUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();// 获取系统默认的异常处理类        myApplication = new MyApplication();    }    @Override    public void uncaughtException(Thread thread, Throwable ex) {        if (!handleException(ex) && mUncaughtExceptionHandler != null) {            // 若是用户没有设置异常处理,则让系统默认的类来处理异常            mUncaughtExceptionHandler.uncaughtException(thread, ex);        } else {            // 进行自定义的方法            // 设置定时任务,1秒后重启此 App            Intent intent = new Intent(context, MainActivity.class);            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);            PendingIntent restartIntent = PendingIntent.getActivity(context, 0, intent, 0);            AlarmManager mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);            mAlarmManager.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent);            // 移除当前任务            myApplication.finishActivity();        }    }    /**     * 对于抛出的异常进行处理,例如打印日志、发送文件给服务器等等     *     * @param ex 导致崩溃的异常     * @return 若在此处理了异常,则返回 true,否则返回 false     */    private boolean handleException(Throwable ex) {        if (ex == null) {            return false;        }        // 此处可以进行一些更为复杂的请求,例如打印崩溃信息日志等        // 这里弹出提示信息        new Thread() {            @Override            public void run() {                Looper.prepare();                Toast.makeText(context, "很抱歉,程序崩溃了,一秒钟后重启。", Toast.LENGTH_SHORT).show();                Looper.loop();            }        }.start();        return true;    }}

点击按钮崩溃,随后自动重启

大功告成!不过最后还是想给自己的项目烧柱香……

0 0
原创粉丝点击