【发布时间】:2017-01-26 11:43:56
【问题描述】:
我一直在拨打我在 xamarin.android 应用程序中遇到的一个来回问题。我将尝试提供尽可能详细的信息以明确我的问题。
当用户单击按钮时,我想要执行一个长时间运行的任务。我试图运行的任务是下载文件,并将其转换为其他格式。用户在启动下载时知道任务,并希望它完成。我已经编写并测试了代码,我只需要正确放置它。
一些必须被排除的限制:
下载和转换任务是
async,因为我使用的库之一强制执行异步方法应用程序关闭时任务不得关闭,因为用户正在等待下载完成。
其中一种方法必须从 UI 线程运行(这就是文档所说的),但我相信该方法将足以接收 UI 上下文,例如一些活动背景。如果我以服务作为上下文运行命令,我会收到以下错误
Java.Lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() service,所以我假设我需要 MainActivity 上下文
我在使用 Service/Intentservice/AsyncTask 之间进行了相当大的争论,并且遇到了几个问题,只有在我实际在手机上进行测试时才会发生这种情况。
-
Service/Intentservice,无法获取UI线程的上下文,我尝试使用以下方法:
VideoConverter vc = new VideoConverter(); Java.IO.File convertedFile = await vc.ConvertFile(Application.Context, outPutFile, logFunction, progressFunction);但我仍然遇到同样的错误。
同样,每当我报告进度时,我都会用图标重建通知,然后出现这个奇怪的警告:09-18 22:47:12.276 W/IconPackHelper(28042): Unable to cache icon /data/system/theme/icons/com.App_7f020002_0.png 09-18 22:47:12.362 W/IconPackHelper(28042): Unable to cache icon /data/system/theme/icons/com.App_7f020002_0.png 09-18 22:47:12.431 W/IconPackHelper(28042): Unable to cache icon /data/system/theme/icons/com.App_7f020002_0.png 09-18 22:47:12.503 W/IconPackHelper(28042): Unable to cache icon /data/system/theme/icons/com.App_7f020002_0.png每当我构建通知时,这是否重要?
总而言之,我应该使用什么来满足我的需求? AsyncTask 似乎是最好的选择,但由于我使用的是 xamarin,我可以使用 await/async,我应该如何构建我的代码?运行活动中的所有代码或将其分解为更多的化合物?
为什么这个错误只出现在我的手机上而不是模拟器上?
非常感谢您的帮助!干杯!
编辑
根据我收到的反馈,我认为最好实际使用将在前台运行的服务,我已经实现了这种方法,但我遇到了一个错误,我提供了更多细节。
这里我从服务内部调用我的异步方法,因为我不能用异步覆盖,我必须使用 Task.Factory 来运行异步函数
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
Task.Factory.StartNew(async () => {
await downloadAndConvert(id);
});
}
这是对一个类的调用,该类将提供特定的转换。注意上下文。
async downloadAndConvert(string id){
...
VideoConverter vc = new VideoConverter();
Java.IO.File convertedFile = await vc.ConvertFile(Application.Context,
outPutFile,
logFunction,
progressFunction);
// Error is firing here
...
}
这里是VideoConverter类对库的调用,接下来注意上下文的to。
public async Task<File> ConvertFile(
Context contex,
File inputFile,
Action<string> logger = null,
Action<int, int> onProgress = null)
{
...
await FFMpeg.Xamarin.FFMpegLibrary.Run(
contex,
cmdParams
, (s) => { ... }
});
...
}
由于ffmpeg xamarin library 是开源的,我已经能够检索导致错误的行。
// lets try to download
var dlg = new ProgressDialog(context);
所以错误是库尝试使用传递的上下文创建一个ProgressDialog,但由于只有一个活动上下文能够启动 ProgressDialog,它对我的服务/应用程序上下文的破坏。
FFmpeg 库中的调用是为第一次运行打开一个ProgressDialog,因为它会下载库并对其进行初始化。我不想更改库代码,因为它很容易通过 nuget 获得,而我不这样做'我真的不想自己建造图书馆。 如果这是最优雅的解决方案,我会这样做,我可以将ProgressDialogs 切换为通知,它会正常工作。
这是我遵循的完整堆栈跟踪:
Java.Lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Users/builder/data/lanes/3511/f4db8a57/source/mono/mcs/class/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:143
at Java.Interop.JniEnvironment+InstanceMethods.CallNonvirtualVoidMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x000a7] in /Users/builder/data/lanes/3511/0e59c362/source/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.g.cs:12083
at Java.Interop.JniPeerMembers+JniInstanceMethods.FinishCreateInstance (System.String constructorSignature, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x00060] in /Users/builder/data/lanes/3511/0e59c362/source/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs:148
at Android.App.ProgressDialog..ctor (Android.Content.Context context) [0x00078] in /Users/builder/data/lanes/3511/0e59c362/source/monodroid/src/Mono.Android/platforms/android-24/src/generated/Android.App.ProgressDialog.cs:48
at FFMpeg.Xamarin.FFMpegLibrary+<Init>d__7.MoveNext () [0x00179] in D:\git
s-github\xamarin-ffmpeg-android\FFMpeg.Xamarin\FFMpegLibrary.cs:94
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Users/builder/data/lanes/3511/f4db8a57/source/mono/mcs/class/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:143
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x00047] in /Users/builder/data/lanes/3511/f4db8a57/source/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:187
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x0002e] in /Users/builder/data/lanes/3511/f4db8a57/source/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:156
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x0000b] in /Users/builder/data/lanes/3511/f4db8a57/source/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:128
at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in /Users/builder/data/lanes/3511/f4db8a57/source/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/TaskAwaiter.cs:113
at FFMpeg.Xamarin.FFMpegLibrary+<Run>d__8.MoveNext () [0x000d0] in D:\git
s-github\xamarin-ffmpeg-android\FFMpeg.Xamarin\FFMpegLibrary.cs:191
--- End of managed Java.Lang.RuntimeException stack trace ---
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.<init>(Handler.java:200)
at android.os.Handler.<init>(Handler.java:114)
at android.app.Dialog.<init>(Dialog.java:119)
at android.app.AlertDialog.<init>(AlertDialog.java:200)
at android.app.AlertDialog.<init>(AlertDialog.java:196)
at android.app.AlertDialog.<init>(AlertDialog.java:141)
at android.app.ProgressDialog.<init>(ProgressDialog.java:77)
那么有什么方法可以传递活动上下文吗?另外,如果我在应用关闭时尝试创建ProgressDialog,应用会崩溃吗?
【问题讨论】:
标签: android multithreading service android-asynctask xamarin.android