**
* author: Created by lsw on 2018/6/8 11:25
* description:
*/
public class MYApplication extends Application {
private static MYApplication app;
public static SysCfgInfo config = new SysCfgInfo();
private long onTouchTime;
@Override
public void onCreate() {
super.onCreate();
app = this;
BugHandler.getInstance().init(this,null,null);
Thread.setDefaultUncaughtExceptionHandler(BugHandler.getInstance());
CrashReport.initCrashReport(getApplicationContext(), "665fa6736b", true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
}
}
public static MYApplication getApp() {
return app;
}
public void setTouchTime(long time){
LogUtil.e( time +" 點擊屏幕時間 --- " );
this.onTouchTime = time;
}
public long getOnTouchTime() {
return onTouchTime;
}
}
APP 中設置全局捕獲異常
捕獲異常利用 定時器 並重啓應用
Intent intent = new Intent(context, MainActivity.class);
PendingIntent restartIntent = PendingIntent.getActivity(
context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
//退出程序
AlarmManager mgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
// mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000,
// restartIntent); // 1秒鐘後重啓應用
android.os.Process.killProcess(android.os.Process.myPid());
**
* 捕捉bug,並寫入日誌文件 自定義的 異常處理類 , 實現了 UncaughtExceptionHandler接口
*
* @author lsw
* @date 2014-3-31
*/
@SuppressLint("SimpleDateFormat")
public class BugHandler implements UncaughtExceptionHandler {
private final String TAG = "BugHandler";
// 需求是 整個應用程序 只有一個 MyCrash-Handler
private static BugHandler myCrashHandler;
private Context context;
private SimpleDateFormat dateFormat = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
private String path;
private String url;
// 1.私有化構造方法
private BugHandler() {
}
public static synchronized BugHandler getInstance() {
if (myCrashHandler != null) {
return myCrashHandler;
} else {
myCrashHandler = new BugHandler();
return myCrashHandler;
}
}
/**
*
* @param context
* @param path
* 生成日誌文件的本地路徑,默認在應用名稱底下創建log文件夾,所有日誌放在改文件夾
* @param url
* 日誌發送到服務器的url
*/
public void init(Context context, String path, String url) {
this.context = context;
this.path = path;
this.url = url;
}
@Override
public void uncaughtException(Thread thread, Throwable throwable) {
// 3.把錯誤的堆棧信息 獲取出來
String errorinfo = getErrorInfo(throwable);
// outputFile(errorinfo);
// outputFile(errorinfo,"/tmp");//將文件存放到臨時目錄下
// LogUtil.e(errorinfo);
//TODO 異常之後重啓應用
Intent intent = new Intent(context, MainActivity.class);
PendingIntent restartIntent = PendingIntent.getActivity(
context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
//退出程序
AlarmManager mgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
// mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000,
// restartIntent); // 1秒鐘後重啓應用
android.os.Process.killProcess(android.os.Process.myPid());
}
public void outputFile(String errorinfo) {
// 1.獲取當前程序的版本號. 版本的id
String versioninfo = "app VERSION: " + getVersionInfo();
// 2.獲取手機的硬件信息.
String mobileInfo = getMobileInfo();
String date = dateFormat.format(new Date());
// 4.創建日誌文件,寫入堆棧
File file = null;
File tmpFile = null;//寫入臨時文件夾
if (path == null) {
String dir = getDirPath();
File parentFile = new File(dir);
if (!parentFile.exists()) {
parentFile.mkdirs();
}
String dateStr = date.replace(":", "").replace(" ", "T");
String fileName = android.os.Build.MODEL + "(" + dateStr + ").log";
path = dir + File.separator + fileName;
file = new File(path);
LogUtil.e(file.getAbsolutePath()+" ===========");
//臨時文件部分
String dirtmp= getDirPath()+"/tmp";
File tmpParentFile = new File(dirtmp);
if (!tmpParentFile.exists()) {
tmpParentFile.mkdirs();
}
String tmpPath = dirtmp + File.separator + fileName;
tmpFile = new File(tmpPath);
//////////////////////////////////////////////
}
FileOutputStream fos = null;
try {
String newline = System.getProperty("line.separator"); // 換行符
fos = new FileOutputStream(file);
fos.write(date.getBytes());
fos.write(newline.getBytes());
fos.write(versioninfo.toString().getBytes());
fos.write(newline.getBytes());
fos.write(mobileInfo.getBytes());
fos.write("==================================================="
.getBytes());
fos.write(newline.getBytes());
fos.write(errorinfo.getBytes());
fos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
fos = null;
}
}
//拷貝日誌文件到臨時文件目錄下
try {
copyFile(file,tmpFile);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.e(TAG, errorinfo);
Log.i(TAG, "日誌文件路徑:" + path);
exit();
// 幹掉當前的程序
// android.os.Process.killProcess(android.os.Process.myPid());
}
/**
* 複製文件
* @param sourceFile 源文件
* @param targetFile 目標文件
* @throws IOException
*/
public static void copyFile(File sourceFile, File targetFile) throws IOException {
BufferedInputStream inBuff = null;
BufferedOutputStream outBuff = null;
try {
// 新建文件輸入流並對它進行緩衝
inBuff = new BufferedInputStream(new FileInputStream(sourceFile));
// 新建文件輸出流並對它進行緩衝
outBuff = new BufferedOutputStream(new FileOutputStream(targetFile));
// 緩衝數組
byte[] b = new byte[1024 * 5];
int len;
while ((len = inBuff.read(b)) != -1) {
outBuff.write(b, 0, len);
}
sourceFile.delete();
// 刷新此緩衝的輸出流
outBuff.flush();
} finally {
// 關閉流
if (inBuff != null)
inBuff.close();
if (outBuff != null)
outBuff.close();
}
}
/**
* 獲取最後一個日誌文件的文本信息
*
* @param
*
*/
public String getTextFromLastFile() {
String text = null;
File file = getLastFile();
if (file != null) {
text = getTextFromFile(file);
}
return text;
}
/**
* 讀取文件裏的文本內容
*
* @param file
* @return
*/
public String getTextFromFile(File file) {
String text = null;
BufferedReader bf = null;
try {
StringBuilder builder = new StringBuilder();
InputStream in = new FileInputStream(file);
InputStreamReader reader = new InputStreamReader(in, "UTF-8");
bf = new BufferedReader(reader);
String line;
while ((line = bf.readLine()) != null) {
builder.append(line);
}
text = builder.toString();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return text;
}
/**
* 刪除文件夾下的創建時間比當前時間大 day 天的文件
* @param day
* @return
*/
public void deleteFilesMoreThenDay(int day) {
String path = getDirPath();
File file = new File(path);
File[] files = file.listFiles();
if (files != null) {
for (File f : files) {
Long time =f.lastModified();
Calendar cd = Calendar.getInstance();
String newDate=cd.getTime().toLocaleString();//系統當前時間
cd.setTimeInMillis(time);
String oldDate=cd.getTime().toLocaleString();//文件創建時間
int length=dateDistance(newDate,oldDate);//相差多少天
if (length>=day&&!f.isDirectory()) {
f.delete();
}
}
}
}
/**
* 計算兩個日期直接相差多少天
* @param oldDate 第一個日期
* @param newDate 第二個日期
* @return
* 相差天數
*/
public int dateDistance(String newDate,String oldDate)
{
int day=0;
SimpleDateFormat myFormatter = new SimpleDateFormat( "yyyy-MM-dd ");
java.util.Date date;
try {
date = myFormatter.parse(newDate);
java.util.Date mydate= myFormatter.parse(oldDate);
day=(int) ((date.getTime()-mydate.getTime())/(24*60*60*1000));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return day;
}
/**
* 刪除日誌文件夾下的所有日誌,全部刪除成功返回true
* @param extraPath 文件夾名稱 參數格式 "/tmp"
* @return
*/
public boolean deleteFiles(String extraPath) {
boolean isSuccess = true;
String path = getDirPath()+extraPath;
File file = new File(path);
File[] files = file.listFiles();
if (files != null) {
for (File f : files) {
if (!f.delete()) {
isSuccess = false;
}
}
}
return isSuccess;
}
/**
* 刪除日誌文件夾下的所有日誌,全部刪除成功返回true
*/
public boolean deleteFiles() {
boolean isSuccess = true;
String path = getDirPath();
File file = new File(path);
File[] files = file.listFiles();
if (files != null) {
for (File f : files) {
if (!f.delete()) {
isSuccess = false;
}
}
}
return isSuccess;
}
/**
* 獲取日誌文件夾下最後一個文件,該文件夾下沒有日誌文件返回null
*
* @return
*/
private File getLastFile() {
// String dir = getDirPath();
String dir = getDirPath()+"/tmp";//現在獲取tmp文件夾裏面的最後一個文件
File file = new File(dir);
File[] files = file.listFiles();
if (files != null) {
int len = files.length;
if (len > 0) {
File f = files[len - 1];
return f;
}
}
return null;
}
public void sendLogToService() {
if (url == null)
return;
new AlertDialog.Builder(context).setMessage("程序崩潰,是否發送日誌到服務器?")
.setTitle("提示")
.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// 發送日誌文件到服務器
// FileUploader.uploadFile("filedata", path, url);
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
}).show();
}
/**
* 獲取錯誤的信息
*
* @param arg1
* @return
*/
public 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
*/
public String getMobileInfo() {
StringBuffer sb = new StringBuffer();
sb.append("phone VERSION.SDK=" + Build.VERSION.SDK_INT);
sb.append("\n");
sb.append("phone VERSION.RELEASE=" + Build.VERSION.RELEASE);
sb.append("\n");
// 通過反射獲取系統的硬件信息
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
*/
public String getVersionInfo() {
try {
PackageManager pm = context.getPackageManager();
PackageInfo info = pm.getPackageInfo(context.getPackageName(), 0);
return info.versionName;
} catch (Exception e) {
e.printStackTrace();
return "版本號未知";
}
}
/**
* 獲取日誌文件的根目錄
*
* @return
*/
public String getDirPath() {
String path = null;
// TODO 路徑爲 sdcard/包名/log
// String name = getApplicationName();
String name = context.getPackageName();
// if (Environment.getExternalStorageState().equals(
// Environment.MEDIA_MOUNTED)) {// 優先保存到SD卡中
String mainPaths = Environment.getExternalStorageDirectory().getPath();
path = mainPaths + SysCfgInfo.ROOTPATH + "/log" ;
// BaseApplication app = (BaseApplication) context.getApplicationContext();
// path = app.getSdCardPath() + File.separator + name + File.separator
// + "log";
// } else {// 如果SD卡不存在,就保存到本應用的目錄下
// path = context.getFilesDir().getAbsolutePath() + File.separator
// + name + File.separator + "log";
// }
return path;
}
private void exit() {
if(context != null)
{
// BaseApplication app = (BaseApplication) context.getApplicationContext();
// if(app != null)
// {
// app.exit();
// }
}
}
/**
* 獲取應用名稱
*
* @return
*/
public String getApplicationName() {
PackageManager pm = null;
ApplicationInfo info = null;
try {
pm = context.getApplicationContext().getPackageManager();
info = pm.getApplicationInfo(context.getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
info = null;
}
String name = (String) pm.getApplicationLabel(info);
return name;
}
by .k
關注"編程v",每一天漲一點
STAY HUNGRY & STAY FOOLISH