ユーザー情報をローカルルームデータベースに保存しています。アクティビティとフラグメントでは、AndroidViewModelとLiveDataを使用して、データベースに加えられた変更をリッスンし、UIを更新します。
ここで、過去のユーザーデータをすべて分析して、将来の決定に関する推奨事項を示します。私の推奨事項は、ユーザーがデータベースを変更するたびに変更されるため、同じ計算を何度も繰り返しながら、推奨事項を頻繁に更新する必要があります。
アプリの起動時に、ViewModelとLiveDataを介してデータベースの変更をリッスンし、推奨事項(同じデータベースに格納されている)を更新するサービスを開始することを考えていました。しかし、どういうわけかサービスはできません
viewModel = ViewModelProviders.of(this).get(DataViewModel.class);
を介してViewModelを取得する基本的に、データベースからすべてのエントリを読み取り、データを分析し、データベースの内容が変更されるたびに5〜10個の値を更新するだけです。
サービス中でない場合、どこでどのように計算する必要がありますか?多分私は間違った考えに囚われており、サービスはそれを行う正しい方法ではないので、これを行う方法についてのアイデアは非常に高く評価されています!
lifeDataOwnerではないため、LiveDataオブジェクトを観察する
LiveData
でobserveForever()
を使用し、必要に応じてremoveObserver()
を介して手動で登録を解除します(サービスのonDestroy()
、早くなければ)。
ここでは標準のサービス制限が適用されることに注意してください(たとえば、サービスはAndroid 8.0+でフォアグラウンドサービスでない限り)1分間実行されるため、とにかく他のアプローチを検討する必要がある場合があります。 。
エンティティに変更はありません。
DAOでは、たとえば、
@Dao
public interface TimeDao {
// ...
// ...
// for a started Service using startService() in background
@Query("select * from times where name = :bName")
List<TimeEntity> getServiceTimes(String bName);
}
これはLiveDataではありません
データベースでは、たとえば、
@Database(entities = {DataEntity.class, TimeEntity.class}, version = 1)
public abstract class BrRoomDatabase extends RoomDatabase {
public abstract TimeDao iTimeDao();
public static BrRoomDatabase getDatabase(final Context context) {
if (INSTANCE == null) {
// ...
}
return INSTANCE;
}
}
インターフェースクラス
public interface SyncServiceSupport {
List<TimeEntity> getTimesEntities(String brName);
}
それの実装クラス。
public class SyncServiceSupportImpl implements SyncServiceSupport {
private TimeDao timeDao;
public SyncServiceSupportImpl(Context context) {
timeDao = BrRoomDatabase.getDatabase(context).iTimeDao();
// getDatabase() from where we get DB instance.
// .. and ..
// public abstract TimeDao iTimeDao(); <= defined abstract type in RoomDatabase abstract class
}
@Override
public List<TimeEntity> getTimesEntities(String name) {
return timeDao.getServiceTimes(name);
}
}
そして最後に...サービスで...
public class SyncService extends Service {
//..
// now, iEntities will have a List of TimeEntity objects from DB ..
// .. retrieved using @Query
private static List<TimeEntity> iEntities = new ArrayList<>();
private static SyncServiceSupportImpl iSyncService;
private static void getFromDB(String brName) {
new AsyncTask<String, Void, Void>() {
@Override
protected Void doInBackground(String... params) {
iEntities = iSyncService.getTimesEntities(params[0]);
return null;
}
@Override
protected void onPostExecute(Void agentsCount) {
}
}.execute(brName);
}
@Override
public void onCreate() {
super.onCreate();
//init service
iSyncService = new SyncServiceSupportImpl(SyncService.this);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// this can be elsewhere also !..
getFromDB(myName);
}
}
私はサービスを使用することになり、次のように私の問題を解決しました:
onCreate
メソッドでApplication object
MyService
をバインドします:
serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder iBinder) {
service = ((MyService.MyLocalBinder) iBinder ).getService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
Intent intent = new Intent(this, MyService.class);
getApplicationContext().bindService(intent, serviceConnection, BIND_AUTO_CREATE);
サービスをアプリケーションコンテキストにバインドしても、アプリケーションが破棄されない限り、サービスは維持されます。 MyService
では、次のようにAndroidViewModelFactory
を介してViewModelのインスタンスを取得します
MyViewModel myViewModel = ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication()).create(MyViewModel.class);
このようにobserveForever
を介してViewModelから取得したLiveDataを観察できます
Observer<List<Entry>> obsEntries = new Observer<List<Entry>>() {
@Override
public void onChanged(@Nullable List<Entry> entries) {
//perform calculations with entries in here
}
};
viewModel.getEntries().observeForever(obsEntries);
重要:サービスのonDestroy
のLiveData参照からオブザーバーを削除します(そのため、Observerオブジェクトへのローカル参照を保持しています)。
@Override
public void onDestroy() {
super.onDestroy();
viewModel.getEntries().removeObserver(obsEntries);
}
みんなありがとう!