I am learning ThreadPoolExecutor by following this tutorial. To demonstrate its usage, I made a simple android project, it has a recyclerview that will show some Strings. Initially, the array of Strings(String[] myDataset = new String[10]
) has 10 nulls. My threadPoolExecutor generates some random strings and fills up the array. So whenever a new String is generated and placed inside the array, I should call notifyDataSetChanged()
so that the recyclerView will update and show those random Strings.
the problem
I don't understand how to call notifyDataSetChanged()
and so I am pinned down. I got this exception:
Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Since I know AsyncTask, I understand that this error means I cannot call this method in background thread but I have to call it in main thread/ui thread ( so in AsyncTask, it would look like this:
@Override
protected void onPostExecute(String result) {
weakReference.get().notifyDataSetChanged(); // something like that
}
). I need it's ThreadPoolExecutor counterpart. I did google and found this but I am not sure how to do this.
The necessary code segment is given below:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private String[] myDataset;
private final ThreadPoolExecutor threadPoolExecutor;
private Future future;
private Runnable getRunnable(final int i) {
Runnable runnable = new Runnable() {
@Override
public void run() {
String randomString = MyAdapter.getRandomString(i)+" "+i; // <--create random string
Log.e(TAG, randomString);
myDataset[i] = randomString;
try { Thread.sleep(3000); }
catch (InterruptedException e) { e.printStackTrace(); }
}
};
return runnable;
}
public void doSomeBackgroundWork(){
Runnable[] commands = new Runnable[myDataset.length];
for(int i1=0; i1<commands.length; i1++) {
final int j1 = i1;
commands[j1] = () -> {
String randomString = MyAdapter.getRandomString(j1)+" "+j1;
Log.e(TAG, randomString);
myDataset[j1] = randomString;
try { Thread.sleep(3000); }
catch (InterruptedException e) { e.printStackTrace(); }
// notifyDataSetChanged(); // <-------- Error. Where/How should I call it?
};
threadPoolExecutor.execute(commands[j1]);
}
}
public MyAdapter(String[] myDataset) {
this.myDataset = myDataset; // {null, null, ... ...}
this.threadPoolExecutor = DefaultExecutorSupplier.getInstance().forBackgroundTasks(); // returns new ThreadPoolExecutor( ... parameters... );
// future[i] = threadPoolExecutor.submit(command); future[i].cancel(true); use it like this
doSomeBackgroundWork();
}
// ... the rest of the recyclerview related code
}
Could anyone help me? Thank you for reading.