【Android全局异常捕获,解决日志打印三次的BUG】最近写的项目需要自己写全局的异常捕捉,所以百度了很多解决方案,发现出现各种问题,好不容易找到一些比较靠谱的方案,但是却发现出现了一个让我无语的问题——日志打印输出三次。于是又开始去寻找答案,发现并没有相关的解决。好嘛,看来还是要自己搞了。
发生该现象的基本原因就是:Application没有完全退出,导致同一个异常多次执行,于是出现了同一个异常打印多次的问题
【解决方案】
- 处理全局异常的Handler:CrashHandler.java,代码如下:
public class CrashHandler implements UncaughtExceptionHandler {
private static CrashHandler instance;
private UncaughtExceptionHandler mDefaultHandler;
public void init(Context ctx) {
Thread.setDefaultUncaughtExceptionHandler(this);
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
// 获取系统默认的UncaughtException处理器public static CrashHandler getInstance() {
if (instance == null) {
instance = new CrashHandler();
}
return instance;
}/**
* 核心方法,当程序crash 会回调此方法, Throwable中存放这错误日志
*/
@Override
public synchronized void uncaughtException(Thread arg0, Throwable arg1) {
if (mDefaultHandler != null && !handleException(arg1)) {
// 如果自定义的没有处理则让系统默认的异常处理器来处理
mDefaultHandler.uncaughtException(arg0, arg1);
} else {
// 退出程序
try {
Thread.sleep(3000);
// 如果处理了,让程序继续运行3秒再退出,保证文件保存并上传到服务器
} catch (InterruptedException e) {
e.printStackTrace();
}
Myapplication.getApplication().closeApplication();
//完全退出Application
//如果使用如下方法退出程序,将会发生日志打印三次的BUG
//android.os.Process.killProcess(android.os.Process.myPid());
//System.exit(1);
}
}private boolean handleException(Throwable arg1) {
String logPath;
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
logPath = Environment.getExternalStorageDirectory()
.getAbsolutePath()
+ File.separator
+ File.separator
+ "log";
File file = new File(logPath);
if (!file.exists()) {
file.mkdirs();
}
try {
FileWriter fw = new FileWriter(logPath + File.separator
+ CommonUtil.getStrTime() + ".log", false);
StringBuffer sb = new StringBuffer();
sb.append("/*************************************************/\n");
sb.append(new Date() + "\n");
// 错误信息
// 这里还可以加上当前的系统版本,机型型号 等等信息
StackTraceElement[] stackTrace = arg1.getStackTrace();
sb.append("错误信息:" + arg1.getMessage() + "\n");
for (int i = 0;
i < stackTrace.length;
i++) {
String info = "文件:" + stackTrace[i].getFileName() + "类:"
+ stackTrace[i].getClassName() + "方法:"
+ stackTrace[i].getMethodName() + "行号:"
+ stackTrace[i].getLineNumber() + "\n";
sb.append(info);
}
sb.append("/*************************************************/\n");
fw.write(sb.toString());
fw.close();
// 上传错误信息到服务器
uploadToServer(sb);
} catch (IOException e) {
Log.e("crash handler", "load file failed...", e.getCause());
}
}
return true;
}private void uploadToServer(StringBuffer sb) {
//执行上传操作,错误信息为:sb.toString();
}}
- Handler的初始化以及MyApplication的编写:MyApplication.java
public class Myapplication extends Application {
private List activitys = new LinkedList();
private List services = new LinkedList();
private static int mTid;
private static Myapplication mApplication;
private CrashHandler crashHandler;
@Override
public void onCreate() {
super.onCreate();
mApplication = this;
mTid = android.os.Process.myTid();
crashHandler = CrashHandler.getInstance();
crashHandler.init(getApplicationContext());
}/**
*
* TODO 获取活动队列
*/
public List getActivitys() {
return activitys;
}/**
*
* TODO 添加Activity
*/
public void addActivity(Activity activity) {
activitys.add(activity);
}/**
*
* TODO 移除Activity
*/
public void removeActivity(Activity activity) {
activitys.remove(activity);
}/**
*
* TODO 添加服务
*/
public void addService(Service service) {
services.add(service);
}/**
*
* TODO 移除Service
*/
public void removeService(Service service) {
services.remove(service);
}/**
*
* TODO 关闭程序
*/
public void closeApplication() {
closeActivitys();
closeServices();
android.os.Process.killProcess(android.os.Process.myPid());
}/**
*
* TODO 关闭所有的Activity
*/
public void closeActivitys() {
ListIterator iterator = activitys.listIterator();
while (iterator.hasNext()) {
Activity activity = iterator.next();
if (activity != null) {
activity.finish();
}
}
}/**
*
* TODO 关闭所有的Service
*/
private void closeServices() {
ListIterator iterator = services.listIterator();
while (iterator.hasNext()) {
Service service = iterator.next();
if (service != null) {
stopService(new Intent(this, service.getClass()));
}
}
}/**
*
* TODO 获取Application
*/
public static Myapplication getApplication() {
return mApplication;
}/**
*
* TODO 获取主线程PID
*/
public static int getmTid() {
return mTid;
}}
- BaseActivity的编写:BaseActivity.java
public class BaseActivity extends Activity {
protected BaseActivity mActivity;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 保存生命周期的完整性
((Myapplication) getApplication()).addActivity(this);
mActivity = this;
}@Override
protected void onDestroy() {
super.onDestroy();
((Myapplication) getApplication()).removeActivity(this);
}
}
总结 以上代码仅供参考,可能有更好的解决方法,欢迎大家给我留言。本人Android菜鸟一枚,并非大牛,可能部分代码不尽如人意,希望各位大大可以予以指出,我会虚心接受并积极改正,谢谢大家!