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

最近公司的项目出现了一点棘手的问题,由于某种未知的原因,该 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;
    }
}

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

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

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值