GVKun编程网logo

利用UncaughtExceptionHandler捕获未try...catch到的异常(用于捕获异常的java语句是)

19

此处将为大家介绍关于利用UncaughtExceptionHandler捕获未try...catch到的异常的详细内容,并且为您解答有关用于捕获异常的java语句是的相关问题,此外,我们还将为您介绍关

此处将为大家介绍关于利用UncaughtExceptionHandler捕获未try...catch到的异常的详细内容,并且为您解答有关用于捕获异常的java语句是的相关问题,此外,我们还将为您介绍关于Android UncaughtExceptionHandler 全局异常监控、Android UncaughtExceptionHandler实例化AlertDialog中断、android – setDefaultUncaughtExceptionHandler使应用程序静默崩溃、android – 从Thread.UncaughtExceptionHandler启动服务?的有用信息。

本文目录一览:

利用UncaughtExceptionHandler捕获未try...catch到的异常(用于捕获异常的java语句是)

利用UncaughtExceptionHandler捕获未try...catch到的异常(用于捕获异常的java语句是)

public class test {

public static void main(String[] args){
Thread thread = new Thread(new MyThread());
thread.setUncaughtExceptionHandler((Thread t,Throwable e)->{
System.out.println("出现异常");
System.out.println("线程名称:" + t.getName());
System.out.println("异常信息:" + e.getClass().getName() +":"+ e.getMessage());
System.out.println("线程状态:" +t.getState());
});
thread.start();
System.out.println("哈哈哈哈");

}
}

class MyThread implements Runnable{
@Override
public void run() {
System.out.println("啦啦啦啦啦啦啦啦啦啦");
System.out.println(1/0); //制造异常
System.out.println("啦啦啦啦啦啦啦啦啦啦");
}
}


运行main,控制台显示如图:

 

Android UncaughtExceptionHandler 全局异常监控

Android UncaughtExceptionHandler 全局异常监控

一、全局捕获异常

为了解决这样的问题,我们需要能够及时的捕获异常,但要捕获的地方是在太多,因此,我们需要进行全局性的异常捕获,那么如何捕获全局异常呢?

答案是UncaughtExceptionHandler+Thread.setDefaultUncaughtExceptionHandler

 

1.UncaughtExceptionHandler是未捕获异常的处理接口,该类率先捕获异常

 UncaughtExceptionHandler: 线程未捕获异常控制器是用来处理未捕获异常的。  
                            如果程序出现了未捕获异常默认情况下则会出现强行关闭对话框 
                            实现该接口并注册为程序中的默认未捕获异常处理  
                            这样当未捕获异常发生时,就可以做些异常处理操作 
                            例如:收集异常信息,发送错误报告 等。

二、代码实战

对于这个接口,我们需要进行实现

public class AppCrashHandler implements UncaughtExceptionHandler {
	
	private Context mContext;

    private Thread.UncaughtExceptionHandler mDefaultHandler;
    /**防止多线程中的异常导致读写不同步问题的lock**/
    private Lock lock = null;
	/**本地保存文件日志**/
	private final String CRASH_REPORTER_EXTENSION = ".crash";
    /**日志tag**/
    private final String STACK_TRACE = "logStackTrance";
    /**保存文件名**/
    private final String crash_pref_path ="app_crash_pref.xml";
	
    private static final String OOM = "java.lang.OutOfMemoryError";
    
    private static final String HPROF_FILE_PATH = Environment.getExternalStorageDirectory().getPath() + "/data_crash.hprof"
    
    private AppCrashHandler()
    {
        lock = new ReentrantLock(true);
    }
    /**
     * 获得单例对象
     * @param context
     * @return AppCrashHandler
     */
	public static AppCrashHandler shareInstance(Context context){
		 AppCrashHandler crashhandler = AppCrashHandler.InstanceHolder.crashHandler;
		 crashhandler.initCrashHandler(context);
		 return crashhandler;
	}
	/**
	 * 使用初始化方法初始化,防止提前初始化或者重复初始化
	 * @param cxt
	 */
	private void initCrashHandler(Context cxt)
	{
		if(!hasInitilized()){
			mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
			Thread.setDefaultUncaughtExceptionHandler(this);
			mContext = cxt; 
		}
		
	}
	
	public interface InstanceHolder
	{
		public static AppCrashHandler crashHandler = new AppCrashHandler();
	}
	
    public static boolean isOOM(Throwable throwable){  
        Log.d(TAG, "getName:" + throwable.getClass().getName());  
        if(OOM.equals(throwable.getClass().getName())){  
            return true;  
        }else{  
            Throwable cause = throwable.getCause();  
            if(cause != null){  
                return isOOM(cause);  
            }  
            return false;  
        }  
    }  
	@Override
	public void uncaughtException(Thread thread, Throwable ex) {
		
		if(isOOM(throwable)){  
                try {  
                    Debug.dumpHprofData(HPROF_FILE_PATH);
                    } catch (Exception e) {  
                        Log.e(TAG, "couldn’t dump hprof", e);  
                    }  
                }  
		 if (!handleExceptionMessage(ex) && mDefaultHandler != null) {  
	            // 如果用户没有处理则让系统默认的异常处理器来处理  
	            mDefaultHandler.uncaughtException(thread, ex);  
	        } else {  
	            try {  
	                Thread.sleep(3000);  
	            } catch (InterruptedException e) {  
	                Log.e(STACK_TRACE, "Error : ", e);  
	            }  
	            android.os.Process.killProcess(android.os.Process.myPid());  
	            System.exit(10);  
	     }  
	}

	/** 
     * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. 开发者可以根据自己的情况来自定义异常处理逻辑 
     * @param ex 
     * @return true:如果处理了该异常信息;否则返回false 
     */  
    private boolean handleExceptionMessage(Throwable ex) 
    {  
        if (ex == null) 
        {  
            return false;  
        }  
        // 使用Toast来显示异常信息  
        new Thread() {  
            @Override  
            public void run() {  
                // Toast 显示需要出现在一个线程的消息队列中  
                Looper.prepare();  
                Toast.makeText(mContext, "程序出错啦,即将退出", Toast.LENGTH_LONG).show();  
                Looper.loop();  
            }  
        }.start();  
        
        String fileName = mContext.getPackageName()+"-"+"appCrash-Exception"+ CRASH_REPORTER_EXTENSION;  
        String crashFileName = saveExceptionToFile(ex,fileName); 
        
		SharedPreferences.Editor editor = mContext.getSharedPreferences(crash_pref_path , Context.MODE_PRIVATE).edit();
		editor.putString(STACK_TRACE, crashFileName);
		editor.commit();
		
		Log.d(STACK_TRACE, "errorLogPath="+crashFileName);
        
        return true;  
    }  

    /**
     * 是否已初始化
     * @return
     */
    public boolean hasInitilized()
    {
    	return mContext!=null;
    }
    /** 
     * 保存错误信息到文件中 
     * @param ex 
     * @return 
     * @throws IOException 
     */  
	private String saveExceptionToFile(Throwable ex,String fileName) 
	{  
		File saveFile = null;
		PrintWriter printWriter = null;  
            try {
            	
            	lock.tryLock();
		if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
		{
			File sdCardDir = Environment.getExternalStorageDirectory();//获取SDCard目录
			saveFile = new File(sdCardDir, fileName);
				    
		}else{
			 saveFile =new File(mContext.getFilesDir(),fileName);
		}
				
				if(!saveFile.exists())
			    {
			    	saveFile.createNewFile();
			    }
			    printWriter = new PrintWriter(saveFile);
			    String result = formatException(ex);
			    printWriter.write(result);
			    printWriter.flush();
				Log.e("CrashException", result);
            }catch(Exception e){
				e.printStackTrace();
			} finally{
				if(printWriter!=null)
				{
					printWriter.close();
				}
				lock.unlock();
			}
           
            return saveFile!=null?saveFile.getAbsolutePath():null;  
    }  
    /**
     * 格式化异常信息
     * @param e
     * @return
     */
    @SuppressLint("SimpleDateFormat")
	private  String  formatException(Throwable e)
	{
    	StringBuilder sb = new StringBuilder();
		StackTraceElement[] stackTrace = e.getStackTrace();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		if (stackTrace!=null)
		{
			String  timeStramp =  sdf.format(new Date(System.currentTimeMillis()));
			String format = String.format("DateTime:%s\nExceptionName:%s\n\n",timeStramp,e.getLocalizedMessage());
			sb.append(format);
			for (int i = 0; i < stackTrace.length; i++) 
			{
				StackTraceElement traceElement = stackTrace[i];
				String 	fileName 	= traceElement.getFileName();
				int 	lineNumber 		= traceElement.getLineNumber();
				String 	methodName 	= traceElement.getMethodName();
				String 	className = traceElement.getClassName();
				sb.append(String.format("%s\t%s[%d].%s \n",className,fileName,lineNumber,methodName));
			}
			sb.append(String.format("\n%s",e.getMessage()));
			Writer stringWriter = new StringWriter();
			PrintWriter pw = new PrintWriter(stringWriter);
			e.printStackTrace(pw);
			pw.flush();
			pw.close();
			
			sb.append("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
			sb.append(stringWriter.toString());
		}
		return sb.toString();
	}
}

这里只保存了文件,一般来说,当app第二次启动时我们需要将该文件上传到网络,时间不是很充裕,这里上传暂时不贴代码了,时间充裕的话会及时补充,请保持关注吧

 

2.初始化,监听全局异常信息,这里需要继承Application,并替换系统默认的Application

public class BaseApplication extends Application 
{
	private  static BaseApplication instance = null;
	private AppCrashHandler appCrashHandler = null;
	
	@Override
	public void onCreate() {
		
		synchronized (this)
		{
			if(instance==null)
			{
				instance = this;
			}
			appCrashHandler =  AppCrashHandler.shareInstance(instance);
		}
		super.onCreate();
		
	}
	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		super.onConfigurationChanged(newConfig);
	}
	
	
}

修改清单文件

<application
        android:name="com.hali.luya.unitest.BaseApplication "
        android:hardwareAccelerated="true"
        android:icon="@drawable/app_logo"
        android:logo="@drawable/app_logo"
        android:label="@string/app_name"
        android:configChanges="locale|keyboard|screenSize"
        android:theme="@style/Theme.AppBaseTheme" >
        
 <!--- ..这里省略一大堆代码.. ---->
 
 </Application>

 

三、腾讯Bugly

腾讯有一个bugly产品可以实现crash收集和处理,当然也可以同时使用UncaughtExceptionHandler,因为腾讯bugly虽然也实现了UncaughtExceptionHandler该回调,但腾讯bugly在捕获异常的同时也会调用你自己的UncaughtExceptionHandler。

 

目前腾讯的bugly不支持回调,但我申请到了腾讯的内测版支持回调。

public class BaseApplication extends Application 
{
	private  static Application instance = null;
	private AppCrashHandler appCrashHandler = null;
	private final String APP_CONTEXT_TAG = "appContext";
	
	@Override
	public void onCreate() {
		
		synchronized (this)
		{
			if(instance==null)
			{
				instance = this;
			}
			appCrashHandler =  AppCrashHandler.shareInstance(instance);
			
			UserStrategy strategy = new UserStrategy(instance); //App的策略Bean
			strategy.setAppChannel(getPackageName());     //设置渠道
			strategy.setAppVersion(getVersion());      //App的版本
			strategy.setAppReportDelay(1000);  //设置SDK处理延时,毫秒
			strategy.setDeviceID(GlobalUtil.getInstance().getDeviceID(instance));
			strategy.setCrashHandleCallback(new AppCrashHandleCallback());
			
			CrashReport.initCrashReport(instance, "900001335", true, strategy); //自定义策略生效,必须在初始化SDK前调用
			CrashReport. setUserId("BBDTEK");
			
		}
		//shutDownLog();
		super.onCreate();
	}
	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		super.onConfigurationChanged(newConfig);
	}
	
	/**
	 * 获取版本号
	 * @return 当前应用的版本号
	 */
	public String getVersion() {
	    try {
	        PackageManager manager = this.getPackageManager();
	        PackageInfo info = manager.getPackageInfo(this.getPackageName(), 0);
	        String version = info.versionName;
	        return this.getString(R.string.app_version) + version;
	    } catch (Exception e) {
	        e.printStackTrace();
	        return this.getString(R.string.app_version);
	    }
	}
	
	private class AppCrashHandleCallback extends CrashHandleCallback //bugly回调
	{
		@Override
		public synchronized Map<String, String> onCrashHandleStart(int crashType, String errorType, String errorMessage, String errorStack)
		{
			String crashTypeName = null;
			switch (crashType)
			{
				case CrashHandleCallback.CRASHTYPE_JAVA_CATCH:
					crashTypeName = "JAVA_CATCH";
					break;
				case CrashHandleCallback.CRASHTYPE_JAVA_CRASH:
					crashTypeName = "JAVA_CRASH";
					break;
				case CrashHandleCallback.CRASHTYPE_NATIVE:
					crashTypeName = "JAVA_NATIVE";
					break;
				case CrashHandleCallback.CRASHTYPE_U3D:
					crashTypeName = "JAVA_U3D";
					break;
				default:
				{
					crashTypeName = "unknown";
				}
			}

			Log.e(APP_CONTEXT_TAG, "Crash Happen Type:" + crashType + " TypeName:" + crashTypeName);
			Log.e(APP_CONTEXT_TAG, "errorType:" + errorType);
			Log.e(APP_CONTEXT_TAG, "errorMessage:" + errorMessage);
			Log.e(APP_CONTEXT_TAG, "errorStack:" + errorStack);

			Map<String, String> userDatas = super.onCrashHandleStart(crashType, errorType, errorMessage, errorStack);
			if (userDatas == null)
			{
				userDatas = new HashMap<String, String>();
			}
	      
	                userDatas.put("DEBUG", "TRUE");
			return userDatas;
		}
		
	}
	/**
	 * 关闭重要信息的日志
	 */
	private void shutDownLog()
	{
		LogUtils.allowE = false;
		LogUtils.allowI = false;
		LogUtils.allowV = false;
		LogUtils.allowW = false;
		LogUtils.allowWtf = false;
		LogUtils.allowD = false;
	}
}

 

 

 

try  doing it

Android UncaughtExceptionHandler实例化AlertDialog中断

Android UncaughtExceptionHandler实例化AlertDialog中断

正如标题所说,我在自定义应用程序类中设置了一个UncaughtExceptionHandler,它在我的应用程序启动时被设置为默认值.

但是,虽然我没有在文档中读过,但您无法使用MyApplication.this或getApplicationContext()实例化Dialog.当我尝试这样做时,我会得到一个

WindowManager$BadTokenException…

我需要另一种选择.我曾想过要做一个新活动来弥补这一点,但宁愿让它成为一个AlertDialog.

有没有办法从MyApplication类中获取UncaughtExceptionHandler的有效上下文?

解决方法:

I have read that you cannot instantiate a Dialog using MyApplication.this or getApplicationContext

正确. Application上下文对于构造UI并不是特别有用.

I have thought of making a new activity to compensate for this but would rather have it be an AlertDialog.

在这种情况下,AlertDialog是不可能的.对于初学者来说,只有一个活动可以打开一个对话框,并且你的所有活动都没有运行(例如,在后台服务中崩溃)和有效(例如,你有一个,但它是崩溃的那个).

编辑:修复前一段以消除混乱

android – setDefaultUncaughtExceptionHandler使应用程序静默崩溃

android – setDefaultUncaughtExceptionHandler使应用程序静默崩溃

CustomExceptionHandler

public class CustomExceptionHandler implements UncaughtExceptionHandler {

private Context ctx;
private ContentResolver cr;

public CustomExceptionHandler(Context ctx,ContentResolver cr) {
    this.ctx = ctx;
    this.cr = cr;
}

public void uncaughtException(Thread t,Throwable e) {

    final Writer result = new StringWriter();
    final PrintWriter printWriter = new PrintWriter(result);
    e.printstacktrace(printWriter);
    String stacktrace = result.toString();
    printWriter.close();


    String deviceUuid = Utilities.DeviceUuid(ctx,cr);
    String bluetoothName = Utilities.LocalBluetoothName();

    AsyncTasks.ErrorLogTask logTask = new AsyncTasks.ErrorLogTask(e,bluetoothName,deviceUuid,stacktrace);
    logTask.execute();
}




}

从我的主要活动中调用:

Thread.setDefaultUncaughtExceptionHandler(new CustomExceptionHandler(getBaseContext(),getContentResolver()));

当现在发生异常时,我不会得到常规的“不幸的是,已停止”弹出窗口.它只是一个黑屏.如果我从我的主要活动中删除我的调用,换句话说不再使用CustomExceptionHandler,我得到默认行为.

有没有办法在我的类中实现默认的错误行为?

提前致谢!

解决方法

您可以在异常处理程序的末尾添加以下内容以获取“遗憾的已停止”对话框:

System.exit(1);

但是,这将导致进程终止,这意味着您的AsyncTask将无法运行完成.

在任何情况下,如果你在uncaughtExceptionHandler中,我怀疑你的代码无论如何都会可靠地运行,因为你不知道应用程序的状态是什么.它可能会起作用,也可能不起作用.您还可以尝试在uncaughtExceptionHandler中创建一个新线程,让该线程休眠一会儿,然后使用System.exit()终止该应用程序.这可能会让您的AsyncTask有足够的时间运行完成.

android – 从Thread.UncaughtExceptionHandler启动服务?

android – 从Thread.UncaughtExceptionHandler启动服务?

我正在尝试设置 this answer中提到的全局异常处理服务.这种方法听起来合乎逻辑,因为在崩溃后,我的自定义 Thread.UncaughtExceptionHandler中的代码可能无法成功执行,因为应用程序可能不处于稳定状态或因为那里可能没有足够的时间在操作系统杀死进程之前.

不幸的是,这种方法似乎不起作用,因为服务在同一个过程中启动,所以它也被杀死了.如何从处理程序的uncaughtException()启动服务?我可以强制服务在完全独立的过程中启动吗?

我在Application中设置我的自定义默认(VM级别)异常处理程序,如下所示:

public class MyApp extends Application {    
    @Override
    public void onCreate() {
        Thread.setDefaultUncaughtExceptionHandler(
            MyExceptionReporter.getInstance(this));
        ...

在我的自定义处理程序中,我正在启动这样的服务:

final Intent i = new Intent(MyExceptionService.INTENT);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.putExtra(MyExceptionService.EXTRA_STACK_TRACE,Log.getStackTraceString(ex));
mContext.startService(i);

该服务在AndroidMaifest.xml文件中进行了解析,并从应用程序的其他位置启动.

解决方法

啊,我想出来了.关键是将android:process添加到清单,这会强制服务在单独的进程中启动.这可以防止服务在应用程序被杀死时被杀死.

<service
    android:name="your.package.blah.blah.MyExceptionService"
    android:process=":exception" >
    <intent-filter>
        <action android:name="your.package.blah.blah.REPORT" />
    </intent-filter>
    </service>

今天关于利用UncaughtExceptionHandler捕获未try...catch到的异常用于捕获异常的java语句是的讲解已经结束,谢谢您的阅读,如果想了解更多关于Android UncaughtExceptionHandler 全局异常监控、Android UncaughtExceptionHandler实例化AlertDialog中断、android – setDefaultUncaughtExceptionHandler使应用程序静默崩溃、android – 从Thread.UncaughtExceptionHandler启动服务?的相关知识,请在本站搜索。

本文标签: