I'm starting a new thread from my activity, this thread does a 10 second operation and then reports back to the UI with runOnUiThread()
During the 10 second operation, the UI becomes unresponsive and does not respond to any user interaction. In this case I am attempting to close the activity using a button in the toolbar. An ANR error is thrown but the button click is processed after the worker thread has finished.
Although, while the thread is working, the app is still able to display a spinning ProgressBar
which wouldn't happen if the work was being done on the UI thread.
The Profiler
shows that the UI thread is sleeping during this work, so to my understanding it should be responsive?. I've tried using AsyncTask
instead but that also doesn't work. Anyway here is some code:
The new Thread
is started when the window comes into focus:
Activity:
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(hasFocus && !recyclerSetup){
progressBar.setIndeterminate(true);
progressBar.setVisibility(View.VISIBLE);
WorkThread thread = new WorkThread();
thread.start();
}
}
Thread:
private class WorkThread extends Thread {
@Override
public void run() {
getViewModelAndWords();
runOnUiThread(() -> setupRecycler());
}
}
private void getViewModelAndWords() {
viewModel = ViewModelProviders.of(this).get(WordViewModel.class);
adapter = new WordDetailedAdapter(this, viewModel, this, this, !favGroup.equals(ANY_WORD_PARAM));
allWords = viewModel.getAllWords();
}
I'm not sure if the viewModel
has anything to do with the issue or not, but it's the viewModel.getAllWords()
method which performs a heavy 10 second Room db operation.
Here's a snapshot of the Profiler
showing the sleeping UI thread and worker Thread
(AsyncTask #6):
EDIT:
Okay, so I think the issue lies within the room DB operation / viewModel
. Replacing the contents of getAllWords()
with Thread.sleep(10000);
free'd up the UI thread for user interaction, therefore it's the following code which is (for some reason) preventing user input:
EDIT 2:
As suggested, I now use onPostExecute()
along with an interface to retrieve the words:
public static class GetAllWordsWithCallBackTask extends AsyncTask<Void, Void, List<Word>>{
WordViewModel.iGetWords listener;
WordDao wordDao;
public GetAllWordsWithCallBackTask(WordDao wordDao, WordViewModel.iGetWords listener) {
this.listener = listener;
this.wordDao = wordDao;
}
@Override
protected List<Word> doInBackground(Void... voids) {
return wordDao.getAllWords();
}
@Override
protected void onPostExecute(List<Word> words) {
listener.gotWords(words);
}
}
get()
has been removed and I simply execute the task, passing in listener
to handle the call back:
public void getAllWordsWithCallBack(WordViewModel.iGetWords listener) {
try {
new GetAllWordsWithCallBackTask(wordDao, listener).execute();
} catch (Exception e) {
Crashlytics.log("Getting all words exception: "+e.getMessage());
e.printStackTrace();
}
}
This works well and the words are returned to my activity successfully, but the UI is still unresponsive while the operation is being executed.