1

我使用来自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;
        }
    }

但它在任务结束后调用。

如果用户在完成之前切换到应用程序,如何中断后台任务执行?

DidEnter后台代码:

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

1 回答 1

2

主要问题是您的DidEnterBackground方法仅在您的 for 循环完成(或您已实现的任何任务)后才会返回,因为您在同一个线程上调用它。不管有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;
            });

        });
    }
于 2012-07-16T12:45:12.220 回答