android总是会突然ANR,这涉及到很多原因。我们只能尽量减少ANR发生的情况,但是却没法完全解决掉。
Paste_Image.png
ANR的出现对用户的体验是非常差的,所以这里给出ANR的解决办法。
1.屏蔽ANR提示
2.自动启动APP
3.发送错误信息给服务器
实现过程如下:
实现异常处理接口:
public class MyCrashHandler implements Thread.UncaughtExceptionHandler
构造起单例模式:
private static MyCrashHandler myCrashHandler ;
private Thread.UncaughtExceptionHandler mDefaultHandler;
private Context context;
public static synchronized MyCrashHandler getInstance(){
if(myCrashHandler!=null){
return myCrashHandler;
}else {
myCrashHandler = new MyCrashHandler();
return myCrashHandler;
}
}
public void init(Context context){
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
this.context = context;
}
实现ANR重启
public void uncaughtException( final Thread thread, final Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
//如果用户没有处理则让系统默认的异常处理器来处理
mDefaultHandler.uncaughtException(thread, ex);
} else {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
// 干掉当前的程序
// android.os.Process.killProcess(android.os.Process.myPid());
// //退出程序
Intent intent = new Intent( BaseApplication.getInstance().getApplicationContext(), WelcomeActivity.class);
PendingIntent restartIntent = PendingIntent.getActivity(
BaseApplication.getInstance().getApplicationContext(), 0, intent,
Intent.FLAG_ACTIVITY_NEW_TASK);
//退出程序
AlarmManager mgr = (AlarmManager) BaseApplication.getInstance().getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000,
restartIntent); // 1秒钟后重启应用
BaseApplication.getInstance().finishActivity();
// System.exit(1);
}
最后是在重启前,发送错误报告
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}
ex.printStackTrace();
//使用Toast来显示异常信息
new Thread() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(context, "很抱歉,程序出现异常,即将重启.", Toast.LENGTH_LONG).show();
Looper.loop();
}
}.start();
System.out.println("程序挂掉了 ");
// 1.获取当前程序的版本号. 版本的id
String versioninfo = getVersionInfo();
// 2.获取手机的硬件信息.
String mobileInfo = getMobileInfo();
// 3.把错误的堆栈信息 获取出来
String errorinfo = getErrorInfo(ex);
Map<String, String> params = new HashMap<String, String>();
params.put("SERVICE_TYPE", Local.NET_ERROR);
params.put("LOGIN_TYPE", Local.TYPE_NAME+"=="+versioninfo+"=="+mobileInfo);
params.put("MESSAGE",errorinfo);
params.put("SCHOOLID", Local.self.centerid);
HttpUtil.post(params, new JsonHttpResponseHandler() {
@Override
public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) {
}
public void onSuccess(int statusCode, Header[] headers, JSONArray timeline) {
ProgressDialogUtils.dismissMyDialog();
System.out.println(timeline.toString());
}
});
System.out.println("信息发送了 ");
return true;
}
如何调用?
在Application中
MyCrashHandler handler = MyCrashHandler.getInstance();
handler.init(getApplicationContext());
Thread.setDefaultUncaughtExceptionHandler(handler);
另外一些辅助性的代码
/**
* 获取错误的信息
* @param arg1
* @return
*/
private String getErrorInfo(Throwable arg1) {
Writer writer = new StringWriter();
PrintWriter pw = new PrintWriter(writer);
arg1.printStackTrace(pw);
pw.close();
String error= writer.toString();
return error;
}
/**
* 获取手机的硬件信息
* @return
*/
private String getMobileInfo() {
StringBuffer sb = new StringBuffer();
//通过反射获取系统的硬件信息
try {
Field[] fields = Build.class.getDeclaredFields();
for(Field field: fields){
//暴力反射 ,获取私有的信息
field.setAccessible(true);
String name = field.getName();
String value = field.get(null).toString();
sb.append(name+"="+value);
sb.append("\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
/**
* 获取手机的版本信息
* @return
*/
private String getVersionInfo(){
try {
PackageManager pm = context.getPackageManager();
PackageInfo info =pm.getPackageInfo(context.getPackageName(), 0);
return info.versionName;
} catch (Exception e) {
e.printStackTrace();
return "版本号未知";
}
}