第二十个项目——使用CursorAdapter进行数据绑定及渲染

实验目的

  • 掌握CursorAdapter进行数据绑定渲染的方法;

实验要求

  • 掌握使用CursorAdapter进行数据绑定渲染的方法;

实验内容

第九个项目中,我们实现了通过读取SQLite数据库读取新闻列表数据,通过遍历查询数据集Cursor对象构造NewsAdapter所需的数据列表。这样的操作方式显得较为繁琐及低效,在本次实验中我们将使用CursorAdapter适配器类用于ListView列表控件显示数据的绑定及渲染操作,CursorAdapter所需要的数据源则是Cursor类型,这可避免由于遍历查询数据集Cursor对象所带来的时间消耗,此外也可适用于从Content Provider组件而来的数据绑定渲染操作。

在实验过程中,我们将子类化CursorAdapter,并重写其抽象方法onBindView()newView()实现数据绑定。

步骤一,打开第九个项目

打开第九个项目,在该项目基础上完成本次实验。

步骤二,定义NewsCursorAdapter类

Android Studio中新建一个名为NewsCursorAdapter的Java类,该类继承至CursorAdapterCursorAdapter继承至BaseAdapter)。与ArrayAdatper类中需要重写getView()方法相比, CursorAdapter的使用略为复杂。在该类中,有两个方法需要进行重写,分别是newView()onBindView()方法。这两个方法在CursorAdapter绑定的ListView控件显示新Item或重新绑定Item数据时被回调。

1. 定义NewsCursorAdapter构造函数

NewsCursorAdapter类中构造方法需要调用基类的构造函数,可以使用CursorAdapter(Context context, Cursor cursor, int flags)该方法第一个参数为Context上下文对象,第二个参数为Cursor对象,第三个参数为标志位。

NewsCursorAdapter构造函数调用基类构造函数时,第二个参数传递null,第三个参数传递0,参数的含义暂时不做解释。

2. 定义ViewHoder内部类

第九个项目类似,需要定义NewsCursorAdapter内部类ViewHoder,其用法与第九个项目相同。

3. 重写newView()方法

newView()方法的三个参数:

  • Context context,上下文对象;

  • Cursor cursor,游标对象,即CursorAdapter绑定的游标对象,

    并且该游标对象已经移动到与当前Item序号对应的数据行上,可直接读取数据;

  • ViewGroup viewGroup,加载Item布局对应的父容器;

因此newView()方法的代码尤为简单,首先通过LayoutInflater加载所需的布局;其次实例化ViewHolder对象,绑定所加载布局对应的UI控件,最后返回加载好的布局对象即可;在本例中第二个参数Cursor并未使用,实际项目中可需要引用Cursor(例如根据行号加载不同布局等)。

4. 重写onBindView()方法

onBindView()方法的三个参数:

  • View view,需要重新绑定数据的Item布局根容器对象;

  • Context context,上下文对象;

  • Cursor cursor,游标对象,与newView()第二个参数相同,可直接通过Cursor提供的方法读取数据;

onBindView()方法的逻辑,首先通过getTag()方法从view布局根容器对象获取ViewHolder对象;其次通过cursor对象获取到所需的数据;最后将获取到的数据更新至ViewHolder对象绑定的UI控件上,完成数据绑定操作。

以下是NewsCursorAdapter类的定义。

public class NewsCursorAdapter extends CursorAdapter {

    private Context mContext;
    private LayoutInflater mInflater;

    public NewsCursorAdapter(Context context) {
        super(context, null, 0);
        mContext = context;

        mInflater = LayoutInflater.from(context);
    }

    @Override
    public View newView(Context context, 
                        Cursor cursor, ViewGroup viewGroup) {
        final View itemView =
                mInflater.inflate(
                        R.layout.list_item,
                        viewGroup,
                        false
                );

        final  ViewHolder holder = new ViewHolder();
        holder.tvTitle = itemView.findViewById(R.id.tv_title);
        holder.tvAuthor = itemView.findViewById(R.id.tv_subtitle);
        holder.ivImage = itemView.findViewById(R.id.iv_image);
        holder.ivDelete = itemView.findViewById(R.id.iv_delete);

        itemView.setTag(holder);

        return itemView;
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        final ViewHolder holder = (ViewHolder) view.getTag();

        final String title = cursor.getString(
                cursor.getColumnIndex(
                      NewsContract.NewsEntry.COLUMN_NAME_TITLE));

        final String author = cursor.getString(
                cursor.getColumnIndex(
                      NewsContract.NewsEntry.COLUMN_NAME_AUTHOR));

        final String imageResource = cursor.getString(
                cursor.getColumnIndex(
                      NewsContract.NewsEntry.COLUMN_NAME_IMAGE));

        Integer id = cursor.getInt(
                cursor.getColumnIndex(
                      NewsContract.NewsEntry._ID));

        holder.tvTitle.setText(title);
        holder.tvAuthor.setText(author);

        Bitmap bitmap = BitmapFactory.decodeStream(
            getClass().getResourceAsStream("/" + imageResource));
        holder.ivImage.setImageBitmap(bitmap);
    }

    class ViewHolder {
        TextView tvTitle;
        TextView tvAuthor;
        ImageView ivImage;
    }
}

步骤三,在MainActivity中初始化NewsCursorAdapter

MainActivity中初始化NewsCursorAdapter,首先通过MyDbOpenHelper.getReadableDatabase()方法 获得SQLiteDatabase对象,在此基础上通过query()方法查询得到指向结果数据集的Cursor游标对象;其次实例化 NewsCursorAdapter对象,并通过其基类CursorAdapter所提供的swapCursor()方法实现切换Cursor对象;最后通过ListViewsetAdapter()方法绑定NewsCursorAdapter对象,完成ListView控件与 CursorAdapter对象绑定操作。

相比于第九个项目中从数据库中读取数据后进行ListView显示新闻列表的初始化方式,本实验中的初始化方式更加简洁便于维护。

public class MainActivity extends AppCompatActivity {
    ...

    private MyDbOpenHelper myDbHelper = null;
    private SQLiteDatabase db = null;
    private CursorAdapter cursorAdapter =null;
    private ListView lvNewsList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        lvNewsList = findViewById(R.id.lv_news_list);
        initData();

        myDbHelper = new MyDbOpenHelper(MainActivity.this);
        db = myDbHelper.getReadableDatabase();
        Cursor cursor = db.query(
                NewsContract.NewsEntry.TABLE_NAME,
                null,
                null,
                null,
                null,
                null,
                null
        );

        cursorAdapter = new NewsCursorAdapter(MainActivity.this);
        cursorAdapter.swapCursor(cursor);
        lvNewsList.setAdapter(cursorAdapter);
        ...
    }
    ...
}

步骤四,编译并运行App

编译本项目,成功后在AVD上或物理机上运行App,其运行效果与第九个项目相同。

实验小结

通过本次实验,你应该掌握了如下知识内容:

  • 使用CursorAdapter进行数据绑定渲染的方法;

Last updated

Was this helpful?