手机APP开发 2017-01-13
转自:http://www.cnblogs.com/youngytj/p/4749004.html
异步(async)方法中的异常无法被App的UnhandledException捕获的问题
这是一个比较严重的问题.目前已知很多的做法就是局部try catch来解决这个问题.这样做是很容易导致Process被强制终止然后引起闪退的问题的.
我这里用了一个线程同步模型类解决这个问题.
using System; using System.Threading; using Windows.UI.Xaml.Controls; namespace AiJianShu.ExceptionHandler { internal class ExceptionHandlingSynchronizationContext : SynchronizationContext { /// <summary> /// 注册事件. 需要在OnLaunched和OnActivated事件中调用 /// </summary> /// <returns></returns> public static ExceptionHandlingSynchronizationContext Register() { var syncContext = Current; if (syncContext == null) throw new InvalidOperationException("Ensure a synchronization context exists before calling this method."); var customSynchronizationContext = syncContext as ExceptionHandlingSynchronizationContext; if (customSynchronizationContext == null) { customSynchronizationContext = new ExceptionHandlingSynchronizationContext(syncContext); SetSynchronizationContext(customSynchronizationContext); } return customSynchronizationContext; } /// <summary> /// 将线程的上下文绑定到特定的Frame上面 /// </summary> /// <param name="rootFrame"></param> /// <returns></returns> public static ExceptionHandlingSynchronizationContext RegisterForFrame(Frame rootFrame) { if (rootFrame == null) throw new ArgumentNullException("rootFrame"); var synchronizationContext = Register(); rootFrame.Navigating += (sender, args) => EnsureContext(synchronizationContext); rootFrame.Loaded += (sender, args) => EnsureContext(synchronizationContext); return synchronizationContext; } private static void EnsureContext(SynchronizationContext context) { if (Current != context) SetSynchronizationContext(context); } private readonly SynchronizationContext _syncContext; public ExceptionHandlingSynchronizationContext(SynchronizationContext syncContext) { _syncContext = syncContext; } public override SynchronizationContext CreateCopy() { return new ExceptionHandlingSynchronizationContext(_syncContext.CreateCopy()); } public override void OperationCompleted() { _syncContext.OperationCompleted(); } public override void OperationStarted() { _syncContext.OperationStarted(); } public override void Post(SendOrPostCallback d, object state) { _syncContext.Post(WrapCallback(d), state); } public override void Send(SendOrPostCallback d, object state) { _syncContext.Send(d, state); } private SendOrPostCallback WrapCallback(SendOrPostCallback sendOrPostCallback) { return state => { try { sendOrPostCallback(state); } catch (Exception ex) { if (!HandleException(ex)) throw; } }; } private bool HandleException(Exception exception) { if (UnhandledException == null) return false; var exWrapper = new AysncUnhandledExceptionEventArgs { Exception = exception }; UnhandledException(this, exWrapper); #if DEBUG && !DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION if (System.Diagnostics.Debugger.IsAttached) System.Diagnostics.Debugger.Break(); #endif return exWrapper.Handled; } public event EventHandler<AysncUnhandledExceptionEventArgs> UnhandledException; } public class AysncUnhandledExceptionEventArgs : EventArgs { public bool Handled { get; set; } public Exception Exception { get; set; } } }
使用实例:
public App() { this.InitializeComponent(); this.Suspending += OnSuspending; this.UnhandledException += App_UnhandledException; } private void RegisterExceptionHandlingSynchronizationContext() { ExceptionHandlingSynchronizationContext .Register() .UnhandledException += SynchronizationContext_UnhandledException; } private async void App_UnhandledException(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e) { e.Handled = true; await new MessageDialog("Application Unhandled Exception:\r\n" + e.Exception.Message) .ShowAsync(); } private async void SynchronizationContext_UnhandledException(object sender, AysncUnhandledExceptionEventArgs e) { e.Handled = true; await new MessageDialog("Synchronization Context Unhandled Exception:\r\n" + e.Exception.Message) .ShowAsync(); } protected override void OnLaunched(LaunchActivatedEventArgs e) { RegisterExceptionHandlingSynchronizationContext(); #if DEBUG if (System.Diagnostics.Debugger.IsAttached) { this.DebugSettings.EnableFrameRateCounter = true; } #endif Frame rootFrame = Window.Current.Content as Frame; // 不要在窗口已包含内容时重复应用程序初始化, // 只需确保窗口处于活动状态 if (rootFrame == null) { // 创建要充当导航上下文的框架,并导航到第一页 rootFrame = new Frame(); rootFrame.NavigationFailed += OnNavigationFailed; if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) { //TODO: 从之前挂起的应用程序加载状态 } // 将框架放在当前窗口中 Window.Current.Content = rootFrame; } if (rootFrame.Content == null) { // 当导航堆栈尚未还原时,导航到第一页, // 并通过将所需信息作为导航参数传入来配置 // 参数 rootFrame.Navigate(typeof(MainPage), e.Arguments); } // 确保当前窗口处于活动状态 Window.Current.Activate(); } protected override void OnActivated(IActivatedEventArgs args) { RegisterExceptionHandlingSynchronizationContext(); base.OnActivated(args); }