在 AsyncTask 上尝试使用 SQLite 检索数据的奇怪行为
Weird behaviour trying to retrieve data with SQLite while on AsyncTask
我的应用程序非常慢,所以我决定使用 AsyncTask 在其中执行最繁重的操作,这样应用程序在更改选项卡时就不会那么慢了。
但是现在,它的行为非常奇怪。让我解释一下:我有一个 ViewPager2,在那个 ViewPager 里面,我有一个 recyclerview。
我在 ViewPager 中放置了一个 AsyncTask,因为它是片段中完成的最重的操作,并且在该 ViewPager 的适配器中,我通过一个名为 DatabaseHelper 的 class 从数据库中检索了一些值,它扩展了 SQLiteOpenHelper 并具有这个方法。
public Cursor getAllTasksByList(int ListID)
{
SQLiteDatabase db = this.getWritableDatabase();
Cursor c = db.rawQuery("SELECT * FROM " + Db.Tables.Tasktable.TASKS_TABLE + " WHERE " + Db.Tables.Tasktable.COL_LIST_ID + " = " + ListID, null);
return c;
}
因为 DatabaseHelper 只有 returns 一个 Cursor,我使用另一个 class 来保持代码的组织性,这个 class 将 Cursor 作为参数,returns 一个列表"ListItem"。这个 class 被称为 "FolderUtils" 并且包含以下方法(我用它来填充我的 RecyclerView 里面的方法,它在我的 ViewPager 里面):
public ArrayList<TaskItem> getTasksByList(int ListID, Context context) {
ArrayList<TaskItem> tasks = new ArrayList<>();
DatabaseHelper d = new DatabaseHelper(context);
Cursor c = d.getAllTasksByList(ListID);
while (c.moveToNext()) {
int id = c.getInt(0);
int listid = c.getInt(1);
boolean checked = c.getInt(2) > 0;
String title = c.getString(3);
tasks.add(new TaskItem(id, listid, checked, title));
}
return tasks;
}
但这就是问题所在,有时这个List是空的,但有时它只是检索我要查找的Table的第一个值,奇怪的是,有时它returns错了值,有时只有当我将 ViewPager 移动到另一个位置或者我只是放置一些断点时它才会起作用。这是我的适配器代码。
@Override
public void onBindViewHolder(@NonNull ListHolder holder, int position) {
new LoadData(mList.get(position), holder).execute();
}
@Override
public int getItemCount() {
return mList.size();
}
private class LoadData extends AsyncTask<Void, Void, Void> {
private ListItem item;
private ListHolder holder;
public LoadData(ListItem item, ListHolder holder) {
this.item = item;
this.holder = holder;
}
@Override
protected void onPreExecute(){
super.onPreExecute();
//I set the visibility to GONE so that the user can just see the final layout and not the layout "Building" itself.
holder.itemView.setVisibility(View.GONE);
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
setItems(item, holder); //setItems is for setting the UI Content.
AttachRecycler(holder, item); //AttachRecycler creates an adapter for the recyclerview with the TaskList values, and attaches it to the recyclerview inside the ViewPager item.
holder.itemView.setVisibility(View.VISIBLE); //Shows the finished item
}
@Override
protected Void doInBackground(Void... voids) {
SetList(item); //SetList is where it takes the values from database and adds it to the list.
return null;
}
}
private void SetList(ListItem item) {
TaskList = new ArrayList<>();
else if (Mode == 1)
{
//Mode by default is 1. The line below does gets executed, however, it returns the wrong values.
TaskList.addAll(FolderUtils.getInstance().getTasksByList(item.getID(), context));
}
private void AttachRecycler(ListHolder holder, ListItem item)
{
LinearLayoutManager manager = new LinearLayoutManager(context);
holder.recycler.setLayoutManager(manager);
adapter = new TaskAdapter(TaskList, item.getColor(), context, item.getID());
holder.recycler.setAdapter(adapter);
}
我该如何解决这个问题?谢谢。
我自己解决了这个问题。
解决方案是使 TaskList 成为 LoadData 内部的私有变量 class,而不是整个 Adapter 的私有变量,这就像每个项目实例的局部变量,删除某些项目中的重复项。
我的应用程序非常慢,所以我决定使用 AsyncTask 在其中执行最繁重的操作,这样应用程序在更改选项卡时就不会那么慢了。
但是现在,它的行为非常奇怪。让我解释一下:我有一个 ViewPager2,在那个 ViewPager 里面,我有一个 recyclerview。
我在 ViewPager 中放置了一个 AsyncTask,因为它是片段中完成的最重的操作,并且在该 ViewPager 的适配器中,我通过一个名为 DatabaseHelper 的 class 从数据库中检索了一些值,它扩展了 SQLiteOpenHelper 并具有这个方法。
public Cursor getAllTasksByList(int ListID)
{
SQLiteDatabase db = this.getWritableDatabase();
Cursor c = db.rawQuery("SELECT * FROM " + Db.Tables.Tasktable.TASKS_TABLE + " WHERE " + Db.Tables.Tasktable.COL_LIST_ID + " = " + ListID, null);
return c;
}
因为 DatabaseHelper 只有 returns 一个 Cursor,我使用另一个 class 来保持代码的组织性,这个 class 将 Cursor 作为参数,returns 一个列表"ListItem"。这个 class 被称为 "FolderUtils" 并且包含以下方法(我用它来填充我的 RecyclerView 里面的方法,它在我的 ViewPager 里面):
public ArrayList<TaskItem> getTasksByList(int ListID, Context context) {
ArrayList<TaskItem> tasks = new ArrayList<>();
DatabaseHelper d = new DatabaseHelper(context);
Cursor c = d.getAllTasksByList(ListID);
while (c.moveToNext()) {
int id = c.getInt(0);
int listid = c.getInt(1);
boolean checked = c.getInt(2) > 0;
String title = c.getString(3);
tasks.add(new TaskItem(id, listid, checked, title));
}
return tasks;
}
但这就是问题所在,有时这个List是空的,但有时它只是检索我要查找的Table的第一个值,奇怪的是,有时它returns错了值,有时只有当我将 ViewPager 移动到另一个位置或者我只是放置一些断点时它才会起作用。这是我的适配器代码。
@Override
public void onBindViewHolder(@NonNull ListHolder holder, int position) {
new LoadData(mList.get(position), holder).execute();
}
@Override
public int getItemCount() {
return mList.size();
}
private class LoadData extends AsyncTask<Void, Void, Void> {
private ListItem item;
private ListHolder holder;
public LoadData(ListItem item, ListHolder holder) {
this.item = item;
this.holder = holder;
}
@Override
protected void onPreExecute(){
super.onPreExecute();
//I set the visibility to GONE so that the user can just see the final layout and not the layout "Building" itself.
holder.itemView.setVisibility(View.GONE);
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
setItems(item, holder); //setItems is for setting the UI Content.
AttachRecycler(holder, item); //AttachRecycler creates an adapter for the recyclerview with the TaskList values, and attaches it to the recyclerview inside the ViewPager item.
holder.itemView.setVisibility(View.VISIBLE); //Shows the finished item
}
@Override
protected Void doInBackground(Void... voids) {
SetList(item); //SetList is where it takes the values from database and adds it to the list.
return null;
}
}
private void SetList(ListItem item) {
TaskList = new ArrayList<>();
else if (Mode == 1)
{
//Mode by default is 1. The line below does gets executed, however, it returns the wrong values.
TaskList.addAll(FolderUtils.getInstance().getTasksByList(item.getID(), context));
}
private void AttachRecycler(ListHolder holder, ListItem item)
{
LinearLayoutManager manager = new LinearLayoutManager(context);
holder.recycler.setLayoutManager(manager);
adapter = new TaskAdapter(TaskList, item.getColor(), context, item.getID());
holder.recycler.setAdapter(adapter);
}
我该如何解决这个问题?谢谢。
我自己解决了这个问题。 解决方案是使 TaskList 成为 LoadData 内部的私有变量 class,而不是整个 Adapter 的私有变量,这就像每个项目实例的局部变量,删除某些项目中的重复项。