Da Ihre Frage "Verwendung RecyclerViewmit einer Datenbank" lautet und Sie nicht genau wissen, ob Sie SQLite oder etwas anderes mit dem möchten RecyclerView, gebe ich Ihnen eine Lösung, die sehr optimal ist. Ich werde Realm als Datenbank verwenden und Sie alle Daten in Ihrem anzeigen lassen RecyclerView. Es unterstützt auch asynchrone Abfragen, ohne Loadersoder zu verwenden AsyncTask.
Warum Reich?

Schritt 1
Fügen Sie die Gradle-Abhängigkeit für Realm hinzu. Die Abhängigkeit für die neueste Version finden Sie hier
Schritt 2
Wenn Sie beispielsweise Ihre Modellklasse erstellen, können Sie beispielsweise Datazwei Felder, eine Zeichenfolge, die in der RecyclerViewZeile angezeigt werden soll, und einen Zeitstempel verwenden, der als itemId zum Animieren von RecyclerViewElementen verwendet wird. Beachten Sie, dass ich weiter RealmObjectunten erläutere, weshalb Ihre DataKlasse als Tabelle und alle Ihre Eigenschaften als Spalten dieser Tabelle gespeichert werden Data. Ich habe den Datentext in meinem Fall als Primärschlüssel markiert, da ich nicht möchte, dass eine Zeichenfolge mehr als einmal hinzugefügt wird. Wenn Sie jedoch Duplikate bevorzugen, legen Sie den Zeitstempel als @PrimaryKey fest. Sie können eine Tabelle ohne Primärschlüssel haben, dies kann jedoch zu Problemen führen, wenn Sie versuchen, die Zeile nach dem Erstellen zu aktualisieren. Ein zusammengesetzter Primärschlüssel zum Zeitpunkt des Schreibens dieser Antwort wird von Realm nicht unterstützt.
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;
}
}
Schritt 3
Erstellen Sie Ihr Layout dafür, wie eine einzelne Zeile in der angezeigt werden soll RecyclerView. Das Layout für ein einzelnes Zeilenelement in unserem Adapterist wie folgt
<?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>
Beachten Sie, dass ich eine FrameLayoutals Wurzel behalten habe , obwohl ich eine TextViewinnere habe. Ich habe vor, weitere Elemente in dieses Layout aufzunehmen und es daher vorerst flexibel zu gestalten :)
Für die Neugierigen da draußen sieht ein einzelner Artikel derzeit so aus.

Schritt 4
Erstellen Sie Ihre RecyclerView.AdapterImplementierung. In diesem Fall ist das Datenquellenobjekt ein spezielles Objekt, RealmResultsdas als LIVE bezeichnet ArrayListwird. Mit anderen Worten, wenn Elemente zu Ihrer Tabelle hinzugefügt oder daraus entfernt werden, wird dieses RealmResultsObjekt automatisch aktualisiert.
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);
}
}
}
Beachten Sie, dass ich notifyItemRemovedmit der Position anrufe, an der die Entfernung stattgefunden hat, aber NICHT anrufe notifyItemInsertedoder notifyItemRangeChangedweil es keine direkte Möglichkeit gibt, festzustellen, an welcher Position das Element in die Datenbank eingefügt wurde, da Realm-Einträge nicht in geordneter Weise gespeichert werden. Das RealmResultsObjekt wird automatisch aktualisiert, wenn ein neues Element hinzugefügt, geändert oder aus der Datenbank entfernt wird, sodass wir notifyDataSetChangedbeim Hinzufügen und Einfügen von Masseneinträgen aufrufen . An diesem Punkt sind Sie wahrscheinlich besorgt über die Animationen, die nicht ausgelöst werden, weil Sie notifyDataSetChangedanstelle von notifyXXXMethoden aufrufen . Genau deshalb muss die getItemIdMethode den Zeitstempel für jede Zeile aus dem Ergebnisobjekt zurückgeben. Die Animation erfolgt in 2 Schritten mit, notifyDataSetChangedwenn Sie anrufen setHasStableIds(true)und dann überschreibengetItemId etwas anderes als nur die Position zu bieten.
Schritt 5
Fügen RecyclerViewwir das zu unserem Activityoder hinzu Fragment. In meinem Fall verwende ich eine Activity. Die Layoutdatei mit dem RecyclerViewist ziemlich trivial und würde ungefähr so aussehen.
<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" />
Ich habe eine hinzugefügt, app:layout_behaviorseit ich RecyclerViewin eine gehe, CoordinatorLayoutdie ich der Kürze halber in dieser Antwort nicht gepostet habe.
Schritt 6
Konstruieren Sie den RecyclerViewIn-Code und geben Sie die benötigten Daten an. Erstellen und initialisieren Sie ein Realm-Objekt im Inneren onCreateund schließen Sie es im Inneren, onDestroyähnlich wie beim Schließen einer SQLiteOpenHelperInstanz. Im einfachsten Fall sieht Ihr onCreateInneres Activityso aus. Die initUiMethode ist, wo all die Magie passiert. Ich öffne eine Instanz von Realm im Inneren 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);
}
Beachten Sie, dass ich im ersten Schritt Realm abfrage, um mir alle Objekte aus der DataKlasse zu geben, die asynchron nach ihrem Variablennamen namens data sortiert sind. Dies gibt mir ein RealmResultsObjekt mit 0 Elementen im Hauptthread, das ich auf dem einstelle Adapter. Ich habe ein hinzugefügt RealmChangeListener, um benachrichtigt zu werden, wenn das Laden der Daten aus dem Hintergrund-Thread, in dem ich notifyDataSetChangedmit meinem aufrufe, abgeschlossen ist Adapter. Ich habe auch setHasStableIdstrue aufgerufen , damit die RecyclerView.AdapterImplementierung Elemente verfolgt, die hinzugefügt, entfernt oder geändert wurden. Das onDestroyfür mich Activityschließt die Realm-Instanz
@Override
protected void onDestroy() {
super.onDestroy();
mRealm.close();
}
Diese Methode initUikann in onCreateIhrem Activityoder onCreateViewoder onViewCreatedvon Ihrem aufgerufen werden Fragment. Beachten Sie die folgenden Dinge.
Schritt 7
BAM! Es gibt Daten aus der Datenbank in Ihrem RecyclerViewasynchonously ohne geladen CursorLoader, CursorAdapter, SQLiteOpenHelpermit Animationen. Das hier gezeigte GIF-Bild ist etwas verzögert, aber die Animationen werden ausgeführt, wenn Sie Elemente hinzufügen oder entfernen.
