Sử dụng recyclerview với cơ sở dữ liệu


127

Hiện tại không có triển khai mặc định của RecyclerView.Ad CHƯƠNG.

Có thể với bản phát hành chính thức, Google sẽ thêm nó.

Vì hiện tại không có hỗ trợ cho CursorAdapterviệc này RecyclerView, làm thế nào chúng ta có thể sử dụng RecyclerViewmột cơ sở dữ liệu? Bất kỳ đề xuất ?

Câu trả lời:


101

Nếu bạn đang chạy một truy vấn với một CursorLoadervà bạn muốn RecyclerViewthay vì ListView.

Bạn có thể dùng thử CursorRecyclerViewAdapter: CthonAd CHƯƠNG trong RecyclerView


12
Mã này hoạt động nhưng không phải là hình ảnh động khi xóa và chèn bởi vì phương thức registerDataSetObserver của lớp Con trỏ không xác định chính xác phần tử nào đã thay đổi. Vì vậy, mỗi khi nhà cung cấp nội dung thay đổi, recyclerview được tải hoàn toàn thông qua notifyDataSetChanged và đây là bản chất của RecyclerView.
francas

1
Điều gì sẽ là nhược điểm của việc chuyển con trỏ đến bộ điều hợp thông qua hàm tạo và chỉ sử dụng con trỏ.moveToP vị trí () trong onBindViewHolder (), để lấy dữ liệu liên quan?
Gautam

2
Gợi ý: Gọi exchangeCoder () từ nhà xây dựng, do đó bạn không phải lặp lại chính mình ở đó
Greg Enni

2
@francas Ảnh động làm việc tốt nếu bạn thiết lậpsetHasStableIds(true)
Alders

2
@alder bạn đã thực hiện bất kỳ thay đổi nào khác ngoài setHasTableIds chưa? Tôi cũng đã thử điều đó, ID trùng khớp và mỗi khi tôi trao đổi con trỏ, danh sách sẽ trở về đầu trang.
dwbrito

89

Giải pháp của tôi là giữ một thành viên CthonAd CHƯƠNG trong triển khai recyclerView.Ad CHƯƠNG của tôi. Sau đó chuyển tất cả xử lý tạo chế độ xem mới và liên kết nó với bộ điều hợp con trỏ, đại loại như thế này:

public class MyRecyclerAdapter extends Adapter<MyRecyclerAdapter.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;

    Context mContext;

    public MyRecyclerAdapter(Context context, Cursor c) {

        mContext = context;

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

            @Override
            public View newView(Context context, Cursor cursor, ViewGroup parent) {
                // Inflate the view here
            }

            @Override
            public void bindView(View view, Context context, Cursor cursor) {
                // Binding operations
            }
        };
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        View v1;

        public ViewHolder(View itemView) {
            super(itemView);
            v1 = itemView.findViewById(R.id.v1);
        }
    }

    @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.itemView, 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);
    }
}

17
Cảm ơn giải pháp này, nó hoạt động với tôi, tôi chỉ cần thêm một dòng vào onBindViewHolder: 'mCthonAd Module.getCthon (). MoveToP vị trí (vị trí)' trước khi gọi bindView () trên mC bổngAd Module
user1071762

8
@nbtk Tại sao không giữ Con trỏ thay vì Con trỏ? Theo tôi hiểu, bạn không sử dụng bất kỳ khả năng nào của CthonAd CHƯƠNG.
MyDogTom

14
@MyDogTom - Tôi không giữ Con trỏ, vì bạn cần xóa nó khi bạn hoàn thành và đặt nó thành NULL là không đủ. CthonAd CHƯƠNG chăm sóc điều này một cách hoàn hảo.
nbtk

3
@nbtk Tôi thực sự thích ý tưởng này, và tôi đã chơi với nó từ đó. Tôi đã thử trừu tượng hóa nó một chút và xây dựng một thư viện, đó không phải là 100% nơi tôi muốn nhưng nó đã hoàn thành công việc. Bạn sẽ quan tâm đến việc kiểm tra nó? Nếu bạn có một github, tôi sẽ vui lòng tin tưởng bạn với cảm hứng. github.com/androidessence/RecyclerViewCoderAdOG
AdamMc331

5
@nbtk Thực hiện các thao tác sau để làm mới chế độ xem của bạn với dữ liệu mới:public void changeCursor(Cursor cursor){ mCursorAdapter.changeCursor(cursor); notifyDataSetChanged(); }
Cijo

48

Vì câu hỏi của bạn nói "Cách sử dụng RecyclerViewvới cơ sở dữ liệu" và bạn không cụ thể cho dù bạn muốn SQLite hay bất cứ điều gì khác với RecyclerView, tôi sẽ cung cấp cho bạn một giải pháp tối ưu cao. Tôi sẽ sử dụng Realm làm cơ sở dữ liệu và cho phép bạn hiển thị tất cả dữ liệu bên trong RecyclerView. Nó cũng có hỗ trợ truy vấn không đồng bộ mà không cần sử dụng Loadershoặc AsyncTask.

Tại sao cảnh giới? hiệu suất thực tế của Android

Bước 1

Thêm phụ thuộc lớp cho Realm, phụ thuộc cho phiên bản mới nhất được tìm thấy ở đây

Bước 2

Ví dụ, tạo lớp mô hình của bạn, giả sử một cái gì đó đơn giản như Datacó 2 trường, một chuỗi được hiển thị bên trong RecyclerViewhàng và dấu thời gian sẽ được sử dụng làm itemId để cho phép các RecyclerViewmục động. Lưu ý rằng tôi mở rộng RealmObjectbên dưới vì Datalớp này sẽ được lưu dưới dạng bảng và tất cả các thuộc tính của bạn sẽ được lưu dưới dạng cột của bảng đó Data. Tôi đã đánh dấu văn bản dữ liệu là khóa chính trong trường hợp của mình vì tôi không muốn một chuỗi được thêm nhiều lần. Nhưng nếu bạn muốn có các bản sao, thì hãy tạo dấu thời gian là @PrimaryKey. Bạn có thể có một bảng không có khóa chính nhưng nó sẽ gây ra vấn đề nếu bạn thử cập nhật hàng sau khi tạo nó. Khóa chính tổng hợp tại thời điểm viết câu trả lời này không được Realm hỗ trợ.

import io.realm.RealmObject;
import io.realm.annotations.PrimaryKey;

public class Data extends RealmObject {
@PrimaryKey
private String data;

//The time when this item was added to the database
private long timestamp;

public String getData() {
    return data;
}

public void setData(String data) {
    this.data = data;
}

public long getTimestamp() {
    return timestamp;
}

public void setTimestamp(long timestamp) {
    this.timestamp = timestamp;
}
}

Bước 3

Tạo bố cục của bạn cho cách một hàng đơn sẽ xuất hiện bên trong RecyclerView. Bố cục cho một mục hàng bên trong của chúng tôi Adapternhư sau

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

<TextView
    android:id="@+id/area"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:background="@android:color/white"
    android:padding="16dp"
    android:text="Data"
    android:visibility="visible" />

</FrameLayout>

Lưu ý rằng tôi đã giữ một FrameLayoutroot như mặc dù tôi có một TextViewbên trong. Tôi dự định thêm nhiều mục trong bố cục này và từ đó làm cho nó linh hoạt ngay bây giờ :)

Đối với những người tò mò ngoài kia, đây là cách một mặt hàng duy nhất hiện tại. bố trí hàng đơn mục bên trong RecyclerView

Bước 4

Tạo RecyclerView.Adaptertriển khai của bạn . Trong trường hợp này, đối tượng nguồn dữ liệu là một đối tượng đặc biệt được gọi RealmResultslà về cơ bản là TRỰC TIẾP ArrayList, nói cách khác, khi các mục được thêm hoặc xóa khỏi bảng của bạn, RealmResultsđối tượng này sẽ tự động cập nhật.

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

import io.realm.Realm;
import io.realm.RealmResults;
import slidenerd.vivz.realmrecycler.R;
import slidenerd.vivz.realmrecycler.model.Data;

public class DataAdapter extends RecyclerView.Adapter<DataAdapter.DataHolder> {
private LayoutInflater mInflater;
private Realm mRealm;
private RealmResults<Data> mResults;

public DataAdapter(Context context, Realm realm, RealmResults<Data> results) {
    mRealm = realm;
    mInflater = LayoutInflater.from(context);
    setResults(results);
}

public Data getItem(int position) {
    return mResults.get(position);
}

@Override
public DataHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = mInflater.inflate(R.layout.row_data, parent, false);
    DataHolder dataHolder = new DataHolder(view);
    return dataHolder;
}

@Override
public void onBindViewHolder(DataHolder holder, int position) {
    Data data = mResults.get(position);
    holder.setData(data.getData());
}

public void setResults(RealmResults<Data> results) {
    mResults = results;
    notifyDataSetChanged();
}

@Override
public long getItemId(int position) {
    return mResults.get(position).getTimestamp();
}

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

public void add(String text) {

    //Create a new object that contains the data we want to add
    Data data = new Data();
    data.setData(text);

    //Set the timestamp of creation of this object as the current time
    data.setTimestamp(System.currentTimeMillis());

    //Start a transaction
    mRealm.beginTransaction();

    //Copy or update the object if it already exists, update is possible only if your table has a primary key
    mRealm.copyToRealmOrUpdate(data);

    //Commit the transaction
    mRealm.commitTransaction();

    //Tell the Adapter to update what it shows.
    notifyDataSetChanged();
}

public void remove(int position) {

    //Start a transaction
    mRealm.beginTransaction();

    //Remove the item from the desired position
    mResults.remove(position);

    //Commit the transaction
    mRealm.commitTransaction();

    //Tell the Adapter to update what it shows
    notifyItemRemoved(position);
}

public static class DataHolder extends RecyclerView.ViewHolder {
    TextView area;

    public DataHolder(View itemView) {
        super(itemView);
        area = (TextView) itemView.findViewById(R.id.area);
    }

    public void setData(String text) {
        area.setText(text);
    }
}
}

Lưu ý rằng tôi đang gọi notifyItemRemovedvới vị trí mà việc xóa xảy ra nhưng tôi KHÔNG gọi notifyItemInsertedhoặc notifyItemRangeChangedvì không có cách nào trực tiếp để biết vị trí của mục được chèn vào cơ sở dữ liệu vì các mục Realm không được lưu theo kiểu được đặt hàng. Đối RealmResultstượng tự động cập nhật bất cứ khi nào một mục mới được thêm, sửa đổi hoặc xóa khỏi cơ sở dữ liệu để chúng tôi gọi notifyDataSetChangedtrong khi thêm và chèn các mục hàng loạt. Tại thời điểm này, có lẽ bạn lo ngại về các hình ảnh động sẽ không được kích hoạt bởi vì bạn đang gọi notifyDataSetChangedthay cho các notifyXXXphương thức. Đó chính xác là lý do tại sao tôi có getItemIdphương thức trả về dấu thời gian cho mỗi hàng từ đối tượng kết quả. Hoạt ảnh đạt được trong 2 bước với notifyDataSetChangednếu bạn gọi setHasStableIds(true)và sau đó ghi đègetItemId để cung cấp một cái gì đó ngoài vị trí.

Bước 5

Cho phép thêm RecyclerViewvào Activityhoặc của chúng tôi Fragment. Trong trường hợp của tôi, tôi đang sử dụng một Activity. Các tập tin bố trí có chứa RecyclerViewkhá tầm thường và sẽ trông giống như thế này.

<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/text_margin"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />

Tôi đã thêm một app:layout_behaviortừ khi tôi RecyclerViewđi vào bên trong CoordinatorLayoutmà tôi chưa đăng trong câu trả lời này cho ngắn gọn.

Bước 6

Xây dựng RecyclerViewmã trong và cung cấp dữ liệu cần thiết. Tạo và khởi tạo một đối tượng Realm bên trong onCreatevà đóng nó bên trong onDestroykhá giống như đóng một SQLiteOpenHelperthể hiện. Đơn giản nhất onCreatebên trong của bạn Activitysẽ trông như thế này. Các initUiphương pháp là nơi mà tất cả sự kỳ diệu xảy ra. Tôi mở một ví dụ của Realm bên trong onCreate.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mRealm = Realm.getInstance(this);
    initUi();
}

private void initUi() {

    //Asynchronous query
    RealmResults<Data> mResults = mRealm.where(Data.class).findAllSortedAsync("data");

    //Tell me when the results are loaded so that I can tell my Adapter to update what it shows
    mResults.addChangeListener(new RealmChangeListener() {
        @Override
        public void onChange() {
            mAdapter.notifyDataSetChanged();
            Toast.makeText(ActivityMain.this, "onChange triggered", Toast.LENGTH_SHORT).show();
        }
    });
    mRecycler = (RecyclerView) findViewById(R.id.recycler);
    mRecycler.setLayoutManager(new LinearLayoutManager(this));
    mAdapter = new DataAdapter(this, mRealm, mResults);

    //Set the Adapter to use timestamp as the item id for each row from our database
    mAdapter.setHasStableIds(true);
    mRecycler.setAdapter(mAdapter);
}

Lưu ý rằng trong bước đầu tiên, tôi truy vấn Realm để cung cấp cho tôi tất cả các đối tượng từ Datalớp được sắp xếp theo tên biến của chúng được gọi là dữ liệu theo cách không đồng bộ. Điều này mang lại cho tôi một RealmResultsđối tượng có 0 mục trên luồng chính mà tôi đang thiết lập trên Adapter. Tôi đã thêm một RealmChangeListenerthông báo khi dữ liệu đã tải xong từ luồng nền nơi tôi gọi notifyDataSetChangedvới Adapter. Tôi cũng đã gọi setHasStableIdsđúng để cho phép RecyclerView.Adaptertriển khai theo dõi các mục được thêm, xóa hoặc sửa đổi. Cái onDestroycủa tôi Activityđóng ví dụ Realm

@Override
protected void onDestroy() {
    super.onDestroy();
    mRealm.close();
}

Phương pháp này initUicó thể được gọi bên trong onCreatecủa bạn Activityhoặc onCreateViewhoặc onViewCreatedcủa bạn Fragment. Lưu ý những điều sau đây.

Bước 7

BAM! Có dữ liệu từ cơ sở dữ liệu bên trong của bạn RecyclerViewasynchonously nạp không CursorLoader, CursorAdapter, SQLiteOpenHelpervới hình ảnh động. Hình ảnh GIF hiển thị ở đây hơi lag nhưng hình ảnh động đang xảy ra khi bạn thêm các mục hoặc xóa chúng.

dữ liệu từ cơ sở dữ liệu bên trong RecyclerView


Cảm ơn đã cung cấp ví dụ toàn diện. Tôi có vài câu hỏi Tôi muốn lưu trữ bitmap trong lĩnh vực này là có thể? nếu có, loại cột sẽ là gì và làm thế nào để lưu trữ và truy xuất nó?
Rakesh

1
@Rakesh không bao giờ lưu trữ hình ảnh bên trong bất kỳ cơ sở dữ liệu nào, luôn lưu trữ nó trong hệ thống tệp của bạn và lưu trữ uri của hình ảnh trong cơ sở dữ liệu
PirateApp

Cảm ơn về sự phản hồi nhanh chóng. Tôi đang tạo một ứng dụng mà tôi muốn lưu trữ hình ảnh cho liên hệ của mình. Nếu tôi đang lưu trữ trên hệ thống tập tin thì có thể có hàng trăm hình ảnh. Làm thế nào tôi có thể quản lý những hình ảnh trên hệ thống tập tin?
Rakesh

9
FWIW, bao gồm một biểu đồ về hiệu suất của Realm khi chèn là không liên quan đến câu hỏi về tái chế (chắc chắn sẽ là về phục hồi)
JRaymond

Với thanh công cụ nói Vivz , đây có phải là giải pháp @slidenerd không?
SymbolixAU

1

Bạn có thể tự thực hiện tất cả các phương pháp cần thiết. Gần đây tôi đã thực hiện việc thực hiện của riêng mình bằng cách chỉ sao chép mã dán từ CthonAd CHƯƠNG.

public class MyAdapter extends RecyclerView.Adapter<ViewHolder> {

        protected boolean mDataValid;
        protected boolean mAutoRequery;
        protected Cursor mCursor;
        protected Context mContext;
        protected int mRowIDColumn;
        protected ChangeObserver mChangeObserver;
        protected DataSetObserver mDataSetObserver;
        protected FilterQueryProvider mFilterQueryProvider;
        public static final int FLAG_AUTO_REQUERY = 0x01;
        public static final int FLAG_REGISTER_CONTENT_OBSERVER = 0x02;

        public Cursor getCursor() {
            return mCursor;
        }

        //Recommended
        public MyAdapter(Context context, Cursor c, int flags) {
            init(context, c, flags);
        }

        public MyAdapter(Context context, Cursor c) {
            init(context, c, FLAG_AUTO_REQUERY);
        }

        public MyAdapter(Context context, Cursor c, boolean autoRequery) {
            init(context, c, autoRequery ? FLAG_AUTO_REQUERY : FLAG_REGISTER_CONTENT_OBSERVER);
        }

        void init(Context context, Cursor c, int flags) {
            if ((flags & FLAG_AUTO_REQUERY) == FLAG_AUTO_REQUERY) {
                flags |= FLAG_REGISTER_CONTENT_OBSERVER;
                mAutoRequery = true;
            } else {
                mAutoRequery = false;
            }
            boolean cursorPresent = c != null;
            mCursor = c;
            mDataValid = cursorPresent;
            mContext = context;
            mRowIDColumn = cursorPresent ? c.getColumnIndexOrThrow("_id") : -1;
            if ((flags & FLAG_REGISTER_CONTENT_OBSERVER) == FLAG_REGISTER_CONTENT_OBSERVER) {
                mChangeObserver = new ChangeObserver();
                mDataSetObserver = new MyDataSetObserver();
            } else {
                mChangeObserver = null;
                mDataSetObserver = null;
            }

            if (cursorPresent) {
                if (mChangeObserver != null) c.registerContentObserver(mChangeObserver);
                if (mDataSetObserver != null) c.registerDataSetObserver(mDataSetObserver);
            }
        }

        // Create new views (invoked by the layout manager)
        @Override
        public ViewHolder onCreateViewHolder(final ViewGroup parent,
                                             int viewType) {
            // create a new view
            final View view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.list_item, parent, false);
            // set the view's size, margins, paddings and layout parameters

            ViewHolder vh = new ViewHolder(view, mCursor, new ViewHolder.IMyViewHolderClicks() {

                @SuppressLint("NewApi")
                @Override
                public void onClick(Cursor cursor) {
                    Log.e("Item :", cursor.getString(cursor.getColumnIndex(MyDatabaseHelper.MW_NAAM)));
                    Intent intent = new Intent(TasksListFragment.this.getActivity(), DetailActivity.class);
                    intent.putExtra(DetailActivity.EXTRA_PARAM_ID, cursor.getLong(cursor.getColumnIndex(MyDatabaseHelper.MW_ID)));

                    ActivityOptions activityOptions = ActivityOptions.makeSceneTransitionAnimation(
                            TasksListFragment.this.getActivity(),

                            // Now we provide a list of Pair items which contain the view we can transitioning
                            // from, and the name of the view it is transitioning to, in the launched activity
                            new Pair<View, String>(
                                    view.findViewById(R.id.imageview_item),
                                    DetailActivity.VIEW_NAME_HEADER_IMAGE),
                            new Pair<View, String>(
                                    view.findViewById(R.id.textview_name),
                                    DetailActivity.VIEW_NAME_HEADER_TITLE)
                    );

                    // Now we can start the Activity, providing the activity options as a bundle
                    startActivity(intent, activityOptions.toBundle());
                    // END_INCLUDE(start_activity)
                }
            });
            return vh;
        }

        // Replace the contents of a view (invoked by the layout manager)
        @SuppressLint("NewApi")
        @Override
        public void onBindViewHolder(ViewHolder holder, int position) {
            // - get element from your dataset at this position
            // - replace the contents of the view with that element
            final Cursor cursor = getItem(position);

            holder.mTextView.setText(cursor.getString(cursor.getColumnIndex(MyDatabaseHelper.MW_NAAM)));
            holder.mImageView.setTransitionName("grid:image:" + cursor.getLong(cursor.getColumnIndex(MyDatabaseHelper.MW_ID)));
            holder.mTextView.setTransitionName("grid:name:" + cursor.getLong(cursor.getColumnIndex(MyDatabaseHelper.MW_ID)));
        }

        //@Override
        // public View getView(int position, View view, ViewGroup viewGroup) {
        //     return view;
        // }

        // Return the size of your dataset (invoked by the layout manager)
        @Override
        public int getItemCount() {
            return getCount();
        }

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

        public Cursor getItem(int position) {
            if (mDataValid && mCursor != null) {
                mCursor.moveToPosition(position);
                return mCursor;
            } else {
                return null;
            }
        }

        @Override
        public long getItemId(int position) {
            if (mDataValid && mCursor != null) {
                if (mCursor.moveToPosition(position)) {
                    return mCursor.getLong(mRowIDColumn);
                } else {
                    return 0;
                }
            } else {
                return 0;
            }
        }

        public Cursor swapCursor(Cursor newCursor) {
            if (newCursor == mCursor) {
                return null;
            }
            Cursor oldCursor = mCursor;
            if (oldCursor != null) {
                if (mChangeObserver != null) oldCursor.unregisterContentObserver(mChangeObserver);
                if (mDataSetObserver != null) oldCursor.unregisterDataSetObserver(mDataSetObserver);
            }
            mCursor = newCursor;
            if (newCursor != null) {
                if (mChangeObserver != null) newCursor.registerContentObserver(mChangeObserver);
                if (mDataSetObserver != null) newCursor.registerDataSetObserver(mDataSetObserver);
                mRowIDColumn = newCursor.getColumnIndexOrThrow("_id");
                mDataValid = true;
                // notify the observers about the new cursor
                notifyDataSetChanged();
            } else {
                mRowIDColumn = -1;
                mDataValid = false;
                // notify the observers about the lack of a data set
                notifyDataSetInvalidated();
            }
            return oldCursor;
        }

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

        public CharSequence convertToString(Cursor cursor) {
            return cursor == null ? "" : cursor.toString();
        }

        public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
            if (mFilterQueryProvider != null) {
                return mFilterQueryProvider.runQuery(constraint);
            }
            return mCursor;
        }


        public FilterQueryProvider getFilterQueryProvider() {
            return mFilterQueryProvider;
        }

        public void setFilterQueryProvider(FilterQueryProvider filterQueryProvider) {
            mFilterQueryProvider = filterQueryProvider;
        }

        protected void onContentChanged() {
            if (mAutoRequery && mCursor != null && !mCursor.isClosed()) {
                if (false) Log.v("Cursor", "Auto requerying " + mCursor + " due to update");
                mDataValid = mCursor.requery();
            }
        }

        private class ChangeObserver extends ContentObserver {
            public ChangeObserver() {
                super(new Handler());
            }

            @Override
            public boolean deliverSelfNotifications() {
                return true;
            }

            @Override
            public void onChange(boolean selfChange) {
                onContentChanged();
            }
        }

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

            @Override
            public void onInvalidated() {
                mDataValid = false;
                notifyDataSetInvalidated();
            }
        }


        private final DataSetObservable mDataSetObservable = new DataSetObservable();

        public void registerDataSetObserver(DataSetObserver observer) {
            mDataSetObservable.registerObserver(observer);
        }

        public void unregisterDataSetObserver(DataSetObserver observer) {
            mDataSetObservable.unregisterObserver(observer);
        }

        public void notifyDataSetInvalidated() {
            mDataSetObservable.notifyInvalidated();
        }
    }

Vậy đâu là Loader trong lớp này?
IgorGanapolsky

Trình tải sẽ sử dụng bộ chuyển đổi này. Xem developer.android.com/guide/components/loaders.html để biết ví dụ về cách sử dụng trình tải. Trong ví dụ này, SimpleCthonAd CHƯƠNG sẽ là MyAd CHƯƠNG
Arno

Ý bạn là gì SimpleCthonAd CHƯƠNG? Bạn đang mở rộng RecyclerView.Ad CHƯƠNG.
IgorGanapolsky

1
Ý tôi là nếu bạn thấy SimpleC bổngAd CHƯƠNG trong ví dụ này, bạn có thể đặt MyAd CHƯƠNG thay cho điều đó. Việc bạn mở rộng bộ điều hợp nào không quan trọng miễn là nó có phương thức hoán đổi và một số phương thức khác.
Arno

Có vẻ hơi quá mã hóa nếu so với câu trả lời của @nbtk ở trên.
eRaisedToX


1

Chỉ là một câu trả lời khác, vì tôi không thích câu trả lời được chấp nhận (mà imo không sử dụng trực quan).

Sau đây là cách thực hiện của riêng tôi, rất giống với (và được truyền cảm hứng một phần bởi) SimpleCursorAdapter:

public class RecyclerViewSimpleCursorAdapter extends RecyclerView.Adapter {
    private int mLayout;
    private Cursor mCursor;
    private String[] mFrom;
    private int[] mTo;

    private boolean mAutoRequery;
    private ContentObserver mContentObserver;

    /**
     * Standard constructor.
     *
     * @param layout resource identifier of a layout file that defines the views for this list item. The layout file should include at least those named views defined in "to"
     * @param c      The database cursor. Can be null if the cursor is not available yet.
     * @param from   A list of column names representing the data to bind to the UI. Can be null if the cursor is not available yet.
     * @param to     The views that should display column in the "from" parameter. These should all be TextViews and ImageViews. The first N views in this list are given the values of the first N columns in the from parameter. Can be null if the cursor is not available yet.
     */
    public RecyclerViewSimpleCursorAdapter(int layout, Cursor c, String[] from, int[] to, boolean autoRequery) {
        mLayout = layout;
        mCursor = c;
        mFrom = from;
        mTo = to;
        mAutoRequery = autoRequery;

        if (mAutoRequery) {
            initializeContentObserver();
        }
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new RecyclerView.ViewHolder(
                LayoutInflater.from(parent.getContext())
                        .inflate(mLayout, parent, false)
        ) {
        };
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        mCursor.moveToPosition(position);

        if (mFrom == null || mTo == null)
            return;

        for (int i = 0; i < mFrom.length && i < mTo.length; i++) {
            String from = mFrom[i];
            int columnIndex = mCursor.getColumnIndex(from);
            String value = mCursor.getString(columnIndex);
            View view = holder.itemView.findViewById(mTo[i]);

            if (view instanceof TextView) {
                ((TextView) view).setText(value);
            } else if (view instanceof ImageView) {
                try {
                    ((ImageView) view).setImageResource(Integer.parseInt(value));
                } catch (NumberFormatException nfe) {
                    ((ImageView) view).setImageURI(Uri.parse(value));
                }
            } else {
                throw new IllegalStateException(view.getClass().getName() + " is not a view that can be bound by this RecyclerViewSimpleCursorAdapter");
            }
        }
    }

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

    private void initializeContentObserver() {
        mContentObserver = new ContentObserver(new Handler()) {
            @Override
            public boolean deliverSelfNotifications() {
                return true;
            }

            @Override
            public void onChange(boolean selfChange) {
                notifyDataSetChanged();
            }
        };
        mCursor.registerContentObserver(mContentObserver);
    }

    /**
     * Change the underlying cursor to a new cursor. If there is an existing cursor it will be closed.
     *
     * @param cursor The new cursor to be used
     */
    public void changeCursor(Cursor cursor) {
        Cursor oldCursor = mCursor;
        if (mAutoRequery) {
            if (mCursor != null) {
                mCursor.unregisterContentObserver(mContentObserver);
            }

            mContentObserver = new ContentObserver(new Handler()) {
                @Override
                public boolean deliverSelfNotifications() {
                    return true;
                }

                @Override
                public void onChange(boolean selfChange) {
                    notifyDataSetChanged();
                }
            };

            mCursor = cursor;
            if (mCursor != null) {
                mCursor.registerContentObserver(mContentObserver);
            }
        }

        notifyDataSetChanged();

        if (oldCursor != null && oldCursor != mCursor) {
            oldCursor.close();
        }
    }

    /**
     * Change the cursor and change the column-to-view mappings at the same time.
     *
     * @param cursor The database cursor. Can be null if the cursor is not available yet.
     * @param from A list of column names representing the data to bind to the UI. Can be null if the cursor is not available yet.
     * @param to The views that should display column in the "from" parameter. These should all be TextViews or ImageViews. The first N views in this list are given the values of the first N columns in the from parameter. Can be null if the cursor is not available yet.
     */
    public void changeCursorAndColumns(Cursor cursor, String[] from, int[] to) {
        mFrom = from;
        mTo = to;
        changeCursor(cursor);
    }

    /**
     * Returns the cursor.
     * @return the cursor
     */
    public Cursor getCursor() {
        return mCursor;
    }
}

Bạn có thể sửa đổi nó cho các cách sử dụng cụ thể khác, nhưng có một con trỏ nó hoạt động giống như SimpleCursorAdaptervậy, chỉ với một RecyclerView.


0

Sau khi lấy dữ liệu từ DB và lưu trữ trong một danh sách, có lẽ nó sẽ giống như thế này:

    dbHelper = new BooksDbAdapter(this);
    dbHelper.open();
    //Clean all data
    dbHelper.deleteAllZist();
    //Add some data
    dbHelper.insertSomeRecords();
    List<String> mylist = dbHelper.getArrayColumn(3);

thêm dữ liệu vào recyclerview

list = new ArrayList<DataObject>();
 Integer i=0;
    for (String lst : mylist) {
        list.add(i++, new DataObject(lst,
                "The RecyclerView widget is a more advanced and flexible 
               version of ListView."));
    }

    recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
    recyclerView.setHasFixedSize(true);
    myRecAdapter = new RecyclerviewAdapter(list, Zist1ChapterActivity.this);

0

Dưới đây là triển khai con trỏ của tôi cho một recyclerview. Nó hỗ trợ OnItemClickListener, OnLongItemClickListener, OnfooterClickListener, Phần và chân trang. Không hỗ trợ , Header, onHeaderClickListner, trình quét nhanh, tiêu đề dính hoặc phần dính.

Chỉ cần mở rộng bộ chuyển đổi này và tạo bộ chuyển đổi của riêng bạn. Ghi đè các phương thức được cung cấp. và chuyển con trỏ từ phương thức OnCthonLoadFinished. Nếu bộ điều hợp đã được tạo thì hoán đổi ()

package com.tracker.paisa;

import android.database.Cursor;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;


/**
 * @author Rahul Upadhyay (https://github.com/devDroidRaul)
 * Supports footer
 * Onitemclicklistener, OnItemLongClickListener, OnFooterClickListener
 * Supports Sections.
 *
 * Does Not support,Header, OnHeaderClickListener, FastScroller, StickySection (this can b done with item decor)
 * Pull requests are welcome for improvements.
 *
 * Override this to give logic to place subheaders between items.
 * public abstract boolean onPlaceSubheaderBetweenItems(int position);
 *
 * create seperate viewHolders for item, subheaders and footer. and return required views.
 *
 * @Override below methods for individual item type.
 * public abstract VH onCreateItemViewHolder(ViewGroup parent, int viewType);
 * public abstract SH onCreateSubheaderViewHolder(ViewGroup parent, int viewType);
 * public abstract FH onCreateFooterViewHolder(ViewGroup parent, int viewType);
 *
 * Bind your views with data here.
 * @Override below methods to bind data to individual item types.
 * public abstract void onBindSubHeaderViewHolder(SH holder, Cursor cursor);
 * public abstract void onBindItemViewHolder(VH holder, Cursor cursor);
 * public abstract void onBindFooterViewHolder(FH holder, int itemPosition);
 *
 * Item type -1,-2,-3 are reserved, kindly do not pass them in getItemViewType.
 */

public abstract class RecyclerViewCursorAdapter<SH extends RecyclerView.ViewHolder, VH extends RecyclerView.ViewHolder, FH extends RecyclerView.ViewHolder>
        extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    public static final String TAG = RecyclerViewCursorAdapter.class.getSimpleName();

    private static final int TYPE_SECTION_HEADER = -1;

    private static final int TYPE_MAIN_HEADER = -2;
    private static final int TYPE_FOOTER = -3;

   // private int headerLayout=0,viewLayout=0;
    boolean createHeader;

    private List<Integer> subheaderPositions = new ArrayList<>();

    private Cursor mCursor;
    private boolean mDataValid,footerRequired=false;
    private int mRowIDColumn;
    private SparseBooleanArray mSelectedItemsIds;



   // public RecyclerViewCursorAdapter() { }

    //constructor
    public RecyclerViewCursorAdapter(Cursor c,boolean footerRequired) {
        setHasStableIds(true);
        swapCursor(c);
        this.footerRequired = footerRequired;

        this.mSelectedItemsIds = new SparseBooleanArray();
    }



    // interface for listning click on recycler view;
    public interface OnItemClickedListener{
        void OnItemClick(int id, Object data);

        void onItemLongClick(int id);
    }

    OnItemClickedListener onItemClickedListener;

    public void setOnItemClickedListener(OnItemClickedListener onItemClickedListener) {
        this.onItemClickedListener = onItemClickedListener;
    }

    public interface OnFooterClickedListener{
        void onFooterClick(Object data);
    }

    OnFooterClickedListener onFooterClickedListener;
    public void setOnFooterClickedListener( OnFooterClickedListener onFooterClickedListener){
        this.onFooterClickedListener = onFooterClickedListener;
    }

    public interface OnHeaderClickedListener{
        void onHeaderClick(Object data);
    }

    OnHeaderClickedListener onHeaderClickedListener;
    public void setOnHeaderClickedListener( OnHeaderClickedListener onHeaderClickedListener){
        this.onHeaderClickedListener = onHeaderClickedListener;
    }

    private void initSubheaderPositions() {
        subheaderPositions.clear();

        if(getItemSize() != 0) {
            //TODO:Handle This please.
            //subheaderPositions.add(0);
        } else {
            return;
        }

        for(int i = 1; i < getItemSize(); i++) {
            if(onPlaceSubheaderBetweenItems(i - 1)) {
                subheaderPositions.add(i + subheaderPositions.size());
            }
        }
    }

    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {

            initSubheaderPositions();



    }

    /**
     * Called when adapter needs to know whether to place subheader between two neighboring
     * items.
     *
     * @return true if you want to place subheader between two neighboring
     * items.
     */
    public abstract boolean onPlaceSubheaderBetweenItems(int position);

    public abstract VH onCreateItemViewHolder(ViewGroup parent, int viewType);

    public abstract SH onCreateSubheaderViewHolder(ViewGroup parent, int viewType);

    public abstract FH onCreateFooterViewHolder(ViewGroup parent, int viewType);

    public abstract void onBindSubHeaderViewHolder(SH holder, Cursor cursor);

    public abstract void onBindItemViewHolder(VH holder, Cursor cursor);

    public abstract void onBindFooterViewHolder(FH holder, int itemPosition);






    public abstract int getItemSize();

    /**
     * Return the view type of the item at position for the purposes
     * of view recycling.
     * Don't return -1. It's reserved for subheader view type.
     */
    public int getViewType(int position) {
        return 0;
    }

    @Override
    public final int getItemViewType(int position) {

        if(isSubheaderOnPosition(position)) {
            return TYPE_SECTION_HEADER;
        } if(footerRequired && getCursor().getPosition()==(getCursor().getCount()-1)){
            return TYPE_FOOTER;
        }else {
            return getViewType(position);
        }
    }

    public boolean isFooterAdded(){
        return footerRequired;
    }
    @Override
    public final RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        Log.d("RVCA-OCVH","create viewholder");
        if(viewType == TYPE_SECTION_HEADER) {
            return onCreateSubheaderViewHolder(parent, viewType);
        } if(footerRequired&&viewType == TYPE_FOOTER){
            return onCreateFooterViewHolder(parent, viewType);
        }else {
            return onCreateItemViewHolder(parent, viewType);
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public final void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        Log.d("RVCA-OBVH","bind viewholder");
        Log.d("RVCA-OBVH","subheader position:"+isSubheaderOnPosition(position));
        if(isSubheaderOnPosition(position)) {
            if (!mDataValid) {
                throw new IllegalStateException("Cannot bind viewholder when cursor is in invalid state.");
            }
            if (!mCursor.moveToPosition(getItemPositionForViewHolder(position))) {
                throw new IllegalStateException("Could not move cursor to position " + getItemPositionForViewHolder(position) + " when trying to bind viewholder");
            }

            onBindSubHeaderViewHolder((SH)holder, mCursor);
        }if(footerRequired && position==getItemCount()-1){
            Log.d("RVCA-OBVH","bind footerHolder");
            onBindFooterViewHolder((FH) holder,position);

        } else {
            if (!mDataValid) {
                throw new IllegalStateException("Cannot bind viewholder when cursor is in invalid state.");
            }
            if (!mCursor.moveToPosition(getItemPositionForViewHolder(position))) {
                throw new IllegalStateException("Could not move cursor to position " + getItemPositionForViewHolder(position) + " when trying to bind viewholder");
            }
            // if(!mCursor.isAfterLast()) {
            //   mCursor.moveToPosition(position);
            onBindItemViewHolder((VH)holder, mCursor);

        }
    }

    @Override
    public final int getItemCount() {
        return getItemSize() + subheaderPositions.size()+(footerRequired?1:0);
    }

    public void notifyDataChanged() {
        initSubheaderPositions();
        notifyDataSetChanged();
    }

    public void notifyItemInsertedAtPosition(int itemPosition) {
        if (itemPosition == 0) {
            if (getItemCount() == 1 || onPlaceSubheaderBetweenItems(itemPosition)) {
                subheaderPositions.add(0, 0);
                increaseSubheaderPositions(1, 2);
                notifyItemRangeInserted(0, 2);
            } else {
                increaseSubheaderPositions(1, 1);
                notifyItemInserted(1);
            }
        } else if (itemPosition == getItemSize() - 1) {
            if (onPlaceSubheaderBetweenItems(itemPosition - 1)) {
                subheaderPositions.add(getItemCount() - 1);
                notifyItemRangeInserted(getItemCount() - 1, 2);
            } else {
                notifyItemInserted(getItemPositionInRecyclerView(itemPosition));
            }
        } else {
            if (onPlaceSubheaderBetweenItems(itemPosition - 1) && onPlaceSubheaderBetweenItems(itemPosition)) {
                final int itemPositionInRv = getItemPositionInRecyclerView(itemPosition - 1);
                final int countOfSubheadersBeforePosition = getCountOfSubheadersBeforePosition(itemPositionInRv);
                subheaderPositions.add(countOfSubheadersBeforePosition, itemPositionInRv + 1);
                increaseSubheaderPositions(countOfSubheadersBeforePosition + 1, 2);
                notifyItemRangeInserted(itemPositionInRv + 1, 2);
            } else if (onPlaceSubheaderBetweenItems(itemPosition)){
                final int itemPositionInRv = getItemPositionInRecyclerView(itemPosition - 1);
                increaseSubheaderPositions(getCountOfSubheadersBeforePosition(itemPositionInRv), 1);
                notifyItemInserted(itemPositionInRv + 1);
            } else if (onPlaceSubheaderBetweenItems(itemPosition - 1)) {
                final int itemPositionInRv = getItemPositionInRecyclerView(itemPosition);
                increaseSubheaderPositions(getCountOfSubheadersBeforePosition(itemPositionInRv), 1);
                notifyItemInserted(itemPositionInRv);
            } else {
                final int itemPositionInRv = getItemPositionInRecyclerView(itemPosition);
                increaseSubheaderPositions(getCountOfSubheadersBeforePosition(itemPositionInRv), 1);
                notifyItemInserted(itemPositionInRv);
            }
        }
    }

    public void notifyItemChangedAtPosition(int itemPosition) {
        final int itemPositionInRv = getItemPositionInRecyclerView(itemPosition);
        notifyItemChanged(itemPositionInRv);
    }

    public void notifyItemRemovedAtPosition(int itemPosition) {

        final int itemPositionInRv = getItemPositionInRecyclerView(itemPosition);

        for (int i = 1; i < subheaderPositions.size(); i++) {
            final int subheaderPosition = subheaderPositions.get(i);
            if (subheaderPosition > itemPositionInRv) {
                final int previousSubheaderPosition = subheaderPositions.get(i - 1);
                if (subheaderPosition - previousSubheaderPosition == 2) {
                    subheaderPositions.remove(subheaderPositions.indexOf(previousSubheaderPosition));
                    decreaseSubheaderPositions(subheaderPositions.indexOf(subheaderPosition), 2);
                    notifyItemRangeRemoved(itemPositionInRv - 1, 2);
                } else {
                    decreaseSubheaderPositions(subheaderPositions.indexOf(subheaderPosition), 1);
                    notifyItemRemoved(itemPositionInRv);
                }
                return;
            }
        }

        final int lastSubheaderPosition = subheaderPositions.get(subheaderPositions.size() - 1);
        if (itemPositionInRv - lastSubheaderPosition == 1 && getItemCount() == itemPosition + subheaderPositions.size()) {
            subheaderPositions.remove(subheaderPositions.size() - 1);
            notifyItemRangeRemoved(itemPositionInRv - 1, 2);
        } else {
            notifyItemRemoved(itemPositionInRv);
        }
    }

    public void setGridLayoutManager(final GridLayoutManager gridLayoutManager) {
        gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
            @Override
            public int getSpanSize(int position) {
                if(subheaderPositions.contains(position)) {
                    return gridLayoutManager.getSpanCount();
                } else {
                    return 1;
                }
            }
        });
    }

    public boolean isSubheaderOnPosition(int position) {
        return subheaderPositions.contains(position);
    }

    public int getCountOfSubheadersBeforePosition(int position) {
        int count = 0;
        for(int subheaderPosition : subheaderPositions) {
            if(subheaderPosition < position) {
                count++;
            }
        }
        return count;
    }

    public int getItemPositionInRecyclerView(int position) {
        int countOfItems = 0;
        for (int i = 1; i < subheaderPositions.size(); i++) {
            final int previousSubheaderPosition = subheaderPositions.get(i - 1);
            final int nextSubheaderPosition = subheaderPositions.get(i);
            countOfItems += nextSubheaderPosition - previousSubheaderPosition - 1;
            if (countOfItems > position) {
                return position + i;
            }
        }
        return position + subheaderPositions.size();
    }

    public int getItemPositionForViewHolder(int viewHolderPosition) {
        return viewHolderPosition - getCountOfSubheadersBeforePosition(viewHolderPosition);
    }

    private void decreaseSubheaderPositions(int startSubheaderPosition, int decreaseNum) {
        for (int i = startSubheaderPosition; i < subheaderPositions.size(); i++) {
            final int subheaderPosition = subheaderPositions.get(i);
            subheaderPositions.set(i, subheaderPosition - decreaseNum);
        }
    }

    private void increaseSubheaderPositions(int startSubheaderPosition, int increaseNum) {
        for (int i = startSubheaderPosition; i < subheaderPositions.size(); i++) {
            final int subheaderPosition = subheaderPositions.get(i);
            subheaderPositions.set(i, subheaderPosition + increaseNum);
        }
    }

    private List<Integer> getSubheaderPositions() {
        return subheaderPositions;
    }

    public int getSubheaderCount() {
        return subheaderPositions.size();
    }

    public void swapCursor(Cursor newCursor) {
        Log.d("RVCA-SC","swap cursor");
        if (newCursor == mCursor) {
            Log.d("RVCA-SC","same cursor doing nothing");
            return;
        }

        if (newCursor != null) {
            Log.d("RVCA-SC","swap cursor not null");
            mCursor = newCursor;
            mRowIDColumn = mCursor.getColumnIndexOrThrow("_id");
            mDataValid = true;

            // notify the observers about the new cursor
            notifyDataChanged();
        } else {
            Log.d("RVCA-SC","swap cursor null");
            notifyItemRangeRemoved(0, getItemCount());
            mCursor = null;
            mRowIDColumn = -1;
            mDataValid = false;
        }
    }

    public Cursor getCursor(){
        return mCursor ;
    }

    @Override
    public long getItemId(int position) {
        if (isSubheaderOnPosition(position))
            return position;
        else {
            int cursorPosition = getItemPositionForViewHolder(position);
            Cursor cursor = getCursor();
            if (hasOpenCursor() && cursor.moveToPosition(cursorPosition)) {
                return cursor.getLong(cursor.getColumnIndex("_id"));
            }
            return NO_CURSOR_POSITION;
        }
    }
    public static final int NO_CURSOR_POSITION = -99;

    protected boolean hasOpenCursor() {
        Cursor cursor = getCursor();
        if (cursor == null || cursor.isClosed()) {
            swapCursor(null);
            return false;
        }
        return true;
    }

    //Methods to do Selection

    public void toggleSelection(int position) {
        selectView(position, !mSelectedItemsIds.get(position));
    }


    //Remove selected selections
    public void removeSelection() {
        mSelectedItemsIds = new SparseBooleanArray();
        notifyDataSetChanged();
    }


    //Put or delete selected position into SparseBooleanArray
    public void selectView(int position, boolean value) {
        if (value)
            mSelectedItemsIds.put(position, value);
        else
            mSelectedItemsIds.delete(position);

        // notifyItemChangedAtPosition(position);
        notifyDataSetChanged();
    }

    //Get total selected count
    public int getSelectedCount() {
        return mSelectedItemsIds.size();
    }

    //Return all selected ids
    public SparseBooleanArray getSelectedIds() {
        return mSelectedItemsIds;
    }

    public void setSelectedItemIds(SparseBooleanArray selectedItemIds){
        this.mSelectedItemsIds=selectedItemIds;
    }


}

0

Việc thực hiện đơn giản nhất là sử dụng đối tượng con trỏ trong bộ điều hợp và chuyển con trỏ đến hàm tạo của khung nhìn để sửa đổi khung nhìn và thay đổi vị trí con trỏ trong onBindViewholder.

Nếu bạn đang sử dụng Trình tải con trỏ, hãy gọi phương thức setCoder trong onLoadfinished()và truyền null vàoonLoadReset()

public class PetCursorRecyclerViewAdapter extends RecyclerView.Adapter<PetCursorRecyclerViewAdapter.ViewHolder> {
Cursor cursor = null;
Context context;

public PetCursorRecyclerViewAdapter(Context context) {
    this.context = context;

}

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

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(context).inflate(R.layout.catalog_item, parent, false);
    return new ViewHolder(v);
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    this.cursor.moveToPosition(position);
    holder.bindModel(this.cursor);
}

/*   getItemCount() returns the count of videos from the Cursor, or 0 if the
   Cursor is null (mimicking the behavior of CursorAdapter, which also treats
   a null Cursor as merely being one that has no rows)*/
@Override
public int getItemCount() {
    if (cursor == null) {
        return 0;
    } else {
        return cursor.getCount();
    }
}

public static class ViewHolder extends RecyclerView.ViewHolder {
    private TextView name_tv, breed_tv;

    public ViewHolder(View itemView) {
        super(itemView);
        name_tv = (TextView) itemView.findViewById(R.id.name_tv);
        breed_tv = (TextView) itemView.findViewById(R.id.breed_tv);
    }

    public void bindModel(Cursor cursor) {
        int name_index = cursor.getColumnIndexOrThrow(PetsContract.PetEntry.COLUMN_PET_NAME);
        int breed_index = cursor.getColumnIndexOrThrow(PetsContract.PetEntry.COLUMN_PET_BREED);
        name_tv.setText(cursor.getString(name_index));
        String breed = cursor.getString(breed_index);
        if (TextUtils.isEmpty(breed)) {
            breed = "Unknown Breed";
        }
        breed_tv.setText(breed);
    }
}    

}


0

Cuối cùng, chúng tôi đã triển khai RecyclerView.Ad CHƯƠNG cho cơ sở dữ liệu / mạng.

Nó nhận ra với các thành phần kiến ​​trúc Android :

Cơ sở dữ liệu phòng: Lớp cơ sở dữ liệu trên cơ sở dữ liệu SQLite đảm nhiệm các nhiệm vụ trần tục mà bạn đã sử dụng để xử lý với một SQLiteOpenHelper. Chủ sở hữu cơ sở dữ liệu đóng vai trò là điểm truy cập vào cơ sở dữ liệu SQLite bên dưới. Cơ sở dữ liệu phòng sử dụng DAO để đưa ra các truy vấn cho cơ sở dữ liệu SQLite.

ViewModel: Cung cấp dữ liệu cho UI. Hoạt động như một trung tâm liên lạc giữa Kho lưu trữ và Giao diện người dùng. Ẩn nơi dữ liệu bắt nguồn từ UI. Các phiên bản ViewModel tồn tại Hoạt động giải trí / Mảnh vỡ.

LiveData: Một lớp giữ dữ liệu có thể được quan sát. Luôn giữ / lưu trữ phiên bản mới nhất của dữ liệu. Thông báo cho người quan sát của nó khi dữ liệu đã thay đổi. LiveData là nhận thức vòng đời. Các thành phần UI chỉ quan sát dữ liệu liên quan và không dừng lại hoặc tiếp tục quan sát. LiveData tự động quản lý tất cả những điều này vì nó nhận thức được các thay đổi trạng thái vòng đời có liên quan trong khi quan sát.


-2

Bạn có thể sử dụng cơ sở dữ liệu SQLite để lưu trữ các chi tiết. Nó rất dễ dàng để truy cập dữ liệu. Bạn có thể kiểm tra mã của tôi trên github. https://github.com/thiru-wta/ToDo

     database = new Database(this);
    getSupportActionBar().setTitle("To Do List");
    etAddItems = (EditText) findViewById(R.id.etAddItem);
    btnAdd = (Button) findViewById(R.id.btnAdd);
    mRecyclerView = (RecyclerView) findViewById(R.id.listView);
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
    adapter = new RecyclerAdapter(this, listData);
    mRecyclerView.setAdapter(adapter);

    btnAdd.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            event_name = etAddItems.getText().toString();
            String getname="";

              database.storeEventDetails(event_name);

                 getname = database.getEventDetails(event_name);


            if (getname.length() != 0) {
                listData.add(getname);
                etAddItems.setText("");

                adapter.notifyData(listData);
            }

Phương pháp cơ sở dữ liệu:

    public void storeEventDetails(String event_name, long timerStart) {
    SQLiteDatabase db1 = getWritableDatabase();
    db1.execSQL("insert into '"+event_details_tbl+"' values('" + event_name + "')");
    db1.close();
}

có được phương pháp:

     public String getEventDetails(String event_name) {
    SQLiteDatabase db1 = getReadableDatabase();
    Cursor cur = db1.rawQuery("select * from '"+event_details_tbl+"' where     event_name ='" + event_name + "'", null);
    cur.moveToFirst();
    String evName = null;
    if (cur != null) {
        do {
            int eventName = cur.getColumnIndex("event_name");

            String ev_name = cur.getString(eventName);

            evName = ev_name;
        } while (cur.moveToNext());

    }
    cur.close();
    db1.close();
    return evName;

}     

-4

Bạn chỉ cần làm theo các bước sau:

  • Trong trình tái chế view.adapter, tạo một ArrayList hoặc Iterator được khởi tạo với giá trị null.
  • Tạo một phương thức như ví dụ trao đổi ex chẳng hạn swapdata(Arraylist<T> data). Bên trong bạn đưa ra một giá trị mới cho danh sách mảng, iterator hoặc bất kỳ cấu trúc nào mà hệ thống có thể lặp lại bằng cách sử dụng vị trí số nguyên int trong bindview. Các giá trị của phương thức này được truyền vào onloaderfinished(). Sau đó gọi ngay sau khi chuyển nhượng notifydatachange(); những thứ này sẽ yêu cầu RecyclerViewvẽ lại tất cả danh sách với dữ liệu mới của ArrayList.

Trong hoạt động hoặc đoạn mà bạn đang sử dụng loadercalback, hãy tạo một phương thức biến con trỏ thành một danh sách mảng hoặc iterator, tùy thuộc vào cấu trúc dữ liệu được chọn trong bộ điều hợp.

Bằng cách này, bạn luôn có thể sử dụng loadercalback mà không chặn luồng chính.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.