当前位置: 首页 > 知识库问答 >
问题:

设置适配器时,RecyclerView阻止UI

尉迟龙光
2023-03-14

我为后台服务实现了一个AsyncTask来执行对数据库的查询,该查询速度非常快,不超过2-3秒。AsyncTask中的ProgressDialog有时很难检测到。

我的问题是,当任务完成并且我检索到游标时,当我将适配器设置到RecyclerView时,流程会冻结我的UI几秒钟,直到数据设置完毕。当我执行搜索(新查询,与获取所有行相同的过程,但行数较少),并替换光标以更新数据时,也会发生这种情况。

下面是一些相关代码:

异步任务

@Override
protected Void doInBackground(Void... Void) {
    if(type==Constants.GET_ZIP_CODES)
        cursor = db.getAllZipCodes();
    else
        cursor = db.searchZipCodes(text);

    return null;
}

@Override
protected void onPostExecute(Void Void) {
    setAdapter();
    mProgressDialog.dismiss();
    super.onPostExecute(Void);
}
private void setAdapter(){
    if(myAdapter == null){
        myAdapter = new MyAdapter(getActivity(), cursor);
        search_rv.setAdapter(myAdapter);
    } else
        myAdapter.swapCursor(cursor);
}

我已经更改了我的适配器,以避免使用CursorAdapter,正如@Cricket_007指出的那样,在适配器中设置适配器是糟糕的设计。

这是我的适配器:

public class SearchListAdapter extends RecyclerView.Adapter<SearchListAdapter.ViewHolder> {


private Context mContext;

private Cursor mCursor;

private boolean mDataValid;
private int mRowIdColumn;

private DataSetObserver mDataSetObserver;

public SearchListAdapter(Context context, Cursor c) {

    mContext = context;
    mCursor=c;

    mDataValid = c != null;
    mRowIdColumn = mDataValid ? mCursor.getColumnIndex("_id") : -1;
    mDataSetObserver = new NotifyingDataSetObserver();
    if (mCursor != null) {
        mCursor.registerDataSetObserver(mDataSetObserver);
    }

}

static class ViewHolder extends RecyclerView.ViewHolder {
    TextView itemTV;

    ViewHolder(View itemView) {
        super(itemView);
        itemTV = (TextView) itemView.findViewById(R.id.itemTV);
    }
}


@Override
public void setHasStableIds(boolean hasStableIds) {
    super.setHasStableIds(true);
}

@Override
public int getItemCount() {
    if (mDataValid && mCursor != null) {
        return mCursor.getCount();
    }
    return 0;
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    // Passing the binding operation to cursor loader
    mCursor.moveToPosition(position);
    String town = mCursor.getString(mCursor.getColumnIndex(Constants.COLUMN_TOWN));
    String zipcode = mCursor.getString(mCursor.getColumnIndex(Constants.COLUMN_ZIPCODE));
    String zipcode_etx = mCursor.getString(mCursor.getColumnIndex(Constants.COLUMN_ZIPCODE_EXTENSION));
    holder.itemTV.setText(zipcode+"-"+zipcode_etx+", "+town);

}

@Override
public SearchListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_search_list_item,parent,false);
    // Passing the inflater job to the cursor-adapter
    return new SearchListAdapter.ViewHolder(itemView);
}

public void swapCursor(Cursor cursor) {
    Cursor old = changeCursor(cursor);
    if (old != null) {
        old.close();
    }
}

private Cursor changeCursor(Cursor newCursor) {
    if (newCursor == mCursor) {
        return null;
    }
    final Cursor oldCursor = mCursor;
    if (oldCursor != null && mDataSetObserver != null) {
        oldCursor.unregisterDataSetObserver(mDataSetObserver);
    }
    mCursor = newCursor;
    if (mCursor != null) {
        if (mDataSetObserver != null) {
            mCursor.registerDataSetObserver(mDataSetObserver);
        }
        mRowIdColumn = newCursor.getColumnIndexOrThrow("_id");
        mDataValid = true;
        notifyDataSetChanged();
    } else {
        mRowIdColumn = -1;
        mDataValid = false;
        notifyDataSetChanged();
    }
    return oldCursor;
}

private class NotifyingDataSetObserver extends DataSetObserver {
    @Override
    public void onChanged() {
        super.onChanged();
        mDataValid = true;
        notifyDataSetChanged();
    }

    @Override
    public void onInvalidated() {
        super.onInvalidated();
        mDataValid = false;
        notifyDataSetChanged();
    }
}


}

共有1个答案

徐秋月
2023-03-14

好吧,我发现了为什么会这样,原因很奇怪。这个问题与RecyclerView无关,而是与获取数据的方式有关。

在获取数据的AsyncTask中,我编写了log.d来打印光标大小,如下所示:

@Override
protected Void doInBackground(Void... Void) {
    if(type==Constants.GET_ZIP_CODES)
        cursor = db.getAllZipCodes();
    else
        cursor = db.searchZipCodes(text);

    Log.d("DATABASE","SIZE   "+cursor.getCount());
    return null;
}

这使得AsyncTask需要更长的时间,ProgressDialog需要更长的时间才能关闭。我理解的是,不知怎么的,数据库查询执行了,代码不断编译,但数据只是在光标中准备好了一段时间。当我在查询之后打印结果时,直到游标完全加载之后,结果才通过行。

 类似资料:
  • Activity中有一个RecyclerView,通过getGroupList()获取数据,这是一个异步方法。 适配器,通过setData方法更新数据,当调用setData()notifyDataSetChanged()时,抛出java。语言:addInArray 可丢弃信息: addInArray被调用,这=android。支持v7.widget。RecyclerView{4295f4f0 VF

  • 在我的主要活动中,我有三个循环利用的观点。 其中一个在底部工作表中,它是主要的(默认情况下,底部工作表是打开以显示这个),在其适配器的onbind方法中,我做了一个onClickListener,以便当用户单击其中的项目时,我想要, 我想回到主活动类来设置To Start一个方法,它的滚动是关闭底表并为下一个回收视图设置数据(当底表关闭时会出现) ......这里的问题是如何从onBind方法的L

  • 一切正常。但Logcat中显示了一些错误。 E/RecyclerView:未附加适配器;跳过布局 E/RecyclerView:未附加适配器;跳过布局 我的activity代码: 我读过与同一问题有关的其他问题,但都没有帮助。请帮帮我

  • 我是kotlin android的新手。我已经创建了回收站视图的适配器。但是我不能为每个回收站视图项目执行单击事件。我需要参考代码的解释。请帮我做这件事。提前谢谢。这是我的代码供您参考。

  • 本文向大家介绍Android实现的RecyclerView适配器,包括了Android实现的RecyclerView适配器的使用技巧和注意事项,需要的朋友参考一下 这个适配器我珍藏已久(近两年), 不断看到别人发适配器相关的文章, 但我总觉得没我的好用, 所以今日拿出来分享(宣传)一下, 欢迎各位指正不足. 源码地址: GitHub 功能 无需继承 Adapter, 无需判断 item 类型. 支

  • 我正尝试使用实现的适配器,如下所示,正如这里的解决方案之一所建议的。