Android进阶之路 – 异常捕获崩溃后重新自启动App

1,135次阅读
没有评论

篇中归纳皆来自多篇网络Blog,只是在其基础上进行效果实验,整合之后写出自己的想法 ,方便予己 ~

目前我仅知俩种捕获异常方式(主讲第一种方式)

系统自带的异常机制,一般是通过实现Thread.UncaughtExceptionHandler接口来实现异常监听
集成三方平台用于捕获异常,我有使用Bugly集成测试过 ~
If you are happy, you can do anything ~
结果测试 – 封装版
简洁版
捕获异常
基础配置
业务版
捕获异常
基础配置
封装版
捕获异常
基础配置
基类封装
自造异常 – 结果测试
小课堂
前情提要: 三个版本之间完全解耦,可独立查看任一版本; 篇中版本之间的代码重复率在百分之90以上,只是争对不同场景,做了归纳 ~

Look Here Baby 一看到自启动这三个字,忍不住的要推下我的另一篇Blog – Android进阶之路 – 开机自启动

经检测针对 Android 9.0 系统,代码有效,可实现我们的需求效果 ~

简洁版代码较少,基本均为必要代码;
业务版主要针对需要上传App奔溃错误到后台的需求;
封装版适用项目,解耦的同时也方便管理;
结果测试 – 封装版

简洁版
主要基于Demo去实现,并没有进行Base封装Activity !

捕获异常
CrashHandler

package nk.com.restartapp;

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;

/**

  • @author MrLiu
  • @date 2020/5/13
  • desc 捕获异常
    */
    public class CrashHandler implements Thread.UncaughtExceptionHandler {
    private Thread.UncaughtExceptionHandler mDefaultHandler;
    MyApplication application; public CrashHandler(MyApplication myApplication) {
    // // 获取系统默认的UncaughtException处理器
    mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
    this.application = myApplication;
    } /**
    • 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成
      */
      @Override
      public void uncaughtException(Thread thread, Throwable ex) {
      // 重启app
      Intent intent = new Intent(application.getApplicationContext(), MainActivity.class);
      //PendingIntent restartIntent = PendingIntent.getActivity(application.getApplicationContext(), 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);
      PendingIntent restartIntent = PendingIntent.getActivity(MyApplication.getContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
      // 退出程序
      AlarmManager mgr = (AlarmManager) application.getSystemService(Context.ALARM_SERVICE);
      // 3秒后重启
      mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 3000, restartIntent);
      //结束进程之前可以把你程序的注销或者退出代码放在这段代码之前
      android.os.Process.killProcess(android.os.Process.myPid());
      }

基础配置
初始化 – MyApplication

package nk.com.restartapp;

import android.app.Activity;
import android.app.Application;
import android.content.Context;

import java.util.ArrayList;
import java.util.List;

/**

  • @author MrLiu
  • @date 2020/5/13
  • desc
    */
    public class MyApplication extends Application {
    private static Context context;
    List activityList = new ArrayList<>(); @Override
    public void onCreate() {
    super.onCreate();
    context = getApplicationContext(); //初始化-异常捕获(设置该CrashHandler为程序的默认处理器) CrashHandler unCeHandler = new CrashHandler(this); Thread.setDefaultUncaughtExceptionHandler(unCeHandler); } public static Context getContext() {
    return context;
    }
    }

清单注册 application – 注册我们自己的MyApplication

android:name=”.MyApplication”

AndroidManifest.xml

<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>

业务版
主要基于Demo去实现,并没有进行Base封装Activity !

内部百分之90的代码相同,唯一不同的是CrashHandler(异常)的一个处理方式,在这个版本中可以在APP崩溃之前将错误上传到后台,主要用于及时定位问题 ;

捕获异常
CrashHandler

package nk.com.startappdemo;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**

  • @author MrLiu
  • @date 2020/5/12
  • desc 异常捕获处理 ~
    */
    public class CrashHandler implements Thread.UncaughtExceptionHandler {
    public static final String TAG = “CrashHandler”; private static CrashHandler INSTANCE = new CrashHandler();
    /**
    • 系统默认的UncaughtException处理类
      / private Thread.UncaughtExceptionHandler mDefaultHandler; /
    • 用来存储设备信息和异常信息
      **/
      private Map mInfos = new HashMap();

    private DateFormat mFormatter = new SimpleDateFormat(“yyyy-MM-dd-HH-mm-ss”); public CrashHandler() {
    } public static CrashHandler getInstance() {
    return INSTANCE;
    } public void init() {
    // 获取系统默认的UncaughtException处理器
    mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
    // 设置该CrashHandler为程序的默认处理器
    Thread.setDefaultUncaughtExceptionHandler(this);
    } /**

    • @描述: 当UncaughtException发生时会转入该函数来处理
      */
      @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(this.getClass().toString(), e == null ? “” : e.toString());
      } // 重新启动应用 Intent intent = new Intent(MyApplication.getContext(), MainActivity.class); PendingIntent restartIntent = PendingIntent.getActivity(MyApplication.getContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); AlarmManager mgr = (AlarmManager) MyApplication.getContext().getSystemService(Context.ALARM_SERVICE); // 1秒钟后重启应用 mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent); // todo:退出程序 android.os.Process.killProcess(android.os.Process.myPid()); System.exit(1); }
      }

    /**

    • @return true:如果处理了该异常信息;否则返回false.
    • @throws
    • @描述:自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
      */
      private boolean handleException(Throwable ex) {
      if (null == ex) {
      return false;
      }
      // 使用Toast来显示异信息
      new Thread() {
      @Override
      public void run() {
      Looper.prepare();
      Toast.makeText(MyApplication.getContext(), “程序开了个小差,即将退出.”, Toast.LENGTH_LONG).show();
      Looper.loop();
      }
      }.start();
      // 收集设备参数信息
      collectDeviceInfo(MyApplication.getContext());
      // 保存日志文件
      saveCrashInfo2File(ex);
      return true;
      }

    /**

    • @描述:收集设备参数信息
      */
      private void collectDeviceInfo(Context context) {
      try {
      PackageManager pm = context.getPackageManager();
      PackageInfo pi = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES);
      if (pi != null) {
      String versionName = pi.versionName == null ? “null” : pi.versionName;
      String versionCode = pi.versionCode + “”;
      mInfos.put(“versionName”, versionName);
      mInfos.put(“versionCode”, versionCode);
      }
      } catch (PackageManager.NameNotFoundException e) {
      Log.e(TAG, “an error occured when collect package info”, e);
      }
      Field[] fields = Build.class.getDeclaredFields();
      for (Field field : fields) {
      try {
      field.setAccessible(true);
      mInfos.put(field.getName(), field.get(null).toString());
      Log.d(TAG, field.getName() + ” : ” + field.get(null));
      } catch (Exception e) {
      Log.e(TAG, “an error occured when collect crash info”, e);
      }
      }
      }

    /**

    • @throws
    • @描述:保存错误信息到文件中 目录/sdcard/qfangadtv/crash/
    • @返回类型 void 返回文件名称,便于将文件传送到服务器
      */
      private String saveCrashInfo2File(Throwable ex) { StringBuffer sb = new StringBuffer();
      for (Map.Entry entry : mInfos.entrySet()) {
      String key = entry.getKey();
      String value = entry.getValue();
      sb.append(key + “=” + value + “\n”);
      } 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 result = writer.toString();
      sb.append(result);
      try {
      long timestamp = System.currentTimeMillis();
      String time = mFormatter.format(new Date());
      String fileName = “crash-” + time + “-” + timestamp + “.log”;
      if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
      String path = “/sdcard/×××/crash/”;
      File dir = new File(path);
      if (!dir.exists()) {
      dir.mkdirs();
      }
      FileOutputStream fos = new FileOutputStream(path + fileName);
      fos.write(sb.toString().getBytes());
      fos.close();
      }
      return fileName;
      } catch (Exception e) {
      Log.e(TAG, “an error occured while writing file…”, e);
      }
      return null;
      }
      }

基础配置
初始化 – MyApplication

package nk.com.startappdemo;

import android.app.Activity;
import android.app.Application;
import android.content.Context;

import java.util.ArrayList;
import java.util.List;

/**

  • @author MrLiu
  • @date 2020/5/13
  • desc
    */
    public class MyApplication extends Application {
    private static Context context;
    List activityList = new ArrayList<>(); @Override
    public void onCreate() {
    super.onCreate();
    context = getApplicationContext(); //初始化-异常捕获(设置该CrashHandler为程序的默认处理器) CrashHandler unCeHandler = new CrashHandler(this); Thread.setDefaultUncaughtExceptionHandler(unCeHandler); } //可以声明内部的 MyApplication 成员参数 或 在子类采用 MyApplication application = (MyApplication) getApplication();
    public static Context getContext() {
    return context;
    }
    }

AndroidManifest.xml

<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>

封装版
基于项目开发原则进行二次简单封装,方便管理 ( Demo地址在此 ) ~

捕获异常
CrashHandler

注意:如果APP莫名的崩溃,同时又没有自启动!那么查看内部的uncaughtException方法,将重启app的逻辑放在if、else的最外层!

package nk.com.restartapp;

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;

/**

  • @author MrLiu
  • @date 2020/5/13
  • desc 捕获异常
    */
    public class CrashHandler implements Thread.UncaughtExceptionHandler {
    private Thread.UncaughtExceptionHandler mDefaultHandler;
    MyApplication application; public CrashHandler(MyApplication myApplication) {
    // // 获取系统默认的UncaughtException处理器
    mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
    this.application = myApplication;
    } /**
    • 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
      *
    • @param ex
    • @return true:如果处理了该异常信息;否则返回false.
      */
      @Override
      public void uncaughtException(Thread thread, Throwable ex) {
      if (!handlerException(ex) && mDefaultHandler != null) {
      // 如果用户没有处理则让系统默认的异常处理器来处理
      mDefaultHandler.uncaughtException(thread, ex);
      } else {
      try {
      Thread.sleep(2000);
      } catch (InterruptedException e) {
      Log.e(“CatchExcep”, “error ;”, e);
      }
      // 重启app
      Intent intent = new Intent(application.getApplicationContext(), MainActivity.class);
      //PendingIntent restartIntent = PendingIntent.getActivity(application.getApplicationContext(), 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);
      PendingIntent restartIntent = PendingIntent.getActivity(MyApplication.getContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
      // 退出程序
      AlarmManager mgr = (AlarmManager) application.getSystemService(Context.ALARM_SERVICE);
      // 3秒后重启
      mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 3000, restartIntent);
      //关闭已打开的Activity后,杀死应用进程(其实有点画蛇添足,因为杀死应用进城时会自动关闭所有的Activity等 ~)
      application.finishAllActivity();
      }
      }

    /**

    • 获取具体异常,此处可做崩溃前的处理
      *
    • @param ex
    • @return true:如果处理了该异常信息;否则返回false.
      */
      private boolean handlerException(Throwable ex) {
      if (ex == null) {
      return false;
      }
      // 发个友好的提示,弹个土司 – 此处只是为了效果,可进行注释或替换为自己的逻辑代码
      new Thread() {
      public void run() {
      Looper.prepare();
      Toast.makeText(application.getApplicationContext(), “检测到程序异常,即将退出”, Toast.LENGTH_SHORT).show();
      Looper.loop();
      }
      }.start();
      return true;
      }
      }

基础配置
初始化 – MyApplication

package nk.com.restartapp;

import android.app.Activity;
import android.app.Application;
import android.content.Context;

import java.util.ArrayList;
import java.util.List;

/**

  • @author MrLiu
  • @date 2020/5/13
  • desc
    */
    public class MyApplication extends Application {
    private static Context context;
    List activityList = new ArrayList<>(); @Override
    public void onCreate() {
    super.onCreate();
    context = getApplicationContext();
    // 设置该CrashHandler为程序的默认处理器
    CrashHandler unCeHandler = new CrashHandler(this);
    Thread.setDefaultUncaughtExceptionHandler(unCeHandler);
    } /**
    • context
      */
      public static Context getContext() {
      return context;
      }

    /**

    • @param activity activity关闭时,删除Activity列表中的Activity对象
      */
      public void removeActivity(Activity activity) {
      activityList.remove(activity);
      }

    /**

    • @param activity 向列表中添加Activity对象
      */
      public void addActivity(Activity activity) {
      activityList.add(activity);
      }

    /**

    • 关闭Activity列表中的 所有Activity
      */
      public void finishAllActivity() {
      for (Activity activity : activityList) {
      if (null != activity) {
      activity.finish();
      }
      }
      // 杀死应用进程
      android.os.Process.killProcess(android.os.Process.myPid());
      }
      }

清单注册application – 注册我们自己的MyApplication

android:name=”.MyApplication”

示例如下:AndroidManifest.xml

<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>

基类封装
BaseActivity

package nk.com.restartapp;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;

/**

  • @author MrLiu
  • @date 2020/5/13
  • desc
    */
    public class BaseActivity extends AppCompatActivity { private MyApplication application; @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    application = (MyApplication) getApplication();
    application.addActivity(this);
    } @Override
    protected void onDestroy() {
    super.onDestroy();
    application.removeActivity(this);
    }
    }

自造异常 – 结果测试
MainActivity

package nk.com.restartapp;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends BaseActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Toast.makeText(this, "启动完成", Toast.LENGTH_SHORT).show();

    findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            List<Object> list = new ArrayList<>();
        }
    });
}

}

activity_main

<TextView
    android:id="@+id/btn"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:layout_gravity="center"
    android:background="#ff7"
    android:gravity="center"
    android:textColor="#f42"
    android:text="自创崩溃 - 数据越界" />

小课堂
直接重启App

private void restartApp() {
        Intent intent = new Intent(this, MainActivity.class);  
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |  
        Intent.FLAG_ACTIVITY_NEW_TASK);  
        startActivity(intent);  
        System.exit(0);  
}

延时重启App

private void restartApp() {
    Intent intent = new Intent(this, MainActivity.class);
    PendingIntent restartIntent = PendingIntent.getActivity(
            application.getApplicationContext(), 0, intent,Intent.FLAG_ACTIVITY_NEW_TASK);
    //退出程序
    AlarmManager mgr = (AlarmManager)application.getSystemService(Context.ALARM_SERVICE);
    // 1秒钟后重启应用
    mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent); 
    //结束进程之前可以把你程序的注销或者退出代码放在这段代码之前
    android.os.Process.killProcess(android.os.Process.myPid());
}

正文完
可以使用微信扫码关注公众号(ID:xzluomor)
post-qrcode
 0
评论(没有评论)

文心AIGC

2023 年 9 月
 123
45678910
11121314151617
18192021222324
252627282930  
文心AIGC
文心AIGC
人工智能ChatGPT,AIGC指利用人工智能技术来生成内容,其中包括文字、语音、代码、图像、视频、机器人动作等等。被认为是继PGC、UGC之后的新型内容创作方式。AIGC作为元宇宙的新方向,近几年迭代速度呈现指数级爆发,谷歌、Meta、百度等平台型巨头持续布局
文章搜索
热门文章
潞晨尤洋:日常办公没必要上私有模型,这三类企业才需要 | MEET2026

潞晨尤洋:日常办公没必要上私有模型,这三类企业才需要 | MEET2026

潞晨尤洋:日常办公没必要上私有模型,这三类企业才需要 | MEET2026 Jay 2025-12-22 09...
“昆山杯”第二十七届清华大学创业大赛决赛举行

“昆山杯”第二十七届清华大学创业大赛决赛举行

“昆山杯”第二十七届清华大学创业大赛决赛举行 一水 2025-12-22 17:04:24 来源:量子位 本届...
MiniMax海螺视频团队首次开源:Tokenizer也具备明确的Scaling Law

MiniMax海螺视频团队首次开源:Tokenizer也具备明确的Scaling Law

MiniMax海螺视频团队首次开源:Tokenizer也具备明确的Scaling Law 一水 2025-12...
清库存!DeepSeek突然补全R1技术报告,训练路径首次详细公开

清库存!DeepSeek突然补全R1技术报告,训练路径首次详细公开

清库存!DeepSeek突然补全R1技术报告,训练路径首次详细公开 Jay 2026-01-08 20:18:...
最新评论
ufabet ufabet มีเกมให้เลือกเล่นมากมาย: เกมเดิมพันหลากหลาย ครบทุกค่ายดัง
tornado crypto mixer tornado crypto mixer Discover the power of privacy with TornadoCash! Learn how this decentralized mixer ensures your transactions remain confidential.
ดูบอลสด ดูบอลสด Very well presented. Every quote was awesome and thanks for sharing the content. Keep sharing and keep motivating others.
ดูบอลสด ดูบอลสด Pretty! This has been a really wonderful post. Many thanks for providing these details.
ดูบอลสด ดูบอลสด Pretty! This has been a really wonderful post. Many thanks for providing these details.
ดูบอลสด ดูบอลสด Hi there to all, for the reason that I am genuinely keen of reading this website’s post to be updated on a regular basis. It carries pleasant stuff.
Obrazy Sztuka Nowoczesna Obrazy Sztuka Nowoczesna Thank you for this wonderful contribution to the topic. Your ability to explain complex ideas simply is admirable.
ufabet ufabet Hi there to all, for the reason that I am genuinely keen of reading this website’s post to be updated on a regular basis. It carries pleasant stuff.
ufabet ufabet You’re so awesome! I don’t believe I have read a single thing like that before. So great to find someone with some original thoughts on this topic. Really.. thank you for starting this up. This website is something that is needed on the internet, someone with a little originality!
ufabet ufabet Very well presented. Every quote was awesome and thanks for sharing the content. Keep sharing and keep motivating others.
热评文章
摩尔线程的野心,不藏了

摩尔线程的野心,不藏了

摩尔线程的野心,不藏了 量子位的朋友们 2025-12-22 10:11:58 来源:量子位 上市后的仅15天...
摩尔线程的野心,不藏了

摩尔线程的野心,不藏了

摩尔线程的野心,不藏了 量子位的朋友们 2025-12-22 10:11:58 来源:量子位 上市后的仅15天...
AI体育教练来了!中国团队打造SportsGPT,完成从数值评估到专业指导的智能转身

AI体育教练来了!中国团队打造SportsGPT,完成从数值评估到专业指导的智能转身

AI体育教练来了!中国团队打造SportsGPT,完成从数值评估到专业指导的智能转身 量子位的朋友们 2025...
AI体育教练来了!中国团队打造SportsGPT,完成从数值评估到专业指导的智能转身

AI体育教练来了!中国团队打造SportsGPT,完成从数值评估到专业指导的智能转身

AI体育教练来了!中国团队打造SportsGPT,完成从数值评估到专业指导的智能转身 量子位的朋友们 2025...
真正面向大模型的AI Infra,必须同时懂模型、系统、产业|商汤大装置宣善明@MEET2026

真正面向大模型的AI Infra,必须同时懂模型、系统、产业|商汤大装置宣善明@MEET2026

真正面向大模型的AI Infra,必须同时懂模型、系统、产业|商汤大装置宣善明@MEET2026 量子位的朋友...