1

I have a Runnable (say "MyThread") that executes a long task and also uses/locks a Thread-Safe Singleton.

I have noticed that when the back button is pressed the screen immediately exits the activity and there is no visual indication that the MyThread has properly finished.

This is evidenced also by the fact that when I 'reopen' my app the singleton is still locked!!!! and of course getLockedInstance() returns null.

So I guess my question is.... what exactly happens to android applications when the back button is pressed even when it is executing critical tasks? Are the threads terminated? Are the threads of the activity frozen and therefore all data being accessed and used? How do we ensure critical tasks are allowed to finish executing?

// singleton class
public class Storage
{
    private int count = 0;
    private static final Storage ourInstance = new Storage();

    public static synchronized Storage getLockedInstance()
    {
        if (ourInstance.count > 0)
            return null;
        ourInstance.count++;
        return ourInstance;
    }

    public synchronized void UnlockInstance()
    {
        if (count > 0)
            count--;
    }
}

// runnable declaration

private Runnable MyThread = new Runnable()
{
    @Override
    public void run()
    {
        Storage s = Storage.getLockedInstance();

        ..... do stuff .....
        [back button pressed]
        ..... this is never reached .....

        s.UnlockInstance();
    }
}
halfer
  • 19,824
  • 17
  • 99
  • 186
zdanman
  • 508
  • 1
  • 3
  • 13
  • The thread won't necessarily stop, but if your app is now in the background, the process could get killed. Have you tried adding logging calls inside your thread? If you absolutely need a task to run, consider putting it in a `Service` which will run as a separate process from your app. – nicobatu Sep 22 '16 at 00:27
  • Please remove "SOLVED" from your title and post the solution you found as a proper answer. – Jongware Oct 02 '16 at 11:24

2 Answers2

1

The Thread class in Android is no different from the Thread class in regular Java programming. It is the closest representation of the underlying Linux native thread an application gets. The Thread class creates the execution environment for tasks, represented by Runnable. The Thread implements Runnable, so the task to be executed is either defined by the thread itself or injected during thread creation.

Lifecycle of thread

When the run method has finished execution, the thread is terminated and its resources can be freed. This is the final state of the thread; no re-use of the Thread instance or its execution environment is possible.

Interruptions (such as pressing back button)

Occasionally, an application wants to terminate the thread’s execution before it has finished its task. For instance, if a thread is taking a long time to download a video and the user presses a button to cancel the download, the UI thread captures the button press and would like to terminate the downloading thread. There is, however, no way a thread can be directly terminated. Instead, threads can be interrupted, which is an request to the thread that is should terminate, but it is the thread itself that determines whether to oblige or not. Interruptions are invoked on the thread reference:

Thread interruption is implemented collaboratively: the thread makes itself available to be interrupted, and other threads issue the call to interrupt it. Issuing an interruption has no direct impact on the execution of the thread; it merely sets an internal flag on the thread that marks it as interrupted. The interrupted thread has to check the flag itself to detect the interruption and terminate gracefully. A thread must implement cancellation points in order to allow other threads to interrupt it and get it to terminate.

A.J
  • 726
  • 1
  • 7
  • 19
  • I implemented a **getLockedInstanceWait** function (utilizing the **Thread.sleep** method) instead of a 'lock and return' type function getLockedInstance(). Now, although there is a little delay when the activity is resumed, eventually the Storage object unlocks and I am able to **reobtain access!!** This confirms what you said - that when the activity or any of the apps activities are resumed... then the Runnable (**MyThread**) is resumed as well and is able to finish executing. Thanks for the help. – zdanman Sep 22 '16 at 10:13
  • @zdanman "_This confirms what you said - that when the activity or any of the apps activities are resumed... then the Runnable (MyThread) is resumed as well"_ You get the answer (copy/pasted from [this book](http://shop.oreilly.com/product/0636920029397.do)) in a wrong way. Background threads keep running after the back button pressed until they're done with their job or the process is killed by OS. If you'd like to block a background thread see [this](http://stackoverflow.com/questions/6776327/how-to-pause-resume-thread-in-android) or use a `Service`. – Onik Sep 22 '16 at 13:14
  • _"Interruptions (such as pressing back button)"_ What kind of interruptions are you talking about? – Onik Sep 22 '16 at 13:16
  • @Onik , Anders Goransson, mentions in his book, for e.g "if the user presses a button to cancel the download (i.e same as pressing back button) this is an interruption example. In addition, you mentioned that threads keep running until they're done their job which is repeating the same thing mentioned in the answer (There is, however, no way a thread can be directly terminated. When the run method has finished execution, the thread is terminated and its resources can be freed) – A.J Sep 22 '16 at 15:39
0

(Posted on behalf of the OP).

Thanks to everyone (and @A.J A.J) for their comments and help. I had misdiagnosed the problem and actually the problem was mine.

The thread does actually finish executing, but since it is a long process, access to the Storage object is blocked to whatever activity the app is resumed to. My solution was to use a getLockedInstanceWait() function (see below) instead of the "lock and return" type previously utilized:

public static Storage getLockedInstanceWait()
{
    Storage s = null;
    while ((s = Storage.getLockedInstance()) == null)
    {
        try
        {
            Thread.sleep(500);
        }
        catch (InterruptedException e)
        {
            return null;
        }
    }

    return s;
}
halfer
  • 19,824
  • 17
  • 99
  • 186