APP全局異常捕獲和重啓APP

   


**
 * 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章