在 AsyncTask 上尝试使用 SQLite 检索数据的奇怪行为

Posted

技术标签:

【中文标题】在 AsyncTask 上尝试使用 SQLite 检索数据的奇怪行为【英文标题】:Weird behaviour trying to retrieve data with SQLite while on AsyncTask 【发布时间】:2020-05-10 00:52:21 【问题描述】:

我的应用程序非常滞后,因此我决定使用 AsyncTask 在其中执行最繁重的操作,这样,该应用程序在更改选项卡时就不会那么慢了。 但是现在,它的行为方式非常奇怪。让我解释一下:我有一个 ViewPager2,在那个 ViewPager 中,我有一个 recyclerview。 我在 ViewPager 中放置了一个 AsyncTask,因为它是片段中完成的最繁重的操作,并且在该 ViewPager 的适配器中,我通过一个名为 DatabaseHelper 的类从数据库中检索一些值,该类扩展了 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 只返回一个Cursor,所以我使用另一个类来保持代码的组织性,这个类将Cursor 作为参数并返回一个“ListItem”列表。此类称为“FolderUtils”并包含以下方法(我使用该方法在 ViewPager 中填充我的 RecyclerView):

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 的第一个值,奇怪的是,有时它会返回错误的值,而且它有时只有在我移动我的时候才有效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);

    

我该如何解决这个问题?谢谢。

【问题讨论】:

【参考方案1】:

自己解决了这个问题。 解决方案是让 TaskList 成为 LoadData 类中的私有变量,而不是整个 Adapter 的私有变量,这就像每个项目实例的局部变量一样,删除了某些项目中的重复项。

【讨论】:

以上是关于在 AsyncTask 上尝试使用 SQLite 检索数据的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章

即使在使用 AsyncTask 之后,编舞者也会跳帧(最多 400 个!)

SQLite 数据库查询和 AsyncTask

从 Fragment 内的 AsyncTask 重新启动 Loader (SQLite) 时出现 IllegalStateException

ListView 未在 AsyncTask 中初始化

Android SQLite 更新无法在 AsyncTask 的后台运行

如何使用 AsyncTask 更新 RecyclerView 项目