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

        在我们通常开发的应用程序中,不可避免的会出现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/";
	}
	@Override
	public 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{
	@Override
	public void onCreate() {
		super.onCreate();
		CrashHandler instance = CrashHandler.getInstance();
		//这里的init方法的作用就是为应用程序设置异常处理,然后应用程序才会获取到未处理的异常
		instance.init(this);
	}
}
        测试Activity----->MainActivity

public class MainActivity extends Activity {

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

 

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

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值