Search code examples
javaandroidrunnable

runOnUiThread() acts on a closed activity when called from ThreadExecutor


I am having an issue with runOnUiThread() acting on a closed activity. Here is the logic:

In activity one, I navigate to activity two.

In activity two I am doing some background fetching and once it is done, I navigate to activity three.

The issue is that if I close activity two while data is still being fetched, my thread keeps running and since runOnUiThread() gets called in my code, activity one gets acted on and it navigates me to activity three. I don't want that to happen. I want the thread to stop or at least for the things in runOnUiThread() to not touch any other activity besides the one that the thread was created in.

Note: In my example it is launching an activity but other code could be in there related to the UI that gets triggered in the same way.

Here is what my code looks like:

ExecutorService executorService = Executors.newSingleThreadExecutor();

executorService.execute(new Runnable() {
    public void run() {
        // Do fetching of data

    runOnUiThread(new Runnable() {
            @Override
            public void run() {
                // Navigate to activity three
            }
        });
    }
});

I tried shutting down the executor service when the activity is closed, and while I can verify that onDestroy() gets called with a console.log statement, it appears neither shutdown() or shutdownNow() work:

@Override
protected void onDestroy() {
    super.onDestroy();

    if (executorService != null) {
        executorService.shutdown(); // Does not work to stop thread from executing
        executorService.shutdownNow(); // Does not work to stop thread from executing
    }

}

Edit: How do I add an interruptor to this to be able to interrupt the thread?


Solution

  • You will have to add a check of ExecutorService.isShutdown() inside your Runnable class. ExecutorService.shutdown() and ExecutorService.shutdownNow() does not guarantee that previously submitted task will be shut down immediately.

    According to the documentation,

    ExecutorService.shutdown()

    Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted. Invocation has no additional effect if already shut down. This method does not wait for previously submitted tasks to complete execution.

    ExecutorService.shutdownNow()

    Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution.

    This method does not wait for actively executing tasks to terminate.

    There are no guarantees beyond best-effort attempts to stop processing actively executing tasks. For example, typical implementations will cancel via Thread.interrupt(), so any task that fails to respond to interrupts may never terminate.