在 AsyncTask 的 doInBackground 中时列表读取为空
List reading empty when inside doInBackground of AsyncTask
我正在尝试读取 AsyncTask
的 doInBackground
中的整数列表。当我将列表传递给 AsyncTask
的构造函数时,它已满。但是,当我到达 doInBackground
函数时,它是空的。有什么想法吗?
public class floatingActionButtonClickListener implements View.OnClickListener{
@Override
public void onClick(View v) {
if(mAdapter.getDeleteModeStatus()){
// Delete items from database
ArrayList<Integer> IDsToDelete = mAdapter.getJournalIDsToDelete();
new DeleteDatabase().execute(IDsToDelete);
// Turn FAB back to regular button
mFAB.setImageResource(R.drawable.baseline_add_white_48); // Turn FAB to delete button
// Disable delete mode
mAdapter.exitDeleteMode();
// Load database
new LoadDatabase().execute();
}
else{
Intent intent = new Intent(getBaseContext(), AcitivtyJournal.class);
int journalType = Constants.JOURNALTYPE_FULL;
intent.putExtra(Constants.JOURNAL_TYPE, journalType);
startActivity(intent);
}
}
}
private class DeleteDatabase extends AsyncTask <ArrayList<Integer>, Void, Void> {
@Override
protected void onPreExecute() {
super.onPreExecute();
mProgressBarHolder.setVisibility(View.VISIBLE);
}
@Override
protected Void doInBackground(ArrayList<Integer>... arrayLists) {
ArrayList<Integer> IDsToDelete = arrayLists[0];
AppDatabase db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "JournalEntries")
.build();
for(Integer idToDelete : IDsToDelete){
db.mJournalEntriesDao().deleteCompleteJournalEntry(idToDelete);
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
mProgressBarHolder.setVisibility(View.GONE);
}
}
}
这不是您使用 AsyncTask 的方式。您需要声明参数,然后在回调中接收它们。
另请注意,您正试图以您的方式从两个线程(主线程和后台线程)访问相同的数据(IDsToDelete),但没有进行适当的同步。
private class DeleteDatabase extends AsyncTask<ArrayList<Integer>, Void, Void> {
@Override
protected Void doInBackground(ArrayList<Integer>... arrayLists) {
ArrayList<Integer> params = arrayLists[0];
// Do what you need
}
}
ArrayList<Integer> IDsToDelete = mAdapter.getJournalIDsToDelete();
new DeleteDatabase().execute(IDsToDelete);
当你有多线程时,你需要寻找两件事:
操作的原子执行
内存可见性。
有共享内存,每个CPU缓存数据。当您从一个线程创建内容时,您不能只期望第二个线程会读取它。在您的情况下,您正在创建 AsyncTask 并从一个线程注入参数,但随后您从另一个线程在 doInBackground 中读取它们。通常,当您通过一个同步块或访问一个 volatile 变量时(我说的是一般情况,因为我也不完全了解 JVM 的工作原理),线程会将其缓存刷新到主内存,然后也从中读取。这就是共享数据的方式。这就是为什么最好使用框架方式的原因,因为框架将负责在线程之间正确发布数据。您可以使用不可变数据,但 List 不是这样的东西。即使您将引用声明为不可变,您也可能会从两个线程中看到正确的对象,但它们持有的数据可能是旧的。
澄清一下。我并不是说以前的方法行不通。我是说这是出于善意。您不能只是在线程之间共享数据并希望它有效。
想通了。为以后可能有类似问题的人发帖。
令人尴尬的是,ArrayList<Integer>
变空了,因为我在调用 AsyncTask().execute()
.
后在函数 mAdapter.exitDeleteMode();
中将其删除
我不知道当我将列表发送到 AsyncTask
时,它是列表的确切地址,而不仅仅是一个新列表(也就是说,直到我在上面发表评论,然后它点击)。我想我是从 C++ 或其他语言那里得到的思路。我不记得是哪个了。
解决方案: 我想到的解决方案是将 mAdapter.exitDeleteMode()
移动到 onPostExecute()
中,而不是将其放在 onClick()
中方法。
另一个可能的解决方案:我相信另一个可行的解决方案(但我没有测试)是将 new ArrayList<Integer> ()
插入 AsyncTask
我正在尝试读取 AsyncTask
的 doInBackground
中的整数列表。当我将列表传递给 AsyncTask
的构造函数时,它已满。但是,当我到达 doInBackground
函数时,它是空的。有什么想法吗?
public class floatingActionButtonClickListener implements View.OnClickListener{
@Override
public void onClick(View v) {
if(mAdapter.getDeleteModeStatus()){
// Delete items from database
ArrayList<Integer> IDsToDelete = mAdapter.getJournalIDsToDelete();
new DeleteDatabase().execute(IDsToDelete);
// Turn FAB back to regular button
mFAB.setImageResource(R.drawable.baseline_add_white_48); // Turn FAB to delete button
// Disable delete mode
mAdapter.exitDeleteMode();
// Load database
new LoadDatabase().execute();
}
else{
Intent intent = new Intent(getBaseContext(), AcitivtyJournal.class);
int journalType = Constants.JOURNALTYPE_FULL;
intent.putExtra(Constants.JOURNAL_TYPE, journalType);
startActivity(intent);
}
}
}
private class DeleteDatabase extends AsyncTask <ArrayList<Integer>, Void, Void> {
@Override
protected void onPreExecute() {
super.onPreExecute();
mProgressBarHolder.setVisibility(View.VISIBLE);
}
@Override
protected Void doInBackground(ArrayList<Integer>... arrayLists) {
ArrayList<Integer> IDsToDelete = arrayLists[0];
AppDatabase db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "JournalEntries")
.build();
for(Integer idToDelete : IDsToDelete){
db.mJournalEntriesDao().deleteCompleteJournalEntry(idToDelete);
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
mProgressBarHolder.setVisibility(View.GONE);
}
}
}
这不是您使用 AsyncTask 的方式。您需要声明参数,然后在回调中接收它们。
另请注意,您正试图以您的方式从两个线程(主线程和后台线程)访问相同的数据(IDsToDelete),但没有进行适当的同步。
private class DeleteDatabase extends AsyncTask<ArrayList<Integer>, Void, Void> {
@Override
protected Void doInBackground(ArrayList<Integer>... arrayLists) {
ArrayList<Integer> params = arrayLists[0];
// Do what you need
}
}
ArrayList<Integer> IDsToDelete = mAdapter.getJournalIDsToDelete();
new DeleteDatabase().execute(IDsToDelete);
当你有多线程时,你需要寻找两件事:
操作的原子执行
内存可见性。
有共享内存,每个CPU缓存数据。当您从一个线程创建内容时,您不能只期望第二个线程会读取它。在您的情况下,您正在创建 AsyncTask 并从一个线程注入参数,但随后您从另一个线程在 doInBackground 中读取它们。通常,当您通过一个同步块或访问一个 volatile 变量时(我说的是一般情况,因为我也不完全了解 JVM 的工作原理),线程会将其缓存刷新到主内存,然后也从中读取。这就是共享数据的方式。这就是为什么最好使用框架方式的原因,因为框架将负责在线程之间正确发布数据。您可以使用不可变数据,但 List 不是这样的东西。即使您将引用声明为不可变,您也可能会从两个线程中看到正确的对象,但它们持有的数据可能是旧的。
澄清一下。我并不是说以前的方法行不通。我是说这是出于善意。您不能只是在线程之间共享数据并希望它有效。
想通了。为以后可能有类似问题的人发帖。
令人尴尬的是,ArrayList<Integer>
变空了,因为我在调用 AsyncTask().execute()
.
mAdapter.exitDeleteMode();
中将其删除
我不知道当我将列表发送到 AsyncTask
时,它是列表的确切地址,而不仅仅是一个新列表(也就是说,直到我在上面发表评论,然后它点击)。我想我是从 C++ 或其他语言那里得到的思路。我不记得是哪个了。
解决方案: 我想到的解决方案是将 mAdapter.exitDeleteMode()
移动到 onPostExecute()
中,而不是将其放在 onClick()
中方法。
另一个可能的解决方案:我相信另一个可行的解决方案(但我没有测试)是将 new ArrayList<Integer> ()
插入 AsyncTask