LiveData 未将数据从一个 Activity 更新到另一个 Activity - Android
LiveData not updating data from one Activity to another Activity - Android
我有2个Activity
即
- 列表
Activity
- 详情
Activity
列表 Activity
显示项目列表,单击列表中的项目显示详细信息 Activity
。
在 ListActivity
中,我们观察从数据库中获取提要,一旦完成,我们就会更新 UI.
列表页
feedViewModel.getFeeds().observe(this, Observer { feeds ->
feeds?.apply {
feedAdapter.swap(feeds)
feedAdapter.notifyDataSetChanged()
}
})
现在我们有一个更新提要(项目)的 DetailActivity
页面,Activity
已完成,但更改未反映在 ListActivity
中。
详情页
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
feedViewModel.setFeedId(id)
feedViewModel.updateFeed()
}
供稿视图模型
class FeedViewModel(application: Application) : AndroidViewModel(application) {
private val feedRepository = FeedRepository(FeedService.create(getToken(getApplication())),
DatabaseCreator(application).database.feedDao())
/**
* Holds the id of the feed
*/
private val feedId: MutableLiveData<Long> = MutableLiveData()
/**
* Complete list of feeds
*/
private var feeds: LiveData<Resource<List<Feed>>> = MutableLiveData()
/**
* Particular feed based upon the live feed id
*/
private var feed: LiveData<Resource<Feed>>
init {
feeds = feedRepository.feeds
feed = Transformations.switchMap(feedId) { id ->
feedRepository.getFeed(id)
}
}
/**
* Get list of feeds
*/
fun getFeeds() = feeds
fun setFeedId(id: Long) {
feedId.value = id
}
/**
* Update the feed
*/
fun updateFeed() {
feedRepository.updateFeed()
}
/**
* Get feed based upon the feed id
*/
fun getFeed(): LiveData<Resource<Feed>> {
return feed
}
}
为简单起见,一些代码已被抽象化。如果需要,我可以添加它们来追踪问题
经过大量调查和 从另一个问题中得出的一些想法。我想通了这个问题。
问题
DatabaseCreator(application).database.feedDao()
没有创建数据库的单例实例,因此第一个 Activity
有另一个实例,其中 LiveData
正在侦听更改,第二个 Activity
有更新数据后回调被忽略的另一个实例。
解决方案
使用 Dagger 或任何其他依赖注入来确保只创建 DB 和 DAO 的单个实例。
我在同一实体的多个活动中遇到了同样的问题。对我来说,将 Room Database 实例编码为 Singleton 很有用,例如:this (step 5)
示例:
public abstract class MyDatabase extends RoomDatabase {
private static MyDatabase mMyDatabase;
public static MyDatabase getInstance(Context context) {
if(mMyDatabase==null){
mMyDatabase = Room.databaseBuilder(context.getApplicationContext(), MyDatabase.class, "app_database").build();
return mMyDatabase;
}
}
}
并且在您拥有的每个 ViewModel 中(class 从 AndroidViewModel 扩展了 Context 参数):
public MyViewModel(@NonNull Application application) {
super(application);
mMyDatabase = MyDatabase.getInstance(application.getApplicationContext());
}
现在,就我而言,每次我在配置活动中编辑一个值时,它都会反映在其他活动中。
希望对您有所帮助。
我遇到了同样的问题。在下面的代码中,我忘记了一行并且单例没有工作(问题与主要答案中的问题相同)。
@Database(entities = [SleepNight::class], version = 1, exportSchema = false)
abstract class SleepDatabase : RoomDatabase() {
abstract val sleepDatabaseDao: SleepDatabaseDao
companion object {
@Volatile
private var INSTANCE: SleepDatabase? = null
fun getInstance(context: Context): SleepDatabase {
synchronized(this) {
var instance = INSTANCE
if (instance == null) {
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
}
return instance
}
}
}
}
忘记行:
INSTANCE = instance
我有2个Activity
即
- 列表
Activity
- 详情
Activity
列表 Activity
显示项目列表,单击列表中的项目显示详细信息 Activity
。
在 ListActivity
中,我们观察从数据库中获取提要,一旦完成,我们就会更新 UI.
列表页
feedViewModel.getFeeds().observe(this, Observer { feeds ->
feeds?.apply {
feedAdapter.swap(feeds)
feedAdapter.notifyDataSetChanged()
}
})
现在我们有一个更新提要(项目)的 DetailActivity
页面,Activity
已完成,但更改未反映在 ListActivity
中。
详情页
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
feedViewModel.setFeedId(id)
feedViewModel.updateFeed()
}
供稿视图模型
class FeedViewModel(application: Application) : AndroidViewModel(application) {
private val feedRepository = FeedRepository(FeedService.create(getToken(getApplication())),
DatabaseCreator(application).database.feedDao())
/**
* Holds the id of the feed
*/
private val feedId: MutableLiveData<Long> = MutableLiveData()
/**
* Complete list of feeds
*/
private var feeds: LiveData<Resource<List<Feed>>> = MutableLiveData()
/**
* Particular feed based upon the live feed id
*/
private var feed: LiveData<Resource<Feed>>
init {
feeds = feedRepository.feeds
feed = Transformations.switchMap(feedId) { id ->
feedRepository.getFeed(id)
}
}
/**
* Get list of feeds
*/
fun getFeeds() = feeds
fun setFeedId(id: Long) {
feedId.value = id
}
/**
* Update the feed
*/
fun updateFeed() {
feedRepository.updateFeed()
}
/**
* Get feed based upon the feed id
*/
fun getFeed(): LiveData<Resource<Feed>> {
return feed
}
}
为简单起见,一些代码已被抽象化。如果需要,我可以添加它们来追踪问题
经过大量调查和
问题
DatabaseCreator(application).database.feedDao()
没有创建数据库的单例实例,因此第一个 Activity
有另一个实例,其中 LiveData
正在侦听更改,第二个 Activity
有更新数据后回调被忽略的另一个实例。
解决方案
使用 Dagger 或任何其他依赖注入来确保只创建 DB 和 DAO 的单个实例。
我在同一实体的多个活动中遇到了同样的问题。对我来说,将 Room Database 实例编码为 Singleton 很有用,例如:this (step 5)
示例:
public abstract class MyDatabase extends RoomDatabase {
private static MyDatabase mMyDatabase;
public static MyDatabase getInstance(Context context) {
if(mMyDatabase==null){
mMyDatabase = Room.databaseBuilder(context.getApplicationContext(), MyDatabase.class, "app_database").build();
return mMyDatabase;
}
}
}
并且在您拥有的每个 ViewModel 中(class 从 AndroidViewModel 扩展了 Context 参数):
public MyViewModel(@NonNull Application application) {
super(application);
mMyDatabase = MyDatabase.getInstance(application.getApplicationContext());
}
现在,就我而言,每次我在配置活动中编辑一个值时,它都会反映在其他活动中。
希望对您有所帮助。
我遇到了同样的问题。在下面的代码中,我忘记了一行并且单例没有工作(问题与主要答案中的问题相同)。
@Database(entities = [SleepNight::class], version = 1, exportSchema = false)
abstract class SleepDatabase : RoomDatabase() {
abstract val sleepDatabaseDao: SleepDatabaseDao
companion object {
@Volatile
private var INSTANCE: SleepDatabase? = null
fun getInstance(context: Context): SleepDatabase {
synchronized(this) {
var instance = INSTANCE
if (instance == null) {
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
}
return instance
}
}
}
}
忘记行:
INSTANCE = instance