Android 全局异常捕获和bugly共用 并重启应用

25 篇文章 0 订阅
10 篇文章 0 订阅
**
 * 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());

        if(BuildConfig.DEBUG){
            CrashReport.initCrashReport(getApplicationContext(), "77315xxb", true);
        }else{
            CrashReport.initCrashReport(getApplicationContext(), "773zzzzccb", false);
        }

        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());

 



import android.annotation.SuppressLint;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Environment;
import android.util.Log;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * 捕捉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;
	}

}

build.gradle 添加bugly

implementation 'com.tencent.bugly:crashreport:3.1.9'

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
Android应用中,可以通过全局捕获异常来避免应用闪退。可以通过以下步骤实现: 1. 创建一个自定义的Application类,并在其中重写`Thread.UncaughtExceptionHandler`接口的`uncaughtException`方法。 2. 在`uncaughtException`方法中处理全局异常,例如记录异常信息、上传日志或者进行其他处理操作。 3. 在Application的onCreate方法中,将自定义的UncaughtExceptionHandler设置为默认的异常处理器。 下面是一个示例代码: ```java public class MyApplication extends Application implements Thread.UncaughtExceptionHandler { @Override public void onCreate() { super.onCreate(); // 设置全局异常处理器 Thread.setDefaultUncaughtExceptionHandler(this); } @Override public void uncaughtException(Thread thread, Throwable ex) { // 处理全局异常,例如记录异常信息、上传日志等操作 Log.e("MyApplication", "Uncaught Exception: " + ex.getMessage()); // 重启应用或者执行其他操作 restartApp(); } private void restartApp() { // 重启应用,可以根据实际需求来实现 Intent intent = new Intent(getApplicationContext(), MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_ONE_SHOT); AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); alarmManager.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, pendingIntent); // 退出应用 System.exit(0); } } ``` 记得在AndroidManifest.xml文件中将自定义的Application类配置为应用的默认Application类: ```xml <application android:name=".MyApplication" ...> ... </application> ``` 通过以上步骤,当应用发生未捕获异常时,会调用自定义的异常处理方法,你可以在其中进行相应的处理操作,例如记录异常信息、上传日志等。最后,你可以选择重启应用或者执行其他操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值