sqlite Recyclerview +内容提供程序+ CursorLoader

s8vozzvw  于 2023-08-06  发布在  SQLite
关注(0)|答案(4)|浏览(100)

我在SQLite数据库中有一些数据。我有一个内容提供程序,它将从数据库中获取数据。现在的问题是我如何实现cursorLoader与recyclerview一起工作?
还有,谁能解释一下为什么我们需要将数据从光标转移到一个对象,以显示在一个列表视图/回收视图中,而不是直接从光标?
例如,在自定义cursorAdapter类中,

Person person = new Person(cursor.getString(cursor.getColumnIndexOrThrow(PERSON_NAME)));
textview.setText = person.getName();

字符串

textview.setText = cursor.getString(cursor.getColumnIndexOrThrow(PERSON_NAME));


以上哪一种方法比较好?
在过去,我们曾经有listview和gridview,现在它们似乎合并成了recyclerview。那么,我如何实现一个基于网格的recyclerview?

l3zydbqr

l3zydbqr1#

一般来说,您应该尝试分离视图和数据职责。因此,您需要提前从数据库中获取所有对象,然后设置一个Adapter,如下所示:

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
    private final List<Person> objectList = new ArrayList<>();

    @Override
    public CustomAdapter.ViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
        final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
        return new ViewHolder(layoutInflater.inflate(R.layout.adapter_item, parent, false));
    }

    @Override
    public void onBindViewHolder(final CustomAdapter.ViewHolder holder, final int position) {
        holder.bindItem(objectList.get(position));
    }

    // Set the persons for your adapter
    public void setItems(final List<Person> persons) {
        objectList.addAll(persons);
        notifyDataSetChanged();
    }

    @Override
    public int getItemCount() {
        return objectList.size();
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        private final TextView mTextViewTitle;
        private Object mObject;

        public ViewHolder(final View itemView) {
            super(itemView);
            mTextViewTitle = (TextView) itemView.findViewById(R.id.view_item_textViewTitle);                
            mTextViewTitle.setText(mObject.getText());
        }

        private void bindItem(@NonNull final Person object) {
            mObject = object;
        }
    }
}

字符串
然后,您可以通过以下方式将适配器绑定到RecyclerView:

final CustomAdapter adapter = new CustomAdapter();
adapter.setItems(mPersons);
mRecyclerView.setAdapter();


为了回答你的第二个问题(“在过去,我们曾经有列表视图和网格视图,现在似乎它们合并成了回收视图。那么,我如何实现一个基于网格的recyclerview?“):
将LayoutManager绑定到RecyclerView时,您可以决定使用哪一个:

final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(layoutManager);


或者是

final GridLayoutManager layoutManager = new GridLayoutManager(this, COLUMN_SPAN_COUNT);
mRecyclerView.setLayoutManager(layoutManager);


有几个LayoutManager。了解更多here .
UPDATE:您不必提前加载所有项,只需将setItems重命名为addItems,就可以开始了

1wnzp6jl

1wnzp6jl2#

有几个Github gist/项目,如thisthis,展示了这样的用例。
虽然您将使用一个为游标适配器定制的Adapter,但您将像往常一样使用GridLayoutManager/LinearLayoutManager。

9gm1akwq

9gm1akwq3#

我觉得你可以直接使用Custom**CursorAdapterRecyclerView,这样就不用把Cursor转换成ArrayList**了:

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

    // Because RecyclerView.Adapter in its current form doesn't natively 
    // support cursors, we wrap a CursorAdapter that will do all the job
    // for us.
    CursorAdapter mCursorAdapter;

    Activity mContext;
    Random rnd;

    public ProductListAdapter(AppCompatActivity context, Cursor c) {

        mContext = context;
        rnd = new Random();

        mCursorAdapter = new CursorAdapter(mContext, c, 0) {

            @Override
            public View newView(Context context, Cursor cursor, ViewGroup parent) {
                // Inflate the view here
                LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
                return inflater.inflate(R.layout.row_product_layout_grid, parent, false);
            }

            @Override
            public void bindView(View view, Context context, Cursor cursor) {
                String productName = cursor.getString(cursor.getColumnIndex(TProduct.PRODUCT_NAME));

                // Binding operations
                ((TextView) view.findViewById(R.id.sub_product_name_text_view)).setText(productName);


                int color = Color.argb(200, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));

                String url = "http://dummyimage.com/300/" + color + "/ffffff&text=" + (cursor.getPosition() + 1);

                Picasso
                        .with(context)
                        .load(url)
                        .placeholder(R.mipmap.ic_launcher) // can also be a drawable
                        .into((ImageView) view.findViewById(R.id.sub_product_image_view));
            }
        };
    }

    public void reQuery(Cursor c) {
        if (mCursorAdapter != null) {
            mCursorAdapter.changeCursor(c);
            mCursorAdapter.notifyDataSetChanged();
        }
    }

    @Override
    public int getItemCount() {
        return mCursorAdapter.getCount();
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        // Passing the binding operation to cursor loader
        mCursorAdapter.getCursor().moveToPosition(position); //EDITED: added this line as suggested in the comments below, thanks :)
        mCursorAdapter.bindView(holder.view, mContext, mCursorAdapter.getCursor());
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // Passing the inflater job to the cursor-adapter
        View v = mCursorAdapter.newView(mContext, mCursorAdapter.getCursor(), parent);
        return new ViewHolder(v);
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        View view;
        public ViewHolder(View itemView) {
            super(itemView);
            view = itemView.findViewById(R.id.product_row_card_view);
        }
    }
}

字符串
希望它对你有用。:)

jvlzgdj9

jvlzgdj94#

使用RecyclerView显示使用CursorLoader从ContentProvider获取的联系人列表。

1. ShowContactBook类其中显示回收器视图

public class ShowContactBook extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>{

private static final String TAG = MainActivity.class.getSimpleName();
private static final int TASK_LOADER_ID = 0;

private CustomCursorAdapter mAdapter;
RecyclerView mRecyclerView;

Toolbar toolbar;

CollapsingToolbarLayout collapsingToolbarLayout;

TextView textViewTotalContacts;

SearchView searchView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_show_contact_book);

    collapsingToolbarLayout = findViewById(R.id.collapsing_toolbar);
    toolbar = findViewById(R.id.toolbar);
    textViewTotalContacts = findViewById(R.id.total_contacts);
    searchView=findViewById(R.id.search);

    setSupportActionBar(toolbar);

    int color = ContextCompat.getColor(this, R.color.black);
    Drawable icon = AppCompatResources.getDrawable(this, R.drawable.arrow_back_24);
    if (icon != null) {
        icon = DrawableCompat.wrap(icon);
        DrawableCompat.setTint(icon, color);
        toolbar.setNavigationIcon(icon);
    }

    toolbar.setNavigationOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            onBackPressed();
        }
    });

    collapsingToolbarLayout.setTitle("Contacts");

    mRecyclerView = findViewById(R.id.list);

    mRecyclerView.setLayoutManager(new LinearLayoutManager(this));

    mAdapter = new CustomCursorAdapter(this);
    mRecyclerView.setAdapter(mAdapter);
    
    /*
     Add a touch helper to the RecyclerView to 
     recognize when a user swipes to delete an 
     item. An ItemTouchHelper enables touch 
     behavior (like swipe and move) on each 
     ViewHolder,and uses callbacks to signal when 
     a user is performing these actions.
     */

    new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
        @Override
        public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
            return false;
        }

        //* Called when a user swipes left or right on a ViewHolder*/

        @Override
        public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
            //* Here is where you'll implement swipe to delete*/

            int id = (int) viewHolder.itemView.getTag();

            String stringId = Integer.toString(id);
            Uri uri = ContactBookContract.contactEntry.CONTENT_URI;
            uri = uri.buildUpon().appendPath(stringId).build();

            /* or
            // Build the URI directly without converting the id to a string
            Uri uri = ContentUris.withAppendedId(TaskContract.TaskEntry.CONTENT_URI, id);
            */

            getContentResolver().delete(uri, null, null);

            getSupportLoaderManager().restartLoader(TASK_LOADER_ID, null, ShowContactBook.this);
        }
    }).attachToRecyclerView(mRecyclerView);


    mAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
        @Override
        public void onChanged() {
            super.onChanged();
            showItemCount();
        }

        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
            super.onItemRangeInserted(positionStart, itemCount);
            showItemCount();
        }

        @Override
        public void onItemRangeRemoved(int positionStart, int itemCount) {
            super.onItemRangeRemoved(positionStart, itemCount);
            showItemCount();
        }
    });

    searchView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            searchView.setIconified(false);
            Toast.makeText(ShowContactBook.this, "Searching", Toast.LENGTH_SHORT).show();
        }
    });

    /*
     Ensure a loader is initialized and active. If the loader doesn't already exist, one is
     created, otherwise the last created loader is re-used.
     */
    getSupportLoaderManager().initLoader(TASK_LOADER_ID, null, this);

}

private void showItemCount() {

    int count = mAdapter.getItemCount();
    String message = count + " Contacts";
    textViewTotalContacts.setText(message);
}

@Override
protected void onResume() {
    super.onResume();
    getSupportLoaderManager().restartLoader(TASK_LOADER_ID, null, ShowContactBook.this);
}

@SuppressLint("StaticFieldLeak")
@NonNull
@Override
public Loader<Cursor> onCreateLoader(int id, @Nullable Bundle args) {
    return new AsyncTaskLoader<Cursor>(this) {

        Cursor mTaskData = null;

        @Override
        protected void onStartLoading() {
            if (mTaskData != null) {

                deliverResult(mTaskData);
            } else {
                forceLoad();
            }
        }

        @Override
        public Cursor loadInBackground() {

            try {
                return getContentResolver().query(ContactBookContract.contactEntry.CONTENT_URI,
                        null,
                        null,
                        null,
                        ContactBookContract.contactEntry._ID + " DESC");

            } catch (Exception e) {
                Log.e(TAG, "Failed to asynchronously load data.");
                e.printStackTrace();
                return null;
            }
        }

        public void deliverResult(Cursor data) {
            mTaskData = data;
            super.deliverResult(data);
        }
    };
}

/**
 * Called when a previously created loader has finished its load.
 *
 * @param loader The Loader that has finished.
 * @param data   The data generated by the Loader.
 */

@Override
public void onLoadFinished(@NonNull Loader<Cursor> loader, Cursor data) {
    // Update the data that the adapter uses to create ViewHolders
    mAdapter.swapCursor(data);
}

/**
 * Called when a previously created loader is being reset, and thus
 * making its data unavailable.
 * onLoaderReset removes any references this activity had to the loader's data.
 *
 * @param loader The Loader that is being reset.
 */

@Override
public void onLoaderReset(@NonNull Loader<Cursor> loader) {
    mAdapter.swapCursor(null);
}

@Override
public void onBackPressed() {
    super.onBackPressed();
}

字符串
}

**1. CustomCursorAdapter类:**CustomCursorAdapter类是RecyclerView.Adapter的自定义实现,用于在RecyclerView中显示Cursor中的数据。在所提供的代码的上下文中,此适配器用于显示从ContentProvider获取的联系人列表。

public class CustomCursorAdapter extends RecyclerView.Adapter<CustomCursorAdapter.TaskViewHolder> {
private Cursor cursor;
private Context mContext;

/**
 * Constructor for the CustomCursorAdapter that initializes the Context.
 *
 * @param mContext the current Context
 */

public CustomCursorAdapter(Context mContext) {
    this.mContext = mContext;
}

/**
 * Called when ViewHolders are created to fill a RecyclerView.
 *
 * @return A new TaskViewHolder that holds the view for each task
 */

@Override
public TaskViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    View view = LayoutInflater.from(mContext)
            .inflate(R.layout.list_view, parent, false);

    return new TaskViewHolder(view);
}

/**
 * Called by the RecyclerView to display data at a specified position in the Cursor.
 *
 * @param holder   The ViewHolder to bind Cursor data to
 * @param position The position of the data in the Cursor
 */

@Override
public void onBindViewHolder(TaskViewHolder holder, int position) {

    int idIndex = cursor.getColumnIndex(ContactBookContract.contactEntry._ID);
    int nameColumnIndex = cursor.getColumnIndex(ContactBookContract.contactEntry.COLUMN_CONTACT_NAME);
    int phColumnIndex = cursor.getColumnIndex(ContactBookContract.contactEntry.COLUMN_CONTACT_PH);
    int emailColumnIndex = cursor.getColumnIndex(ContactBookContract.contactEntry.COLUMN_CONTACT_EMAIL);
    int imageColumnIndex = cursor.getColumnIndex(ContactBookContract.contactEntry.COLUMN_CONTACT_IMAGE);

    cursor.moveToPosition(position); 

    final int id = cursor.getInt(idIndex);
    String name = cursor.getString(nameColumnIndex);
    String ph = cursor.getString(phColumnIndex);
    String email = cursor.getString(emailColumnIndex);

    //* Extract the image byte array from the cursor*/
    byte[] imageByteArray = cursor.getBlob(imageColumnIndex);

    //* Convert byte array back to Bitmap*/
    Bitmap bitmap = BitmapFactory.decodeByteArray(imageByteArray, 0, imageByteArray.length);

    holder.itemView.setTag(id);
    holder.nameTextView.setText(name);
    holder.circleImageView.setImageBitmap(bitmap);

    holder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            int id = (int) holder.itemView.getTag();
            Uri uri = ContentUris.withAppendedId(ContactBookContract.contactEntry.CONTENT_URI, id);
          
            Toast.makeText(mContext, "" + uri.toString() + " : " + name, Toast.LENGTH_SHORT).show();
            Intent intent = new Intent(mContext, ContactDetail.class);
           
            intent.setData(uri);
            mContext.startActivity(intent);

            applyTemporaryHoverEffect(holder.itemView);
        }
    });
}

private void applyTemporaryHoverEffect(View view) {
    final int originalBackgroundColor = view.getSolidColor();
    final int hoverColor = ContextCompat.getColor(mContext, R.color.hoverColor);
    final int duration = 100; 
    view.setBackgroundColor(hoverColor);
    
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            view.setBackgroundColor(originalBackgroundColor);
        }
    }, duration);
}

/**
 * Returns the number of items to display.
 */

@Override
public int getItemCount() {
    if (cursor == null) {
        return 0;
    }
    return cursor.getCount();
}

/**
 * When data changes and a re-query occurs, this function swaps the old Cursor
 * with a newly updated Cursor (Cursor c) that is passed in.
 */

public Cursor swapCursor(Cursor c) {
    // check if this cursor is the same as the previous cursor (mCursor)
    if (cursor == c) {
        return null;
    }
    Cursor temp = cursor;
    this.cursor = c;

    if (c != null) {
        this.notifyDataSetChanged();
    }
    return temp;
}

//* Inner class for creating ViewHolders*/
class TaskViewHolder extends RecyclerView.ViewHolder {

    TextView nameTextView;
    CircleImageView circleImageView;

    /**
     * Constructor for the TaskViewHolders.
     *
     * @param itemView The view inflated in onCreateViewHolder
     */

    public TaskViewHolder(View itemView) {
        super(itemView);
        nameTextView = (TextView) itemView.findViewById(R.id.name);
        circleImageView = (CircleImageView) itemView.findViewById(R.id.list_imageView);
    }
}


}

相关问题