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;
}
}
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

 

如果你覺得文章對你有幫助,可以點擊旁邊的“推薦”按鈕,這樣會讓更多需要的人有機會看到


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com