Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 554|回复: 0

Xamarin.Android-捕获未处理异常(全局异常)

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-7-11 13:31:55 | 显示全部楼层 |阅读模式

    一、前言

    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;
            }
        }
    View Code
    [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);
            }
    
        }
    View Code

    通过实现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;
            }
        }
    View Code

    注册未处理异常事件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

     

    如果你觉得文章对你有帮助,可以点击旁边的“推荐”按钮,这样会让更多需要的人有机会看到

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-20 15:18 , Processed in 0.069115 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表