web-dev-qa-db-ja.com

Android -room永続ライブラリ-DAO呼び出しは非同期なので、コールバックを取得する方法は?

私が読んだことからメインスレッドでデータベースクエリを発行することはできません(メインスレッドで遅延を引き起こす可能性があります)だから、UIのテキストビューを更新しようとしていると想像してくださいいくつかのデータがどのようにコールバックを取得するメインスレッド。例を示しましょう。ビジネスモデルデータをEventsというオブジェクトに保存したいと想像してください。したがって、EventDaoオブジェクトがあります。

以下にこのDAOオブジェクトがあると想像してください。

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

}

そして今、いくつかのアクティビティでテキストビューがあり、その値を更新したいのでこれを行います:

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

フェッチはメインスレッドから行われているため、このように呼び出してスムーズな更新を期待できるとは思わない。ここで最善のアプローチは何ですか?

いくつかの追加情報:モデルデータベースの情報をメモリに静的に保持するのではなく、取得するためのメカニズムとしてルームデータベースを使用したかった。そのため、残りのサービスを介してダウンロードした後、dbを介してローカルでモデルを使用できます。

[〜#〜] update [〜#〜]:したがって、ライブデータを返すので、これを行うことができます:

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

そして、それは非常に小さなものに有効です。しかし、私のデータベースには100万のアイテムがあると想像してください。その後、この呼び出しを行うと、データの取得に遅延が生じます。これが最初に呼び出されると、遅延があることがユーザーに表示されます。これを避ける方法は?明確にするために、ライブデータが不要な場合があります。ビューを一度更新するだけです。これを行う方法を知る必要がありますか? liveDataがない場合でも。

16
j2emanue

クエリを同期的に実行し、データセットの更新の通知を受信しない場合は、戻り値をLiveDataオブジェクトにラップしないでください。 Googleのサンプルコードをご覧ください。

loadProductSync()here を見てください

12
Bohsen

非同期をオフにして同期アクセスを許可する方法があります。

データベースを構築するときに使用できます: allowMainThreadQueries()

また、メモリ内での使用: Room.inMemoryDatabaseBuilder()

推奨されていませんが。そのため、超高速アクセスが必要な場合は、最終的にメモリ内データベースとメインスレッドアクセスを使用できます。それは私のデータの大きさによると思いますが、この場合は非常に小さいです。

しかし、コールバックを使用したい場合.... rxJavaを使用すると、データベースに保存したい国のリスト用に作成されたものがあります:

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

}

その後、この関数にサブスクライバを簡単に追加して、Rxjavaでコールバックを取得できます。

6
j2emanue

Bohsenのように、クエリにlivedataを同期的に使用することをお勧めします。しかし、特別な場合には、ロジックに基づいて非同期操作を行いたいことがあります。以下の例では、親コメントの子コメントを取得する必要があります。 DBですでに利用可能ですが、recyclerviewアダプタのparent_idに基づいて取得する必要があります。これを行うには、AsyncTaskのreturnコンセプトを使用して結果を取得しました。 (コトリンに戻る)

リポジトリクラス

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クラス

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