How to pass a value from a runnable thread once it has finished in Android Studio?

Viewed 98

I am using a thread to get an id from my database. Once the thread has finished running I need to use that id in another thread to get a list of items. Once that thread has finished I use the list of items to populate a spinner. The problem I am encountering is that it is populating the spinner before the thread has returned the list of items. How can I make it so the spinner doesn't get populated until the thread has finished running?

        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

                new Thread(new Runnable() {
                    @Override
                    public void run() {

                        String bookName = existingBooks.get((int) spinner.getSelectedItemId());

                        Book myBook = AppDatabase.getInstance(getContext()).bookDAO().getBookByTitle(bookName);

                        long book_Id = myBook.getBook_id();

                        existingCountDates = AppDatabase.getInstance(getContext()).countDAO().getCountDatesInBook(book_Id);

                        List<Count> Counts = AppDatabase.getInstance(getContext()).countDAO().getAllCounts();

                        Log.e("Dates", existingCountDates.toString());
                        Log.e("All Counts", Counts.toString());

                    }
                }).start();

                //TODO: FIX THIS ISSUE
                Log.e("Problem:", "This gets called before the thread finishes. Not sure how to fix it");
                str_adapter.clear();
                for (int i = 0; i < existingCountDates.size(); i++) {
                    str_adapter.add(existingCountDates.get(i));
                }
                str_adapter.notifyDataSetChanged();

            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
                //TODO: DISABLE OTHER DROPDOWN MENUS?
            }
        });

enter image description here

3 Answers

I am not sure whether this will help you or not. But you can use a bool variable to check whether the thread has finished its work.

bool flag = false;
new Thread(new Runnable() {
    @Override
    public void run() {
        //statements
        flag = true;
    }
}).start();
while(flag != true);
//statements to be executed after completion of thread.

NOTE: Make sure execution never goes to infinite loop.

How can I make it so the spinner doesn't get populated until the thread has finished running?

There are a couple of ways to do that. The easiest might be to get an ExecutorService which is usually recommended as opposed to creating a Thread "by hand". This also allows you to return a value from your job in which case you submit a Callable<?> instead of a Runnable.

ExecutorService threadPool = Executors.newFixedThreadPool(1);
...
Future<Void> future = threadPool.submit(new Runnable() {
    public void run() {
       ...
    }
});
// wait for this job to finish
future.get();
...
// when you are done with the pool you need to shut it down
threadPool.shutdown();

You can also start a thread and then join() with it. That waits for the thread to finish.

Thread thread = new Thread(new Runnable() { ... });
thread.start();
// now we can do stuff while the thread runs in the background
...
// wait for the thread to finish before returning
thread.join();
...

The get() method or the join() method also means that the existingCountDates or anything else that was modified inside of the job will be updated in the caller's memory appropriately.

Related