Android-----使用UncaughtExceptionHandler捕获全局异常

来源:互联网 发布:centos linux 删除软件 编辑:程序博客网 时间:2024/06/05 00:39

        在我们通常开发的应用程序中,不可避免的会出现crash现象,特别是当应用程序已经上线之后,这些crash异常信息我们通常是很难捕捉到的,如果我们不能对这些异常信息做及时的收集并且修复的话,势必会带来用户体验度的下降,为此,Android的Thread类中为我们提供了setDefaultUncaughtExceptionHandler方法,这个方法会为我们设置默认的异常处理器,当然这个默认的异常处理器是我们自己实现UncaughtExceptionHandler接口来实现的,这个接口里面存在一个uncaughtExceptionHandler方法,我们可以在这个方法里面进行一些写日志的操作,同时呢,将我们的异常信息发送给我们的服务端,服务端收到这些异常信息之后就可以进行BUG的修复工作了,下面是我实现的一个捕获全局异常的实例:

        实现步骤是:

        (1):创建一个实现了UncaughtExceptionHandler接口的类,并且实现它里面的uncaughtExceptionHandler方法;

        (2):通过Thread的setDefaultUncaughtExceptionHandler方法将我们创建的UncaughtExceptionHandler对象设置为默认的异常处理器,这样的话,当异常发生的时候就会回调它里面的uncaughtExceptionHandler方法了,我们可以在uncaughtExceptionHandler方法里面进行异常信息上传服务器或者异常信息写入SD的操作;

        (3):因为我们的异常是发生在整个应用程序中的,所以我们应该保证的就是我们的setDefaultUncaughtExceptionHandler的调用以及UncaughtExceptionHandler对象的创建是在应用初始化的时候完成的,因此我们需要实现自己的Application对象,具体来说就是继承Application接口,在onCreate方法里面进行这些操作就可以了;

        实现我们自己的UncaughtExceptionHandler----->CrashHandler

public class CrashHandler implements UncaughtExceptionHandler{//存储异常信息文件的路径private static String FILE_PATH = "";// = Environment.getExternalStorageDirectory().getPath()+"/CrashFile/";//存储异常信息文件名private static final String FILE_NAME = "crash";//存储异常信息文件的后缀名private static final String FILE_SUFFIX_NAME = ".txt";//当前的应用上下文private Context mContext;//创建一个单例的CrashHandler对象private static CrashHandler instance = new CrashHandler();private UncaughtExceptionHandler systemDefaultHandler;private CrashHandler(){}public static CrashHandler getInstance(){return instance; }public void init(Context context){FILE_PATH = getFilePath(context);systemDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();//首先获得系统已经默认的异常处理器Thread.setDefaultUncaughtExceptionHandler(this);//设置当前UncaughtExceptionHandler对象为异常处理器mContext = context.getApplicationContext();}/** * 获取到存储错误日志信息文件的存储路径 * @param context * @return */public String getFilePath(Context context){String filePath = "";filePath = context.getCacheDir().getPath();return filePath+"/CrashFile/";}@Overridepublic void uncaughtException(Thread thread, Throwable throwable) {//到处错误信息到本地SD卡文件writeExceptionToSDCard(throwable);if(systemDefaultHandler != null){//由系统默认的异常处理器来进行处理systemDefaultHandler.uncaughtException(thread, throwable);}else{//由当前进程自己结束掉自己Process.killProcess(Process.myPid());}}/** * 将错误信息写入到SD卡上面 * @param throwable */public void writeExceptionToSDCard(Throwable throwable){if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){//表示SD不存在,则直接退出就可以了return;}//如果SD卡存在的话,则我们需要将异常信息写入到SD卡就可以了File dir = new File(FILE_PATH);if(!dir.exists()){//目录不存在,则创建目录dir.mkdir();}//创建出来一个异常信息文件名出来SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");String nowStringTime = format.format(new Date());String realFilePath = FILE_PATH+FILE_NAME+"_"+nowStringTime+"_"+FILE_SUFFIX_NAME;//真正的异常信息文件的名字File file = new File(realFilePath);//将错误信息写到日志文件中try {PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(file)));//将当前时间写到日志文件中writer.println(nowStringTime);//将手机型号信息写到日志文件中writePhoneInfoToSDCard(writer);writer.println();throwable.printStackTrace(writer);writer.close();//关闭资源} catch (Exception e) {e.printStackTrace();}}/** * 将手机型号信息写到SD卡上面 * @param writer * @throws NameNotFoundException  */public void writePhoneInfoToSDCard(PrintWriter writer) throws NameNotFoundException{PackageManager manager = mContext.getPackageManager();PackageInfo info = manager.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES);//App版本号writer.print("App_Version: ");writer.print(info.versionName+"_");writer.println(info.versionCode);//Android版本号writer.print("Android Version: ");writer.print(Build.VERSION.RELEASE+"_");writer.println(Build.VERSION.SDK_INT);//手机制造商writer.print("Manufacturer: ");writer.println(Build.MANUFACTURER);//手机型号writer.print("Model: ");writer.println(Build.MODEL);//CPU架构writer.print("CPU ABI: ");writer.println(Build.CPU_ABI);}}
        创建我们自己的Application----->MyApplication

public class MyApplication extends Application{@Overridepublic void onCreate() {super.onCreate();CrashHandler instance = CrashHandler.getInstance();//这里的init方法的作用就是为应用程序设置异常处理,然后应用程序才会获取到未处理的异常instance.init(this);}}
        测试Activity----->MainActivity

public class MainActivity extends Activity {public Button mButton;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mButton = (Button) findViewById(R.id.button);mButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View arg0) {/***************(1) int result = 1/0; ****************//***************(2) try {int result = 1/0;} catch (Exception e) {}****************//***************(3)new Thread(new Runnable() {@Overridepublic void run() {int result = 1/0;}}).start();****************/}});}}
        如果我们打开(1)处的注释,从DDMS中查看异常输出日志文件信息,可以发现如下内容:

 

        可以看到,他记录了我们除以0所带来的异常信息,但是如果我们注释掉代码(1),打开注释(2)的话,会发现不会产生错误日志文件,原因就在于,我们已经捕获了异常,只不过没有对异常进行处理而已,那么我们的UncaughtExceptionHandler就不再会捕获这个异常了;

        如果我们打开注释(3)的代码,你会发现同样也会创建一个错误日志文件出来,这说明在子线程中出现的异常信息UncaughtExceptionHandler也照样可以捕获到的;

0 0
原创粉丝点击