如何调试Xamarin Forms应用程序,该应用程序在Android上消失而不会引发任何异常


编辑:我在logcat中发现了错误。请参阅下面的确认答案

我是Xamarin的新手,但已经做了相当多的Android开发。我的Xamarin应用程序在没有任何通知或异常的情况下消失了。我似乎找不到如何调试这种情况。

我把所有的东西都包在了try/catch块中(让人恶心),但没有抛出异常(或者至少没有被捕获)。

我实现了这个来自博客的堆栈溢出答案中的全局错误处理例程。如果我故意抛出一个错误,全局错误处理程序会捕获它,所以它是有效的。但是,在这种情况下,没有任何例外。

我的应用程序在一点动画后崩溃。通常是平移或收缩。如果我被缩小并且显示的位图很大,它会崩溃得更快。有一个暂停,然后应用程序消失。

我的应用程序正在用SkiaSharp做很多位图动画。我在背景中绘制位图(Task.run( () => <My Drawing code>)),然后引发一个事件以使表面视图无效

MainThread.BeginInvokeOnMainThread(() =>
{
// Code to run on the main thread
canvasView.InvalidateSurface();
}); 

以绘制位图。当纵横比不变时(即没有执行夹点),我会重用工作位图,当创建新位图时,我会处理旧位图。

为了限制绘图,我有一个接受绘图请求的队列。因此,为了绘制,我将绘制请求排入队列,并在后台启动一个任务(请参阅上面运行的任务)。当该任务启动时,它会从队列中请求绘制请求。队列将不会返回下一个,而是返回最新的,并终止任何其他较旧的请求。如果线程启动时没有请求,它会立即退出。如果用户正在进行大量的缩放或平移,这将限制正在绘制的位图的数量。我正在锁定队列以确保线程不会越界。

我偶尔会在输出窗口中注意到,我会看到#15到#19个线程已经启动。但这并不一致。

有没有可能是太多线程被启动,操作系统正在扼杀应用程序?如果使用了太多内存,操作系统会杀死应用程序吗?

我知道安卓会在没有通知的情况下杀死一个应用程序,但我从来没有让它在应用程序处于活动和运行状态时这样做过。我确信我的代码中有一个错误,但当我一无所获时,我不知道如何找到它。

有没有办法从操作系统中了解应用程序关闭的原因?有没有办法查看Xamarin Forms应用程序的操作系统级别可能记录的错误?

编辑:我一直在使用adb logcat --pid=<my pid>来监控应用程序,但当它关闭时,不会输出任何内容。我还没有尝试查看完整的logcat未经过滤的日志,但。。。但如果有什么消息,我会更新的。

EDIT#2使用logcat,我发现了错误。它没有显示在Visual Studio的logcat输出中,我不得不直接连接到adb logcat *:E并查看所有错误。以下是相对位:

07-30 23:25:48.796 1324 1480 E WindowManager:win=Window{491bfd6 u0 Splash Screen com.valleystreams.dupler EXITING}destroySurfaces:appStopped=false win.mWindowRemovalAllowed=true win.mRemoveOnExit=true win.mViewVisibility=0 caller=com.android.server.wm.AppWindowToken.dedestroySurfaces:1178 com.android.server.wm.AppWindowToken.dedestroysurfaces:1159com.android.server.wm.WindowState.onExitAnimationDone:5055.android.server.wm.WindowStateAnimator.onAnimationFinished:284com.android-server.wm.WindowsState.onAnimationFinished:5507com.android_server.wm.-$$Lambda$yVRF8YoeNdTa8GR1wDStVsHu8xM。run:2.android.seerver.wm.SurfaceAnimatorlambda$getFinishedCallback$0$SurfaceAnimator:100

以下是我认为正在发生的事情。输入通道已经失效,操作系统正在扼杀应用程序

07-30 23:28:07.285 1324 1749 E InputDispatcher:通道'fc5d006com.valleystreams.dupler/cr646da0ed5dbdbd092c.MainActivity(服务器)'~通道已不可恢复地断开,将被处理!

07-30 23:28:07.384 1324 1479 E WindowManager:RemoteException occured on reporting focusChanged,w=Window{fc5d006 u0 com.valleystreams.dupler/crc646da0ed5db1bd092c.MainActivity}

07-30 23:28:07.384 1324 1479 E WindowManager:android.os.DeadObjectException

07-30 23:28:07.384 1324 1479 E WindowManager:在android.os.BinderProxy.transactNative(Native Method)

07-30 23:28:07.384 1324 1479 E WindowManager:在android.os.BinderProxy.transaction(BinderProxy:java:527)

07-30 23:28:07.384 1324 1479 E WindowManager:在android.view.IWindows$Stub$Proxy.windowFocusChanged(IWindow.java:829)

07-30 23:28:07.384 1324 1479 E WindowManager:at com.android.server.wm.WindowState.reportFocusChangedSerialized(WindowState.java:3654)

07-30 23:28:07.384 1324 1479 E WindowManager:在com.android.server.wm.WindowManagerService$H.handleMessage(WindowManagerService.java:5255)

07-30 23:28:07.384 1324 1479 E WindowManager:在android.os.Handler.dispatchMessage(Handler.java:107)

07-30 23:28:07.384 1324 1479 E WindowManager:在android.os.Looper.loop(Looper.java:237)

07-30 23:28:07.384 1324 1479 E WindowManager:在android.os.HandlerThread.run(HandlerThread.java:67)

07-30 23:28:07.384 1324 1479 E WindowManager:在com.android.server.ServiceThread.run(ServiceThread.java:44)

您既没有等待Task完成,也没有在其中捕获异常;火与遗忘;应用程序上下文永远不会捕捉到场景异常。

有两种选择。

等待Task将异常抛出堆栈:

await Task.Run(() => < My Drawing code >);

或者捕获任务内部的异常:

await Task.Run(() =>
{
try
{
< My Drawing code >
}
catch (Exception ex)
{
< Log exception >
}
});

最终我找到了如何调试和解决问题。

对于调试,正如@SushiHangover所说,我使用了LogCat。但是,通常在使用LogCat时,我会根据应用程序或进程id(pid)进行筛选。在上面的场景中,操作系统正在扼杀应用程序。因此,我的应用程序没有抛出任何异常,也没有记录任何信息。该应用程序随即消失。因此,筛选到我的应用程序的日志没有显示任何信息。我去掉了过滤器,花了很长时间查看手机上每个应用程序的所有日志消息后,我发现了根本问题。

08-01 01:21:04.155 1324 1749 D InputDispatcher:正在等待应用程序为输入做好准备(8831):706303f原因:正在等待发送非键事件,因为被触摸的窗口尚未完成处理500.0ms前传递给它的某些输入事件。等待队列长度:8。等待队列头年龄:733.6ms.

(请注意,PID隐藏在消息的文本中,但进程的PID来自操作系统。还请注意,应用程序名称不会出现在任何位置。因此,要跟踪此情况,您必须在PID崩溃之前知道它,然后在消息中对您的PID进行文本搜索)

有了这些信息,我可以看到操作系统正在毫无征兆地杀死我的应用程序,因为我处理触摸事件的时间太长了。我所做的所有渲染都是在背景线程上完成的,只有主绘制事件在主线程上完成。然而,我没有意识到的是,我的背景线程并没有像我想要的那样将位图缩小到屏幕大小,而是返回了一个非常大的位图。然后,作为在主线程上绘制的应用程序,它采用了这个非常大的位图,并将其压缩到屏幕大小。这个过程花费了很长时间,导致触摸事件延迟。我修复了后端渲染,使其在后台线程上执行收缩。这最终解决了问题,一切都像丝绸一样流畅,没有来自操作系统的意外终止。

外卖:

  1. 如果你的应用程序在没有警告的情况下消失,你必须检查操作系统消息中的错误。在这种情况下,你必须对你的PID进行文本搜索(即不要过滤你的PID)
  2. 如果您收到InputDispatcher警告或错误,那么您可能在主线程中占用了太多的进程时间

最新更新