在编写android客户端应用时,总会由于各种各样的原因,导致我们的程序异常退出,这些原因包括:程序的不合理,异常的未捕获,这些通过我们的review都是可以提高的,但是如果是由于android不同的系统版本,不同的配置的机型导致我们的程序异常退出,这是无法避免的,但如何才能减少这个原因导致的程序异常呢,这正是写本篇文章的意图.
在全局异常处理开始前,有两个类是我们必须要知道的,一个是android的Application类,这个类是一个应用程序的全局类,可以将一些所有模块都会用的公共信息都放在这个类中初始化,例如:用户登陆信息,手机信息等,一个应用程序的启动最先启动的就是其对应的Application类的实例,然后再由这个实例去调用要启动的那个Activity,另一个就是全局异常捕获类:Thread.UncaughtExceptionHandler,线程未捕获异常处理器,用来处理未捕获异常。如果程序出现了未捕获异常,默认会弹出系统中强制关闭对话框。我们需要实现此接口,并注册为程序中默认未捕获异常处理。这样当未捕获异常发生时,就可以定制异常处理操作,例如:将异常信息存放到SD卡文件中,将应用程序强制关闭,上传错误的日志文件等.
一般情况下出现这种异常的原因有以下几点:
1.应用的兼容性欠缺,不过这个孔明 没有办法的事件,android手机千差万别,不同的硬件配置,不同的的手机尺寸,不同的系统版本,所以难免会有考虑不周全的地方.
2.编写程序时使用了高版本的API,这样当应用跑到低版本的android系统时自然会有异常发生.
第二种情况是我们在写代码时可以尽量避免的,那就是如果用到了高版本的API,那一定要针对低版本的系统去做处理,这样就可减少这个原因产生的异常.那对于第一种情况怎么办呢,就要用到我们今天的主角,全局异常捕获了.
当APP异常退出时,这部分异常信息是可以通过全局异常处理机制捕获到的,一旦捕获到后,就可以上传到我们的文件服务器中,去做分析,针对性的改进,这就是全局异常处理最主要的作用.
全局异常示例代码:
/**********************************************************
* @文件名称:MicCrashHandler.java
* @创建时间:2014年10月20日 下午1:10:15
* @文件描述:捕获全局未处理到的异常,上传服务器
* @修改历史:2014年10月20日创建初始版本
**********************************************************/
public class MicCrashHandler implements UncaughtExceptionHandler
{
public static final String TAG = "MicCrashHandler";
/**
* 系统默认的异常捕获类
*/
private Thread.UncaughtExceptionHandler mDefaultHandler;
/**
* 自定义异常处理类
*/
private static MicCrashHandler INSTANCE;
private Context mContext;
/**
* 存储异常信息
*/
private HashMap infos = new HashMap();
// 存储文件夹路径
private static final String path = Environment.getExternalStorageDirectory() + "/focustech/mic/log/";
private File dirFile;
private File file;
private static final String fileName = "mic_crash_exception.log";
private MicCrashHandler()
{
}
static
{
INSTANCE = new MicCrashHandler();
}
/**
* 单例模式,获取自定义异常处理类
*/
public static MicCrashHandler getInstance()
{
return INSTANCE;
}
public void init(Context context)
{
mContext = context;
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
}
/**
*
* 自定义异常处理
* @param thread
* @param ex
*/
@Override
public void uncaughtException(Thread thread, Throwable ex)
{
if (!handleException(ex) && mDefaultHandler != null)
{
// 如果用户没有处理则让系统默认的异常处理器来处理
mDefaultHandler.uncaughtException(thread, ex);
}
else
{
}
}
/**
* 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
*/
private boolean handleException(Throwable ex)
{
if (ex == null)
{
return false;
}
new Thread()
{
@Override
public void run()
{
Looper.prepare();
ToastUtil.toast(mContext, R.string.crash_exception);
Looper.loop();
}
}.start();
// 收集设备参数信息
Util.collectDeviceInfo(mContext, infos);
// 保存日志文件
saveCrashInfo2File(ex);
/**
* 以后要加上传功能,需要启动服务去上传应该
*/
// uploadExceptionFile();
ActivityManager.getInstance().finishAllActivity();
Process.killProcess(Process.myPid());
System.exit(0);
return true;
}
/**
* 保存错误信息到文件中
* @param ex
* @return 返回文件名称,便于将文件传送到服务器
*/
private void saveCrashInfo2File(Throwable ex)
{
/**
* 组装异常信息
*/
String exceptionMsg = assembleExceptionMsg(ex);
try
{
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
{
dirFile = new File(path);
if (!dirFile.exists())
{
dirFile.mkdirs();
}
file = new File(path + fileName);
RandomAccessFile fos = new RandomAccessFile(file, "rw");
fos.seek(file.length());
fos.write(exceptionMsg.getBytes());
fos.close();
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
/**
* 组装异常信息,在这里拼装想要的格式
*/
private String assembleExceptionMsg(Throwable ex)
{
StringBuffer sb = new StringBuffer();
for (Map.Entry entry : infos.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 + "\r\n");
return sb.toString();
}
/**
* 发送上传文件请求
*/
@SuppressWarnings("unused")
private void uploadExceptionFile()
{
if (!NetworkUtils.isConnectInternet(mContext))
{
return;
}
if (file == null || !file.exists())
{
return;
}
else
{
RequestCenter.uploadExceptionFile(mContext, listener, file);
}
}
private DisposeDataListener listener = new DisposeDataListener()
{
@Override
public void onSuccess(Object obj)
{
/**
* 发送成功后,还要删除此异常文件,才退出
*/
SysManager.exitSystem(mContext);
}
@Override
public void onFailure(Object failedReason)
{
SysManager.exitSystem(mContext);
}
};
}