0
@Override
protected void onCreate (Bundle savedInstanceState) {
    
    progressDialog.show();

    if (/* task that returns a boolean value */) {
        // Do stuff        
    }
    else {
        // Do other stuff     
    }

    progressDialog.dismiss();

}

This code should be showing the progress dialog, wait for the task to produce its result, then evaluate the if statement and dismiss the dialog. But this doesn't happen: the UI thread is blocked, the task is executed and only then is the progress dialog shown, only to be dismissed immediately.

What would be the correct way to solve this problem ?

2 Answers2

1

A simple worker thread.

public void onClick(View v) {
    new Thread(new Runnable() {
        public void run() {
            // a potentially time consuming task
        }
    }).start();
}

There are other alternatives that can be considered depending on your requirement as mentioned in this answer.

javdromero
  • 1,850
  • 2
  • 11
  • 19
  • 1
    Seems like I had to wrap the whole thing in one of these to separate it from the UI thread. Thanks! – outsidethecave Jul 12 '21 at 15:30
  • You should not use Threads directly, use various utilities designed for background tasks. The official doc recommends Coroutines for Kotlin and Java Concurrent utilities for Java. There are also some libraries for background processing. – Ananta Raha Jul 12 '21 at 16:00
0

You can use AsyncTask for this purpose, however, it has been deprecated in Sdk 30 and recommended to use the java.concurrent.* utilities directly docs. Following is an workaround using ExecutorService, although it is not perfect, it definitely meets your functionality:

In your Activity (say, MyActivity), create a member of ExecutorService and initialize it. Add method and callback like following, when you want to perform some background task, just call it:

public class MyActivity extends AppCompatActivity {
    // You can use your preferred executor
    private final ExecutorService executor = new ThreadPoolExecutor(0, 1,
            3L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>());

    @Override
    protected void onCreate (Bundle savedInstanceState) {
        // Initiate the task
        executeParallel(new Callable<Boolean> {
            @Override
            public Boolean call() {
                // Perform your task and return boolean
                return trueOrFalse;
            }
        }, new Callback<Boolean>() {
            @Override
            public void onStart() {
                // Show progress dialog
                progressDialog.show();
            }

            @Override
            public void onComplete(Boolean result) {
                if (result) {
                    // Do some tasks
                } else {
                    // Do other tasks
                }
                // Remove dialog
                progressDialog.dismiss();
            }
        }, new Handler(Looper.getMainLooper()));
    }

    public <R> void executeParallel(@NonNull Callable<R> callable, @Nullable Callback<R> callback, Handler handler) {
        executor.execute(() -> {
            handler.post(() -> {
                if (callback != null) {
                    callback.onStart();
                }
            });
            R r = null;
            try {
                r = callable.call();
            } catch (Exception e) {
                // Ignore
            } finally {
                R result = r;
                handler.post(() -> {
                    if (callback != null) {
                        callback.onComplete(result);
                    }
                });
            }
        });
    }

    public interface Callback<R> {
        void onStart();
        void onComplete(R result);
    }
}

When you are done, just shut down the ExecutorService. This Executor and related methods can be moved into ViewModel if you use them for better design. Remember, you should not use Thread directly to avoid potential memory leak.

Ananta Raha
  • 1,011
  • 5
  • 14
  • What kind of memory leaks would occur? – outsidethecave Jul 12 '21 at 16:29
  • At first, you cannot update your UI elements from background thread, to solve this there is Handler which interacts between threads. Secondly, if you run a thread to do long-running task and a configuration change occurs, your activity gets destroyed but the thread keeps alive, uses system resources and might result in unexpected behavior unless you handle them properly. – Ananta Raha Jul 12 '21 at 16:46