从前台服务观察LiveData

27

我有一个存储LiveData对象的代码库,它通过ViewModel同时被活动和前台服务使用。 当我从活动开始观察时,一切都像预期的那样工作。 但是从服务中观察没有触发观察。 这是我使用的代码:

class MyService: LifecycleService() {
     lateinit var viewModel: PlayerServiceViewModel

     override fun onCreate() {
          viewModel = MyViewModel(applicationContext as Application)
     }

     override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
          viewModel.getLiveData().observe(this, Observer { data ->
            // Do something with the data
        })
     }
}

你有什么思路为什么它不起作用,我没有收到数据吗?

1个回答

33

我在LifecycleActivityFragments中使用了ViewModelLiveData,并且它按预期工作并观察数据。

谈到你的问题,当你从Service或其他Activity创建新的ViewModel时,它会创建所有LiveData和其他依赖项的新实例,以便ViewModel可以从Repository查询,最终到DAO。 如果你没有为两个ViewModels使用相同的DAO,那么你的LiveData可能不会更新,因为它正在观察不同 DAO实例

我在我的项目中使用了Dagger2来维护DAO和其他常见依赖项的Singleton实例。因此,你可以尝试将你的Repository和DAO设置为singleton,以保持跨应用程序的一致性。

我在LifecycleService中使用了相同的流程与Services一起尝试了它,并且它对我有用。

当数据从null变为提取的数据时,我得到了以下输出。

D/ForegroundService: onStartCommand: Resource{status=LOADING, message='null', data=null}
D/ForegroundService: onStartCommand: Resource{status=SUCCESS, message='null', data=TVShow(id=14,...

一开始,由于数据库中没有数据,所以显示为空数据。

从网络中获取数据并将其更新到数据库后,Observer会自动观察到数据。

下面的代码可用于解决该问题。

public class ForegroundService extends LifecycleService {

    private static final String TAG = "ForegroundService";

    private TVShowViewModel tvShowViewModel;
    private TVShow tvShow;

    @Inject TVShowDataRepo tvShowDataRepo;

    @Override
    public void onCreate() {
        super.onCreate();

        AndroidInjection.inject(this);
        tvShowViewModel = new TVShowViewModel(tvShowDataRepo);
        tvShowViewModel.init(14);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        tvShowViewModel.getTVShow().observe(this, tvShowResource -> {
            Log.d(TAG, "onStartCommand: " + tvShowResource);
        });
        return super.onStartCommand(intent, flags, startId);
    }
}

3
感谢您提供详细的答案。我一直在使用单例模式,但问题实际上是因为缺少super.onCreate()super.onStartCommand()引起的。在更新AS和kotlin插件后,我发现它们开始抱怨缺少这些调用,然后我意识到了这个问题。 - Ilya Sosis
3
不建议在服务中使用ViewModels。请参见此处 - hara
2
@hara 是的。他们不建议在服务中使用它,因为“Service”没有持有任何视图,并且使用“ViewModel”作为其生命周期感知视图(如Activity和Fragments)是没有意义的。 但是,我们可以使用不同的类来保存我们的“LiveData”,而不是使用“ViewModel”,因为这些“LiveData”观察者的上下文无论如何都是服务。 因此,我们将能够访问“LiveData”,而无需在“ViewModel”内定义它。 - adityakamble49
@adityakamble49 当我将我的服务扩展为LifecycleService时,我遇到了这个异常:
java.lang.InstantiationException: ...没有零参数构造函数
如果我搜索一下,通常这个错误会出现在IntentService中,但这不是一个IntentService。我有正确的注入。你有什么想法如何解决这个问题吗?
- Wahib Ul Haq
4
在服务中,我们可以使用单例模式的 DAO 实例,并在服务中更新 DAO,从而自动更新由活动使用的 ViewModel 中的数据,从而更新 UI,而不是在服务中使用 ViewModel。 - Samyak
@Samyak,+. ViewModel存在于UI中,而不是服务中。在服务中,我们必须在没有ViewModel的情况下访问内存,例如使用Repository。 - FreePhoenix888

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接