package com.arialyy.frame.core;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Looper;
import android.text.TextUtils;
import com.arialyy.frame.http.HttpUtil;
import com.arialyy.frame.permission.PermissionManager;
import com.arialyy.frame.util.AndroidUtils;
import com.arialyy.frame.util.CalendarUtils;
import com.arialyy.frame.util.FileUtil;
import com.arialyy.frame.util.NetUtils;
import com.arialyy.frame.util.show.FL;
import com.arialyy.frame.util.show.L;
import com.arialyy.frame.util.show.T;
import com.google.gson.Gson;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.Map;
import java.util.WeakHashMap;
/**
* Created by lyy on 2016/4/21.
* 异常捕获
*/
final class CrashHandler implements Thread.UncaughtExceptionHandler {
private static final Object LOCK = new Object();
private static volatile CrashHandler INSTANCE = null;
private static final String TAG = "CrashHandler";
private Thread.UncaughtExceptionHandler mDefaultHandler;
private Context mContext;
private String mServerHost, mPramKey;
private String mExceptionFileName = "AbsExceptionFile.crash";
/**
* 获取CrashHandler实例 ,单例模式
*/
public static CrashHandler getInstance(Context context) {
if (INSTANCE == null) {
synchronized (LOCK) {
INSTANCE = new CrashHandler(context);
}
}
return INSTANCE;
}
private CrashHandler(Context context) {
mContext = context;
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
}
/**
* 开启异常捕获
* 需要网络权限,get请求,异常参数
*
* @param serverHost 服务器地址
* @param key 数据传输键值
*/
public void setServerHost(String serverHost, String key) {
mServerHost = serverHost;
mPramKey = key;
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
mDefaultHandler.uncaughtException(thread, ex);
} else {
// Sleep一会后结束程序
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//不要把线程都杀了,否则连日志都看不了
// android.os.Process.killProcess(android.os.Process.myPid());
//如果把这句话注释掉,有异常都不会退出
System.exit(10);
}
}
/**
* 处理捕获到的异常
*
* @param ex
* @return
*/
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}
//在这里处理崩溃逻辑,将不再显示FC对话框
new Thread() {
@Override
public void run() {
Looper.prepare();
T.showLong(mContext, "很抱歉,程序出现异常,即将退出");
Looper.loop();
}
}.start();
sendExceptionInfo(ex);
return true;
}
/**
* 发送异常数据给服务器
*
* @param ex
*/
private void sendExceptionInfo(final Throwable ex) {
ExceptionInfo info = new ExceptionInfo();
info.time = CalendarUtils.getNowDataTime();
info.versionCode = AndroidUtils.getVersionCode(mContext);
info.versionName = AndroidUtils.getVersionName(mContext);
info.systemVersionCode = Build.VERSION.SDK_INT;
info.phoneModel = Build.MODEL;
info.exceptionMsg = FL.getExceptionString(ex);
if (AndroidUtils.checkPermission(mContext, Manifest.permission.INTERNET) &&
AndroidUtils.checkPermission(mContext, Manifest.permission.ACCESS_NETWORK_STATE)) {
if (NetUtils.isConnected(mContext) && !TextUtils.isEmpty(mServerHost) && !TextUtils.isEmpty(mPramKey)) {
String objStr = new Gson().toJson(info);
HttpUtil util = HttpUtil.getInstance(mContext);
Map<String, String> params = new WeakHashMap<>();
params.put(mPramKey, objStr);
util.get(mServerHost, params, new HttpUtil.AbsResponse());
}
} else {
L.e(TAG, "请在manifest文件定义android.permission.INTERNET和android.permission.ACCESS_NETWORK_STATE权限");
return;
}
File file = new File(mContext.getCacheDir().getPath() + "/crash/" + mExceptionFileName);
if (!file.exists()) {
FileUtil.createFile(file.getPath());
}
writeExceptionToFile(info.exceptionMsg, file);
}
/**
* 将异常日志写入文件
*/
private void writeExceptionToFile(String message, File crashFile) {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(CalendarUtils.getNowDataTime());
stringBuffer.append("\n");
stringBuffer.append(message);
stringBuffer.append("\n");
PrintWriter writer = null;
try {
writer = new PrintWriter(new FileWriter(crashFile, true));
writer.append(stringBuffer);
writer.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (writer != null) {
writer.close();
}
}
}
private class ExceptionInfo {
int versionCode;
String versionName;
int systemVersionCode;
String exceptionMsg;
String phoneModel;
String time;
}
}