[英]Android How Do I Call RecyclerVIew notifyDataSetChanged() after ThreadPoolExecutor finishes?
I am learning ThreadPoolExecutor by following this tutorial .我正在按照本教程学习 ThreadPoolExecutor。 To demonstrate its usage, I made a simple android project, it has a recyclerview that will show some Strings.
为了演示它的用法,我做了一个简单的 android 项目,它有一个 recyclerview 可以显示一些字符串。 Initially, the array of Strings(
String[] myDataset = new String[10]
) has 10 nulls.最初,字符串数组 (
String[] myDataset = new String[10]
) 有 10 个空值。 My threadPoolExecutor generates some random strings and fills up the array.我的 threadPoolExecutor 生成一些随机字符串并填充数组。 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.因此,每当生成一个新字符串并将其放置在数组中时,我都应该调用
notifyDataSetChanged()
以便 recyclerView 将更新并显示这些随机字符串。
I don't understand how to call notifyDataSetChanged()
and so I am pinned down.我不明白如何调用
notifyDataSetChanged()
,所以我被固定住了。 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:因为我知道 AsyncTask,所以我知道这个错误意味着我不能在后台线程中调用这个方法,但我必须在主线程/ui 线程中调用它(所以在 AsyncTask 中,它看起来像这样:
@Override
protected void onPostExecute(String result) {
weakReference.get().notifyDataSetChanged(); // something like that
}
). )。 I need it's ThreadPoolExecutor counterpart.
我需要它的 ThreadPoolExecutor 对应物。 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.
感谢您的阅读。
There is a Handler class under the hood in all cases where you need to communicate to UIThread from the another Thread (AsyncTask use it as well).在所有需要从另一个线程(AsyncTask 也使用它)与 UIThread 通信的情况下,引擎盖下都有一个处理程序 class 。
Some of possible choices:一些可能的选择:
Use Handler, connected to main looper:使用 Handler,连接到主循环器:
Handler handler = new Handler(getMainLooper()); handler.post(new Runnable() { @Override public void run() { notifyDataSetChanged(); } });
Use "runOnUiThread" that you've mentioned:使用您提到的“runOnUiThread”:
runOnUiThread(new Runnable() { @Override public void run() { notifyDataSetChanged(); } });
Use the "post" method of your UI-View (RecyclerView, for example):使用 UI-View 的“post”方法(例如 RecyclerView):
yourRecyclerView.post(new Runnable() { @Override public void run() { notifyDataSetChanged(); } });
In case anyone needs, here is what I did based on sergiy-tikhonov 's answer.如果有人需要,这是我根据sergiy-tikhonov的回答所做的。
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
recyclerViewWeakReference.get().post(new Runnable() { // <---- this is the change
@Override
public void run() {
notifyDataSetChanged();
}
});
};
threadPoolExecutor.execute(commands[j1]);
}
}
So as you can see, I tried the third option.如您所见,我尝试了第三个选项。 First I created a
WeakReference<RecyclerView> recyclerViewWeakReference = new WeakReference<RecyclerView>(myRecyclerView)
in the parent fragment (or activity if you are using that).首先,我在父片段(或活动,如果你正在使用它)中创建了一个
WeakReference<RecyclerView> recyclerViewWeakReference = new WeakReference<RecyclerView>(myRecyclerView)
) 。 Then I passed the weak reference into MyAdapter
.然后我将弱引用传递给
MyAdapter
。 I used weakReference
because that is what you do with AsyncTask,so my instincts alerted me to do so.我使用
weakReference
,因为这就是你对AsyncTask 所做的,所以我的直觉提醒我这样做。 I hope this is helpful.我希望这是有帮助的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.