Menggunakan recyclerview dengan database

127

Saat ini tidak ada implementasi standar RecyclerView.Adapter tersedia.

Mungkin dengan rilis resmi, Google akan menambahkannya.

Karena tidak ada dukungan untuk CursorAdapterdengan RecyclerViewsaat ini, bagaimana kita bisa menggunakan RecyclerViewdengan database? Ada saran?

Anak anjing hilang
sumber

Jawaban:

101

Jika Anda menjalankan kueri dengan CursorLoaderdan yang Anda inginkan, RecyclerViewbukan ListView.

Anda dapat mencoba CursorRecyclerViewAdapter: CursorAdapter di RecyclerView

skyfishjy
sumber
12
Kode berfungsi tetapi tidak animasi setelah menghapus dan menyisipkan karena metode registerDataSetObserver dari kelas kursor tidak mengidentifikasi elemen mana yang telah berubah secara tepat. Jadi setiap kali penyedia konten mengubah recyclerview dimuat sepenuhnya melalui notifyDataSetChanged , dan ini adalah inti dari RecyclerView.
francas
1
Apa yang menjadi kelemahan dari hanya menyerahkan kursor ke adaptor melalui konstruktor dan hanya menggunakan cursor.moveToPosition () di onBindViewHolder (), untuk mendapatkan data yang relevan?
Gautam
2
Saran: Panggil swapCursor () dari konstruktor, jadi Anda tidak perlu mengulangi sendiri di sana
Greg Ennis
2
@francas Animations berfungsi dengan baik jika Anda mengatursetHasStableIds(true)
alders
2
@alders, sudahkah Anda membuat perubahan lain selain setHasTableIds? Saya telah mencoba itu juga, ID itu cocok dan setiap kali saya menukar kursor daftar kembali ke atas.
dwbrito
89

Solusi saya adalah menahan anggota CursorAdapter di implementasi recyclerView.Adapter saya. Kemudian melewati semua penanganan menciptakan tampilan baru & mengikatnya ke adaptor kursor, sesuatu seperti ini:

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);
    }
}
nbtk
sumber
17
Terima kasih atas solusi ini, ini berfungsi untuk saya, saya hanya perlu menambahkan satu baris ke dalamBindViewHolder: 'mCursorAdapter.getCursor (). MoveToPosition (posisi)' sebelum memanggil bindView () pada mCursorAdapter
user1071762
8
@nbtk Mengapa tidak memegang Cursor alih-alih CursorAdapter? Seperti yang saya mengerti, Anda tidak menggunakan kapabilitas CursorAdapter.
MyDogTom
14
@MyDogTom - Saya tidak memegang kursor, karena Anda harus menghapusnya ketika Anda selesai, dan mengaturnya ke NULL tidak cukup. CursorAdapter menangani ini dengan sempurna.
nbtk
3
@ Ntk Saya benar-benar menyukai ide ini, dan saya telah bermain dengannya sejak itu. Saya mencoba abstrak sedikit dan membangun perpustakaan, itu bukan 100% di mana saya ingin tetapi belum menyelesaikan pekerjaan. Apakah Anda tertarik untuk memeriksanya? Jika Anda memiliki github, saya akan dengan senang hati memberi Anda inspirasi. github.com/androidessence/RecyclerViewCursorAdapter
AdamMc331
5
@nbtk Lakukan hal berikut untuk menyegarkan tampilan Anda dengan data baru:public void changeCursor(Cursor cursor){ mCursorAdapter.changeCursor(cursor); notifyDataSetChanged(); }
Cijo
48

Karena pertanyaan Anda mengatakan "Bagaimana cara menggunakan RecyclerViewdengan database" dan Anda tidak spesifik apakah Anda ingin SQLite atau yang lainnya RecyclerView, saya akan memberikan solusi yang sangat optimal. Saya akan menggunakan Realm sebagai basis data dan membiarkan Anda menampilkan semua data di dalam RecyclerView. Ini memiliki dukungan permintaan asinkron juga tanpa menggunakan Loadersatau AsyncTask.

Mengapa dunia? kinerja realm.io Android

Langkah 1

Tambahkan dependensi gradle untuk Realm, ketergantungan untuk versi terbaru dapat ditemukan di sini

Langkah 2

Buat kelas model Anda, misalnya, katakanlah sesuatu yang sederhana seperti Datayang memiliki 2 bidang, string yang akan ditampilkan di dalamRecyclerView baris dan cap waktu yang akan digunakan sebagai itemId untuk memungkinkan RecyclerViewitem bernyawa. Perhatikan bahwa saya memperluas di RealmObjectbawah ini karena Datakelas Anda akan disimpan sebagai tabel dan semua properti Anda akan disimpan sebagai kolom dari tabel itu Data. Saya telah menandai teks data sebagai kunci utama dalam kasus saya karena saya tidak ingin string ditambahkan lebih dari sekali. Tetapi jika Anda lebih suka memiliki duplikat, maka jadikan timestamp sebagai @PrimaryKey. Anda bisa memiliki tabel tanpa kunci utama tetapi itu akan menyebabkan masalah jika Anda mencoba memperbarui baris setelah membuatnya. Kunci primer gabungan pada saat penulisan jawaban ini tidak didukung oleh Realm.

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;
}
}

Langkah 3

Buat tata letak Anda untuk bagaimana satu baris seharusnya muncul di dalam RecyclerView . Tata letak untuk item baris tunggal di dalam kami Adapteradalah sebagai berikut

<?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>

Perhatikan bahwa saya telah menyimpan FrameLayoutroot meskipun saya punyaTextView di dalam. Saya berencana untuk menambahkan lebih banyak item dalam tata letak ini dan karenanya membuatnya fleksibel untuk saat ini :)

Untuk orang-orang yang penasaran di luar sana, ini adalah bagaimana satu item terlihat saat ini. tata letak baris item tunggal di dalam RecyclerView

Langkah 4

Buat RecyclerView.Adapterimplementasi Anda . Dalam hal ini, objek sumber data adalah objek khusus yang disebut RealmResultsyang pada dasarnya adalah LIVE ArrayList, dengan kata lain, karena item ditambahkan atau dihapus dari tabel Anda, RealmResultsobjek ini diperbarui secara otomatis.

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);
    }
}
}

Perhatikan bahwa saya menelepon notifyItemRemoveddengan posisi di mana penghapusan terjadi tetapi saya TIDAK menelepon notifyItemInsertedatau notifyItemRangeChangedkarena tidak ada cara langsung untuk mengetahui posisi mana item yang dimasukkan ke dalam basis data karena entri Realm tidak disimpan dengan cara yang dipesan. The RealmResultsobjek auto update setiap kali item baru ditambahkan, dimodifikasi atau dihapus dari database sehingga kita sebut notifyDataSetChangedsambil menambahkan dan memasukkan entri massal. Pada titik ini, Anda mungkin khawatir tentang animasi yang tidak akan dipicu karena Anda menelepon notifyDataSetChangeddi tempat notifyXXXmetode. Itulah sebabnya saya memiliki getItemIdmetode mengembalikan timestamp untuk setiap baris dari objek hasil. Animasi dicapai dalam 2 langkah dengan notifyDataSetChangedjika Anda memanggil setHasStableIds(true)dan kemudian menimpanyagetItemId untuk memberikan sesuatu selain dari posisi.

Langkah 5

Mari kita tambahkan RecyclerViewke Activityatau Fragment. Dalam kasus saya, saya menggunakan Activity. File layout yang berisi RecyclerViewsangat sepele dan akan terlihat seperti ini.

<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" />

Saya telah menambahkan app:layout_behaviorsejak saya RecyclerViewmasuk ke dalam CoordinatorLayoutyang saya belum diposting di jawaban ini untuk singkatnya.

Langkah 6

Bangun RecyclerViewkode in dan berikan data yang dibutuhkan. Buat dan inisialisasi objek Realm di dalamnya onCreatedan tutup di dalamnya onDestroyseperti menutup SQLiteOpenHelperinstance. Paling sederhana onCreatedi dalam Anda Activityakan terlihat seperti ini. The initUimetode adalah di mana semua keajaiban terjadi. Saya membuka contoh Realm di dalam 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);
}

Perhatikan bahwa pada langkah pertama, saya meminta Realm untuk memberi saya semua objek dari Datakelas yang diurutkan berdasarkan nama variabel mereka yang disebut data secara asinkron. Ini memberi saya RealmResultsobjek dengan 0 item pada utas utama yang saya atur di Adapter. Saya menambahkan RealmChangeListeneruntuk diberitahu ketika data telah selesai memuat dari utas latar tempat saya menelepon notifyDataSetChangeddengan saya Adapter. Saya juga telah memanggil setHasStableIdstrue untuk membiarkan RecyclerView.Adapterimplementasi melacak item yang ditambahkan, dihapus atau dimodifikasi. Untuk onDestroysaya Activitymenutup instance Realm

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

Metode ini initUidapat disebut dalam onCreatedari Anda Activityatau onCreateViewatau onViewCreateddari Anda Fragment. Perhatikan hal-hal berikut.

Langkah 7

BAM! Ada data dari database dalam Anda RecyclerViewasynchonously dimuat tanpa CursorLoader, CursorAdapter, SQLiteOpenHelperdengan animasi. Gambar GIF yang ditampilkan di sini agak lamban tetapi animasinya terjadi ketika Anda menambahkan item atau menghapusnya.

data dari basis data di dalam RecyclerView

PirateApp
sumber
Terima kasih telah memberikan contoh komprehensif. Saya punya beberapa pertanyaan. Saya ingin menyimpan bitmap di ranah apakah mungkin? jika ya, apa yang akan menjadi jenis kolom dan bagaimana cara menyimpan dan mengambilnya?
Rakesh
1
@Rakesh tidak pernah menyimpan gambar di dalam basis data apa pun, selalu menyimpannya di sistem file Anda dan menyimpan uri dari gambar di basis data
PirateApp
Terima kasih atas tanggapan yang cepat. Saya membuat aplikasi tempat saya ingin menyimpan gambar untuk kontak saya. Jika saya menyimpan di sistem file mungkin ada ratusan gambar. Bagaimana saya mengelola gambar-gambar itu di sistem file?
Rakesh
9
FWIW, termasuk grafik kinerja Realm pada penyisipan cukup tidak relevan dengan pertanyaan tentang tinjauan ulang (yang tidak dapat dihindari tentang pengambilan)
JRaymond
Mengingat bilah alat mengatakan Vivz , apakah ini solusi @slidenerd?
SymbolixAU
1

Anda dapat menerapkan semua metode yang diperlukan sendiri. Baru-baru ini saya membuat implementasi sendiri dengan hanya menyalin kode tempel dari CursorAdapter.

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();
        }
    }
Arno
sumber
Jadi di mana Loader di kelas ini?
IgorGanapolsky
Pemuat akan menggunakan adaptor ini. Lihat developer.android.com/guide/components/loaders.html untuk contoh cara menggunakan loader. Dalam contoh ini, SimpleCursorAdapter akan menjadi MyAdapter
Arno
Apa maksudmu SimpleCursorAdapter? Anda memperluas RecyclerView.Adapter.
IgorGanapolsky
1
Maksud saya, jika Anda melihat SimpleCursorAdapter dalam contoh, Anda dapat menempatkan MyAdapter di tempat itu. Tidak masalah adaptor apa yang Anda perpanjang asalkan memiliki metode swapcursor dan beberapa metode lainnya.
Arno
Tampaknya sedikit over coding jika dibandingkan dengan jawaban @ nbtk di atas.
eRaisedToX
1

Hanya jawaban lain, karena saya tidak suka yang diterima (yang juga tidak memiliki penggunaan intuitif).

Berikut ini adalah implementasi saya sendiri, yang sangat mirip dengan (dan sebagian terinspirasi oleh) 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;
    }
}

Anda dapat memodifikasinya untuk penggunaan khusus lainnya, tetapi memiliki kursor berfungsi seperti SimpleCursorAdapterhalnya hanya dengan a RecyclerView.

Massimo
sumber
0

Setelah mengambil data dari DB dan menyimpan dalam daftar, mungkin itu harus seperti ini:

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

tambahkan data ke 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);
Josef
sumber
0

Di bawah ini adalah implementasi cursoradapter saya untuk recyclerview. Ini mendukung OnItemClickListener, OnLongItemClickListener, OnfooterClickListener, Bagian, dan catatan kaki. Tidak mendukung , Header, onHeaderClickListner, penggulung cepat, header lengket, atau bagian lengket.

Cukup rentangkan adaptor ini dan buat adaptor Anda sendiri. Ganti metode yang disediakan. dan meneruskan kursor dari metode OnCursorLoadFinished.Jika adaptor sudah dibuat kemudian swapCursor ()

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;
    }


}
Dev Raul
sumber
0

Implementasi yang paling sederhana adalah dengan menggunakan objek kursor di adaptor dan meneruskan kursor ke konstruktor viewholder untuk mengubah tampilan dan mengubah posisi kursor di onBindViewholder.

Jika Anda menggunakan Loader kursor, panggil metode setCursor masuk onLoadfinished()dan meneruskan null inonLoadReset()

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);
    }
}    

}

KingKongCoder
sumber
0

Akhirnya kami memiliki implementasi RecyclerView.Adapter untuk database / jaringan.

Itu diwujudkan dengan Komponen Arsitektur Android :

Basis data kamar: Lapisan basis data di atas basis data SQLite yang menangani tugas-tugas biasa yang Anda gunakan untuk menanganiSQLiteOpenHelper . Pemegang basis data yang berfungsi sebagai titik akses ke basis data SQLite yang mendasarinya. Database Kamar menggunakan DAO untuk mengeluarkan pertanyaan ke database SQLite.

ViewModel: Menyediakan data ke UI. Bertindak sebagai pusat komunikasi antara Repositori dan UI. Menyembunyikan tempat data berasal dari UI. Contoh ViewModel selamat dari Kegiatan / Penggalan rekreasi.

LiveData: Kelas pemegang data yang dapat diamati. Selalu memegang / menyimpan data versi terbaru. Memberitahu pengamatnya ketika data telah berubah. LiveData sadar akan siklus hidup. Komponen UI hanya mengamati data yang relevan dan jangan berhenti atau melanjutkan pengamatan. LiveData secara otomatis mengelola semua ini karena menyadari perubahan status siklus hidup yang relevan saat mengamati.

Leo240
sumber
-2

Anda dapat menggunakan database SQLite untuk menyimpan detailnya. Sangat mudah untuk mengakses data. Anda dapat memeriksa kode saya di 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);
            }

Metode basis data:

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

dapatkan metode:

     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;

}     
thiru-wta
sumber
-4

Anda cukup mengikuti langkah-langkah ini:

  • Di pendaur ulang view.adapter, buat ArrayList atau Iterator diinisialisasi dengan nilai nol.
  • Buat metode seperti ex swapcursor, misalnya swapdata(Arraylist<T> data). Di dalam Anda memberikan nilai-nilai baru ke daftar array, iterator atau struktur apa saja yang dapat diulang-ulang menggunakan posisi integer di dalam bindview. Nilai-nilai metode ini diteruskan dalam onloaderfinished(). Kemudian teleponlah tepat setelah penugasan notifydatachange(); ini akan meminta RecyclerViewuntuk menggambar kembali semua daftar dengan data baru dari ArrayList.

Dalam aktivitas atau fragmen di mana Anda menggunakan loadercalback, buat metode yang mengubah kursor ke daftar array, atau iterator, tergantung pada struktur data yang dipilih dalam adaptor.

Dengan cara ini Anda selalu dapat menggunakan loadercalback tanpa memblokir utas utama.

tarik
sumber