我使用http://software.tavlikos.com/2010/12/08/multitasking-in-ios-the-monotouch-way-part-i/文章中的代码示例在iOS应用程序DidEnterBackground事件上运行后台任务。
任务繁重且时间长 - 接近1分钟。如果用户强制应用程序回到前台,他应该等到任务完成。它有点弱。
我尝试使用WillEnterForeground事件:
public override void WillEnterForeground (UIApplication application)
{
if (taskId != 0) {
Console.WriteLine("Finish previous task");
application.EndBackgroundTask(taskId);
taskId = 0;
}
}
但在任务结束后调用。
如果用户在完成之前切换到应用程序,如何中断后台任务执行?
DidEnterBackground代码:
public override void DidEnterBackground (UIApplication application)
{
Console.WriteLine ("DidEnterBackground");
if (taskId != 0) {
Console.WriteLine("Finish previous task");
application.EndBackgroundTask(taskId);
taskId = 0;
}
taskId = application.BeginBackgroundTask(delegate {
if (taskId != 0) {
application.EndBackgroundTask(taskId);
taskId = 0;
}
});
Console.WriteLine("Begin task");
application.InvokeOnMainThread(delegate() {
for(int i = 0; i < 700; i++) {
if ((i + 1) % 100 == 0)
Console.WriteLine("Time to remain: {0} seconds", application.BackgroundTimeRemaining);
//viewController.Touch();
}
});
application.EndBackgroundTask(taskId);
taskId = 0;
}
答案 0 :(得分:2)
主要问题是,只有在for循环完成后(或者,无论你执行了哪个任务),你的DidEnterBackground
方法才会返回,因为你在同一个线程上调用它。使用InvokeOnMainThread
与否,无关紧要,您的任务将在同一个线程上执行,实际上,您不需要调用InvokeOnMainThread
,因为您已经在主线程上。在正常情况下,这会导致您的应用被iOS终止。但是,由于您首先调用BeginBackgroundTask,因此不会发生这种情况。
因此,由于您的DidEnterBackground
方法的返回时间延迟,并且您在此期间将应用程序带回前台,因此之后执行<{>>的WillEnterForeground
方法是正常的任务结束。那是因为WillEnterForeground
方法尚未返回,因为DidEnterBackground
方法尚未返回,所以它在此之后排队。
在我上面提到的上一篇文章的例子中,我通过调用new System.Action(SomeDelegate(){}).BeginInvoke(null, null);
来异步调用我的任务。您可以使用您喜欢的任何解决方案,我现在主要使用ThreadPool
。
所以,我会像这样修改你上面的DidEnterBackground方法:
public override void DidEnterBackground (UIApplication application)
{
Console.WriteLine ("DidEnterBackground");
if (taskId != 0) {
Console.WriteLine("Finish previous task");
application.EndBackgroundTask(taskId);
taskId = 0;
}
taskId = application.BeginBackgroundTask(delegate {
if (taskId != 0) {
application.EndBackgroundTask(taskId);
taskId = 0;
}
});
Console.WriteLine("Begin task");
ThreadPool.QueueUserWorkItem(delegate {
application.InvokeOnMainThread(delegate() {
for(int i = 0; i < 700; i++) {
if ((i + 1) % 100 == 0)
Console.WriteLine("Time to remain: {0} seconds", application.BackgroundTimeRemaining);
//viewController.Touch();
}
// EndBackgroundTask must also be executed on the main thread.
application.EndBackgroundTask(taskId);
taskId = 0;
});
});
}