Xamarin.Android-捕获未处理异常(全局异常)
一、前言
android中如果出现了未处理的异常,程序会闪退,这是非常不好的用户体验,很多用户会因此卸载APP,因此未处理的异常是应该尽力避免的。
有些很难避免的异常(如:IO、网络等),应在代码中进行捕捉并做相应的处理,以阻止程序崩溃闪退。
但是“没有任何程序是完美的”,况且各式各样的android终端也大大增加了异常的出现概率,就连强大的QQ、微信等不也会闪退嘛!
这时就需要全局捕获未处理的异常,并进行处理。(注意:本文中的处理方式并不能阻止APP闪退)
处理方式:收集异常信息、当前场景[时间、硬件参数],在合适的时机上传至服务端
作用:1、便于下一版本修复bug 2、便于帮助用户解决异常造成的困难
二、参照java android的方式(这是坑啊)
xamarin.android在很多时候都可以参考java android的代码,因此我按照java android的方式实现了一下“捕获未处理异常”
[Obsolete] public class CrashHandler:Thread.IUncaughtExceptionHandler { //系统默认的UncaughtException处理类 private Thread.IUncaughtExceptionHandler mDefaultHandler; //CrashHandler实例 private static CrashHandler INSTANCE = new CrashHandler(); //程序的Context对象 private Context mContext; /// <summary> /// 保证只有一个CrashHandler实例 /// </summary> private CrashHandler() { } /// <summary> /// 获取CrashHandler实例 ,单例模式 /// </summary> /// <returns></returns> public static CrashHandler GetInstance() { return INSTANCE; } public IntPtr Handle { get { return Thread.CurrentThread().Handle; } } public void Dispose() { this.Dispose(); } /// <summary> /// 初始化 /// </summary> /// <param name="context"></param> public void Init(Context context) { mContext = context; //获取系统默认的UncaughtException处理器 mDefaultHandler = Thread.DefaultUncaughtExceptionHandler; //设置该CrashHandler为程序的默认处理器 Thread.DefaultUncaughtExceptionHandler = this; } ///当UncaughtException发生时会转入该函数来处理 public void UncaughtException(Thread thread, Throwable ex) { if (!HandleException(ex) && mDefaultHandler != null) { //如果用户没有处理则让系统默认的异常处理器来处理 mDefaultHandler.UncaughtException(thread, ex); } else { //退出程序 Android.OS.Process.KillProcess(Android.OS.Process.MyPid()); JavaSystem.Exit(1); } } /// <summary> /// 异常处理 /// </summary> /// <param name="ex"></param> /// <returns>如果处理了该异常信息返回true; 否则返回false.</returns> private bool HandleException(Throwable ex) { if (ex == null) { return false; } //处理程序(记录 异常、设备信息、时间等重要信息) //************ //提示 Task.Run(() => { Looper.Prepare(); //可以换成更友好的提示 Toast.MakeText(mContext, "很抱歉,程序出现异常,即将退出.", ToastLength.Long).Show(); Looper.Loop(); }); //停一会,让前面的操作做完 System.Threading.Thread.Sleep(2000); return true; } }
[Application(Label = "MyApplication")] public class MyApplication : Application { public MyApplication(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer) { } public override void OnCreate() { base.OnCreate(); CrashHandler crashHandler = CrashHandler.GetInstance(); crashHandler.Init(ApplicationContext); } }
通过实现Java.Lang.Thread.IUncaughtExceptionHandler接口自定义一个异常处理类CrashHandler,并替换掉Java.Lang.Thread.DefaultUncaughtExceptionHandler,
当UncaughtException发生时会转入CrashHandler类中的UncaughtException方法中,在此处进行异常处理。
然后制造一个异常throw new Exception("我是异常!");,本以为程序会进入CrashHandler类中的UncaughtException方法中,结果却不是,也就是说这种方式失败了,为什么? google后发现,IUncaughtExceptionHandler只能捕获到Dalvik runtime的异常,mono runtime中的C#异常,这个不起作用。
因此这种方式不行,坑坑坑!
三、正确的捕捉方式
[Application(Label = "MyApplication")] public class MyApplication : Application { public MyApplication(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer) { } public override void OnCreate() { base.OnCreate(); //注册未处理异常事件 AndroidEnvironment.UnhandledExceptionRaiser += AndroidEnvironment_UnhandledExceptionRaiser; //CrashHandler crashHandler = CrashHandler.GetInstance(); //crashHandler.Init(ApplicationContext); } protected override void Dispose(bool disposing) { AndroidEnvironment.UnhandledExceptionRaiser -= AndroidEnvironment_UnhandledExceptionRaiser; base.Dispose(disposing); } void AndroidEnvironment_UnhandledExceptionRaiser(object sender, RaiseThrowableEventArgs e) { UnhandledExceptionHandler(e.Exception, e); } /// <summary> /// 处理未处理异常 /// </summary> /// <param name="e"></param> private void UnhandledExceptionHandler(Exception ex, RaiseThrowableEventArgs e) { //处理程序(记录 异常、设备信息、时间等重要信息) //************** //提示 Task.Run(() => { Looper.Prepare(); //可以换成更友好的提示 Toast.MakeText(this, "很抱歉,程序出现异常,即将退出.", ToastLength.Long).Show(); Looper.Loop(); }); //停一会,让前面的操作做完 System.Threading.Thread.Sleep(2000); e.Handled = true; } }
注册未处理异常事件AndroidEnvironment.UnhandledExceptionRaiser += AndroidEnvironment_UnhandledExceptionRaiser; 在AndroidEnvironment_UnhandledExceptionRaiser中进行异常处理。
制造一个异常throw new Exception("我是异常!");,妥妥的进入了AndroidEnvironment_UnhandledExceptionRaiser,OK,成功!
说明:捕获异常后的具体处理,无非就是读取硬件信息、时间、异常信息,并保存至本地,在合适的时机上传至服务端,为了突出重点,我在这里就不实现了。
https://github.com/jordanqin/CatchException
参考:
http://forums.xamarin.com/discussion/4576/application-excepionhandler
http://blog.csdn.net/liuhe688/article/details/6584143
如果你觉得文章对你有帮助,可以点击旁边的“推荐”按钮,这样会让更多需要的人有机会看到