简体   繁体   中英

Finish iOS background task, when move it foreground

I use code samples from http://software.tavlikos.com/2010/12/08/multitasking-in-ios-the-monotouch-way-part-i/ article to run background task on iOS application DidEnterBackground event.

Task is heavy and long timing - near 1 minute. If user force application back to foreground, he should wait till task is finished. It's a bit weak.

I tried to use WillEnterForeground event:

    public override void WillEnterForeground (UIApplication application)
    {
        if (taskId != 0) {
            Console.WriteLine("Finish previous task"); 
            application.EndBackgroundTask(taskId);
            taskId = 0;
        }
    }

but it calls after task ending.

How to break background task execution if user switched to app before it's done?

DidEnterBackground code:

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

The main problem is that your DidEnterBackground method will return only after your for loop completes (or, whichever task you have implemented), because you are calling it on the same thread. With InvokeOnMainThread or not, it doesn't matter, your task will be executed on the same thread and, actually, you don't need to call InvokeOnMainThread since you are already on the main thread. Under normal circumstances, this would cause your app to be terminated by iOS. However, since you are calling BeginBackgroundTask first, this does not happen.

So since your DidEnterBackground method's return is delayed and you bring your app back to the foreground in the meantime, it's normal for your WillEnterForeground method to be executed after your task ends. That's because the WillEnterForeground method cannot be executed since the DidEnterBackground method hasn't returned yet, so it's queued after that.

In my example in the above article you mentioned, I am calling my task asynchronously by calling new System.Action(SomeDelegate(){}).BeginInvoke(null, null); . You can use whichever solution you like, I am now mostly using the ThreadPool .

So, I would modify your above DidEnterBackground method like this:

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

        });
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM