程序异常的处理的分析---从起步到超越

                   相信大家在使用一些软件时,它们崩溃前都会出现一些对话框,例如“程序终止,点击确定发送错误日志以便我们更好解决问题!”这些应用程序是怎么处理的呢?

                   所谓“智者千虑,必有一失”。在Android中肯定没少遇到过空指针异常、程序异常终止等相关问题。即便是调试成功了,也很难保证用户的操作不会造成新问题的发生。对于此类FC(force close )问题,我们现在就来看看“愚者千虑,必有一得”的逆袭! 



【一】起步篇


先上一段代码:

public class Myapp extends Application {

	@Override
	public void onLowMemory() {
		
		super.onLowMemory();
		Intent intent= new Intent();
		intent.setAction("kill other process");
		sendBroadcast(intent);
	}

}
先定义一个新类,由于需要应用程序的相关操作,继承 Application类。在继承类后,这个例子中,我们先看最简单的一个错误解决办法: onLowMemory(),顾名思义,就是在低内存状态程序会触动执行的方法。这个方法可以说把一般左右的问题都解决了。


在这个例子中,我们先是注册了一个广播接受者,在filter里指定一个动作(这里是“kill other process”),在低内存时,发送广播,在继承广播的类里,定义收到广播后的方法,例如可以杀死一些后台进程,或指定其它方法。


【二】同步篇

既然会了基本的问题处理,那么剩下的问题呢?比如程序的空指针异常问题,现在我们仍旧没有处理它。现在我们就来看看另一个需要继承的方法:onCreat()。这个方法我们很熟悉了,它确实和预想中的一样,是程序第一次执行时启动的方法。

这样,我们就知道了可以把许多初始化操作放在其中执行。要想彻底解决其他问题,我们还需要再新建一个类,实现UncaughtExceptionHandler 的接口。这个接口位于lang下的线程中(import java.lang.Thread.UncaughtExceptionHandler)。我们仍旧从代码着手。请看代码:

public class MyCrashHandler implements UncaughtExceptionHandler {
  
	private MyCrashHandler(){
	  
  }
	//该类的实例对应一把锁,syschronized方法必须获得调用该方法的类的实例才能执行,否则线程阻塞
	private static MyCrashHandler myCrashHandler;
	
	public static synchronized MyCrashHandler getInstance(){
		if(myCrashHandler==null){
			myCrashHandler=new MyCrashHandler();
		}
		return myCrashHandler;
		
	} 
	
	
	public void uncaughtException(Thread arg0, Throwable arg1) {
		System.out.println("程序出错FC");
		android.os.Process.killProcess(android.os.Process.myPid());

	}

}

实现接口中的一个方法: public void uncaughtException(Thread arg0, Throwable arg1)

这里我们在控制台中打印log,并利用安卓进程管理机制,杀死当前的进程。同时,为了保证只创建一个类的实例,我们私有化构造方法,并利用java中的synchronized关键字,实现进程锁。这样,就能保证创建类的实例对象时,只能一次性的、且通过getInstance()方法进行。



好了,再回到Myapp类里,写写onCreat()方法

public class Myapp extends Application {
//应用程序第一次调用时实施绑定UncrashExceptionHandler
	@Override
	public void onCreate() {
		
		super.onCreate();
		MyCrashHandler myCrashHandler= MyCrashHandler.getInstance();
		Thread.currentThread().setUncaughtExceptionHandler(myCrashHandler);
	}
     
}

我们调用getInstance()方法,返回得到一个实现了uncaughtException方法的对象。我们使用代码将其绑定到程序所在的当前进程中。

Thread.currentThread().setUncaughtExceptionHandler(myCrashHandler)




【三】超越篇


现在我们已经兼顾了几乎可能出现的任何问题。但是,如果有其他偶然因素出现时,或者程序终止后我们需要得到错误日志,让用户把错误日志上传到程序所在的服务器,又要怎么操作呢?很高兴的是,Android工程师给我们提供了相关的方法来获取用户信息。


仍然是一段代码:

StringBuilder sb = new StringBuilder();
		// 1.获取当前应用程序的版本号.
		PackageManager pm = context.getPackageManager();
		try {
			PackageInfo packinfo = pm.getPackageInfo(context.getPackageName(),
					0);
			sb.append("程序的版本号为" + packinfo.versionName);
			sb.append("\n");

			// 2.获取手机的硬件信息.
			Field[] fields = Build.class.getDeclaredFields();
			for (int i = 0; i < fields.length; i++) {
				// 暴力反射,获取私有的字段信息
				fields[i].setAccessible(true);
				String name = fields[i].getName();
				sb.append(name + " = ");
				String value = fields[i].get(null).toString();
				sb.append(value);
				sb.append("\n");
			}
			// 3.获取程序错误的堆栈信息 .
			StringWriter writer = new StringWriter();
			PrintWriter printWriter = new PrintWriter(writer);
			ex.printStackTrace(printWriter);
			
		    String result =	writer.toString();
		    sb.append(result);
		    
		    
		    System.out.println(sb.toString());

			// 4.把错误信息 提交到服务器
                uploadtoHttp(sb);
		    
		} catch (Exception e) {
			e.printStackTrace();
		}

		// 完成自杀的操作
		android.os.Process.killProcess(android.os.Process.myPid());
	}
分析以上代码,不难发现,我们先是得到一个包的管理器(PackageManager),然后调用 getPackageInfo方法,获取到出错的版本等软信息。

Android里将所有的硬件信息都打包到了Build.class.getDeclaredFields()中,我们调用它,就会返回一个Field的数组,返回了此类的所有信息。接着,我们将所有Field里的字串直接拼接到Stringbuilder中。然后用ex.printStackTrace(printWriter)获取错误的堆栈信息。如果有所需要,还可以把这些信息都一起发送到服务器。这样工程师就能对错误进行进一步的统计分析,对产品进行优化。



OK,现在大功告成,是不是感觉你的应用程序变得健康许多了呢~









  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值