java Android ThreadPoolExecutor完成后如何调用RecyclerVIew notifyDataSetChanged()?
我正在学习ThreadPoolExecutor,方法如下tutorial。为了演示它的用法,我做了一个简单的安卓项目,它有一个recyclerview,可以显示一些字符串。最初,字符串数组(String[] myDataset = new String[10]
)有10个空值。我的threadPoolExecutor生成一些随机字符串并填充数组。因此,每当生成一个新字符串并将其放入数组中时,我应该调用notifyDataSetChanged()
,以便recyclerView将更新并显示这些随机字符串
问题
我不知道如何调用notifyDataSetChanged()
,所以我被束缚住了。我得到了一个例外:
Caused by: 安卓.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
因为我知道AsyncTask,我知道这个错误意味着我不能在后台线程中调用这个方法,但我必须在主线程/ui线程中调用它(所以在AsyncTask中,它看起来像这样:
@Override
protected void onPostExecute(String result) {
weakReference.get().notifyDataSetChanged(); // something like that
}
)。我需要它的线程池执行器对应。我在谷歌上找到了this,但我不知道怎么做
必要的代码段如下所示:
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
}
有人能帮我吗?谢谢你的阅读
# 1 楼答案
在所有需要从另一个线程与UIThread通信的情况下,引擎盖下都有一个Handler class(AsyncTask也可以使用它)
一些可能的选择:
使用连接到主活套的处理程序:
Handler handler = new Handler(getMainLooper()); handler.post(new Runnable() { @Override public void run() { notifyDataSetChanged(); } });
使用您提到的“runOnUiThread”:
runOnUiThread(new Runnable() { @Override public void run() { notifyDataSetChanged(); } });
使用UI视图的“post”方法(例如,RecyclerView):
yourRecyclerView.post(new Runnable() { @Override public void run() { notifyDataSetChanged(); } });
# 2 楼答案
如果有人需要,以下是我根据sergiy-tikhonov的答案所做的
如你所见,我尝试了第三种选择。首先,我在父片段中创建了一个
WeakReference<RecyclerView> recyclerViewWeakReference = new WeakReference<RecyclerView>(myRecyclerView)
(如果您正在使用该片段,则为活动)。然后我将弱引用传递到MyAdapter
。我使用了weakReference
,因为这是使用AsyncTask所做的,所以我的直觉提醒我这样做。我希望这是有帮助的