RecyclerView Adapters 系列(2):RecyclerView Cursor Adapter

1,865 阅读2分钟
原文链接: android.jobbole.com

在Android平台中,CursorAdapter[3]是一个适配器,用来把Cursor[4]对象的数据展示到ListView控件里。RecyclerView[5]适配器的第二篇将解释如何自己构造一个简单可重用的Cursor适配器,以及如何在你的应用中使用它。第三篇文章中,我将展示一个CursorAdapter类的更高级版本。

(相比于Android CursorAdapter,本例中用到的Cursor,不包含名为“_id”的列)

首先,我们创建一个抽象类RecyclerViewCursorAdapter,该类持有Cursor对象并实现一些RecyclerView.Adapter类需要的方法(例如getItemCount())。

而且,我们的适配器类将定义一个新的方法叫做onBindViewHolder(RecyclerView.ViewHolder, Cursor)。所以,你不需要每次获取Cursor对象来将数据绑定到ViewHolder。

我们还增加了一些帮助方法,例如:

  • swapCursor(Cursor):提供带数据集(dataset)的适配器。
  • getItem(int):获得Cursor对象,移动到正确的位置。
  • getCursor():获得Cursor对象。
import android.database.Cursor;
import android.support.v7.widget.RecyclerView;

public abstract class RecyclerViewCursorAdapter
        extends RecyclerView.Adapter
{
    private Cursor cursor;

    public void swapCursor(final Cursor cursor)
    {
        this.cursor = cursor;
        this.notifyDataSetChanged();
    }

    @Override
    public int getItemCount()
    {
        return this.cursor != null
                ? this.cursor.getCount()
                : 0;
    }

    public Cursor getItem(final int position)
    {
        if (this.cursor != null && !this.cursor.isClosed())
        {
            this.cursor.moveToPosition(position);
        }

        return this.cursor;
    }

    public Cursor getCursor()
    {
        return this.cursor;
    }

    @Override
    public final void onBindViewHolder(final VH holder, final int position)
    {
        final Cursor cursor = this.getItem(position);
        this.onBindViewHolder(holder, cursor);
    }

    public abstract void onBindViewHolder(final VH holder, final Cursor cursor);
}

实现这个抽象类并填充数据是相当简单的。

import android.content.Context;
import android.database.Cursor;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import butterknife.Bind;
import butterknife.ButterKnife;

public class SearchResultsCursorAdapter extends RecyclerViewCursorAdapter
    implements View.OnClickListener
{
    private final LayoutInflater layoutInflater;
    private OnItemClickListener onItemClickListener;

    public SearchResultsCursorAdapter(final Context context)
    {
        super();

        this.layoutInflater = LayoutInflater.from(context);
    }

    public void setOnItemClickListener(final OnItemClickListener onItemClickListener)
    {
        this.onItemClickListener = onItemClickListener;
    }

    @Override
    public SearchResultViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType)
    {
        final View view = this.layoutInflater.inflate(R.layout.listitem_search, parent, false);
        view.setOnClickListener(this);

        return new SearchResultViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final SearchResultViewHolder holder, final Cursor cursor)
    {
        holder.bindData(cursor);
    }

     /*
     * View.OnClickListener
     */

    @Override
    public void onClick(final View view)
    {
        if (this.onItemClickListener != null)
        {
            final RecyclerView recyclerView = (RecyclerView) view.getParent();
            final int position = recyclerView.getChildLayoutPosition(view);
            if (position != RecyclerView.NO_POSITION)
            {
                final Cursor cursor = this.getItem(position);
                this.onItemClickListener.onItemClicked(cursor);
            }
        }
    }

    public static class SearchResultViewHolder extends RecyclerView.ViewHolder
    {
        @Bind(R.id.textview_name)
        TextView textViewName;

        public SearchResultViewHolder(final View itemView)
        {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }

        public void bindData(final Cursor cursor)
        {
            final String name = cursor.getString(cursor.getColumnIndex("name"));
            this.textViewName.setText(name);
        }
    }

    public interface OnItemClickListener
    {
        void onItemClicked(Cursor cursor);
    }
}

Providing the adapter with data in your Activity / Fragment:

在Activity或Fragment中提供带数据的适配器:

import android.app.Activity;
import android.app.LoaderManager;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;

public class SearchActivity extends Activity implements LoaderManager.LoaderCallbacks
{
    private static final int LOADER_SEARCH_RESULTS = 1;

    private SearchResultsCursorAdapter adapter;

    @Override
    protected void onCreate(final Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // create adapter
        this.adapter = new SearchResultsCursorAdapter(this);

        // start loader
        this.getLoaderManager().restartLoader(LOADER_SEARCH_RESULTS, null, this);
    }

    @Override
    public Loader onCreateLoader(final int id, final Bundle args)
    {
        switch (id)
        {
            case LOADER_SEARCH_RESULTS:

                final Uri uri = Uri.parse("content://some_uri");
                return new CursorLoader(this, uri, null, null, null, null);
        }

        return null;
    }

    @Override
    public void onLoadFinished(final Loader loader, final Cursor data)
    {
        switch (loader.getId())
        {
            case LOADER_SEARCH_RESULTS:

                this.adapter.swapCursor(data);
                break;
        }
    }

    @Override
    public void onLoaderReset(final Loader loader)
    {
        switch (loader.getId())
        {
            case LOADER_SEARCH_RESULTS:

                this.adapter.swapCursor(null);
                break;
        }
    }
}

1 赞

关于作者:lihenair[6]

码农一个爱喷爱足球爱生活 个人主页[7] · 我的文章[8] · 10[9] ·