web-dev-qa-db-de.com

Android-Raum persistente Bibliothek - DAO-Anrufe sind asynchron, wie kann man also Rückruf erhalten?

Aus dem, was ich gelesen habe, können Sie mit Room keine Datenbankabfragen für den Haupt-Thread ausgeben (da dies zu Verzögerungen beim Haupt-Thread führen kann). so stellen Sie sich vor, ich versuche, eine Textansicht im UI-Haupt-Thread zu aktualisieren, die einige Daten enthält, wie ich einen Rückruf erhalten würde. Lass mich dir ein Beispiel zeigen. Stellen Sie sich vor, ich möchte meine Geschäftsmodelldaten in einem Objekt namens Events speichern. Wir hätten daher ein EventDao-Objekt:

stellen Sie sich vor, wir haben dieses DAO-Objekt unten:

@Dao
public interface EventDao {

   @Query("SELECT * FROM " + Event.TABLE_NAME + " WHERE " + Event.DATE_FIELD + " > :minDate" limit 1)
   LiveData<List<Event>> getEvent(LocalDateTime minDate);

   @Insert(onConflict = REPLACE)
   void addEvent(Event event);

   @Delete
   void deleteEvent(Event event);

   @Update(onConflict = REPLACE)
   void updateEvent(Event event);

}

und jetzt habe ich in einigen Aktivitäten eine Textansicht und möchte deren Wert aktualisieren, so dass ich Folgendes tue:

 myTextView.setText(EventDao.getEvent(someDate));/*i think this is illegal as im trying to call room dao on mainthread, therefore how is this done correctly ? would i need to show a spinner while it updates ?*/

da das Abrufen aus dem Haupt-Thread erfolgt, glaube ich nicht, dass ich es so nennen kann, und erwarte ein reibungsloses Update. Was ist der beste Ansatz hier? 

Weitere Informationen: Ich wollte die Raumdatenbank als Mechanismus zum Abrufen von Modellinformationen verwenden, anstatt sie statisch im Speicher zu behalten. das modell wäre also lokal über die db verfügbar, nachdem ich es über einen rest-dienst heruntergeladen habe. 

UPDATE: da ich also eine Livedata zurückschicke, kann ich folgendes tun:

eventDao = eventDatabase.eventDao();
eventDao.getEvent().observe(this, event -> {
     myTextView.setText(event.get(0));
});

und das funktioniert für etwas sehr kleines. Aber stellen Sie sich vor, meine Datenbank hat eine Million Artikel. Wenn ich diesen Anruf mache, wird es eine Verzögerung beim Abrufen der Daten geben. Beim allerersten Aufruf wird dies für den Benutzer sichtbar, dass eine Verzögerung vorliegt. Wie vermeide ich das? Um klar zu sein, gibt es Zeiten, in denen ich keine Live-Daten haben möchte. Ich muss nur die Ansicht aktualisieren. Ich muss wissen, wie das geht? auch wenn es nicht bei liveData ist. 

11
j2emanue

Wenn Sie Ihre Abfrage synchron ausführen möchten und keine Benachrichtigungen über Aktualisierungen in der Datenmenge erhalten möchten, packen Sie den Wert nicht einfach in ein LiveData-Objekt. Überprüfen Sie den Beispielcode von Google.

Werfen Sie einen Blick auf loadProductSync () hier

8
Bohsen

Es gibt eine Möglichkeit, asynchron zu deaktivieren und den synchronen Zugriff zuzulassen. 

beim Erstellen der Datenbank können Sie Folgendes verwenden: allowMainThreadQueries ()

und für die Verwendung im Speicher: Room.inMemoryDatabaseBuilder ()

Obwohl es nicht empfohlen wird. Am Ende kann ich also eine in-Memory-Datenbank und einen Haupt-Thread-Zugriff verwenden, wenn ich einen sehr schnellen Zugriff wollte. Ich denke, es hängt davon ab, wie groß meine Daten sind und ist in diesem Fall sehr klein. 

aber wenn Sie einen Rückruf verwenden wollten ... mit rxJava habe ich eine Liste der Länder erstellt, die ich in einer Datenbank speichern wollte:

public Observable<CountryModel> queryCountryInfoFor(final String isoCode) {
    return Observable.fromCallable(new Callable<CountryModel>() {
        @Override
        public CountryModel call() throws Exception {
            return db.countriesDao().getCountry(isoCode);
        }
    }).subscribeOn(Schedulers.io())

 .observeOn(AndroidSchedulers.mainThread());

}

sie können dann einfach einen Teilnehmer zu dieser Funktion hinzufügen, um den Rückruf mit Rxjava zu erhalten. 

6
j2emanue

Als Bohsen vorgeschlagene Verwendung von Livedata zur Abfrage synchron. In bestimmten Fällen möchten wir jedoch eine asynchrone Operation basierend auf der Logik durchführen. Im Beispielfall muss ich einige untergeordnete Kommentare für die übergeordneten Kommentare abrufen. Es ist bereits in der Datenbank verfügbar, muss jedoch basierend auf seiner parent_id im Recyclerviewadapter abgerufen werden. Dafür habe ich das Rückgabekonzept von AsyncTask verwendet, um das Ergebnis zurückzuerhalten. (Rückkehr in Kotlin)

Repositor-Klasse

fun getChildDiscussions(parentId: Int): List<DiscussionEntity>? {
        return GetChildDiscussionAsyncTask(discussionDao).execute(parentId).get()
    }

private class GetChildDiscussionAsyncTask constructor(private val discussionDao: DiscussionDao?): AsyncTask<Int, Void, List<DiscussionEntity>?>() {
        override fun doInBackground(vararg params: Int?): List<DiscussionEntity>? {
            return discussionDao?.getChildDiscussionList(params[0]!!)
        }
    }

Dao-Klasse

@Query("SELECT * FROM discussion_table WHERE parent_id = :parentId")
fun getChildDiscussionList(parentId: Int): List<DiscussionEntity>?
0
Naveen Kumar M