【问题标题】:Android ViewModel observer not called from background未从后台调用 Android ViewModel 观察者
【发布时间】:2019-09-12 14:46:38
【问题描述】:

我正在使用 MVVM 模式开发小型 android 应用程序。 我的问题是我的 ViewModel MyActivity 中的观察者没有从后台调用。即使应用程序在后台,我也需要调用它以向用户显示系统 Notification 应用程序计算过程已完成并且结果已准备好。

这是位于onCreate in MyActivity 中的当前实现:

mainActivityViewModel.getTestResult().observe(MainActivity.this, new Observer<String>() {
        @Override
        public void onChanged(@Nullable String blogList) {
            Toast.makeText(getApplicationContext(), "test...", Toast.LENGTH_SHORT).show();
            if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)){
                //The app is in foreground - showDialog
            }else{
                //The app is in background - showNotification
            }
        }

目前,仅当应用程序处于前台时才会调用此观察者 - 如果进程在应用程序处于前台时完成 - 'showDialog' 将触发,如果应用程序处于后台 - showNotification 将触发 - 但仅在之后我会再次打开应用程序。这不是我试图实现的行为。请帮忙!谢谢。

【问题讨论】:

  • 你不能这就是android的工作方式......但你可以尝试为此使用前台服务
  • 嗨@Selvin,您能详细说明一下吗?什么样的服务?谢谢。

标签: android android-mvvm


【解决方案1】:

onChanged 仅在Activity 的当前Lifecycle 状态至少为STARTED 时才会被调用。当您离开 Activity 时,onPause 会被调用,这意味着它至少不是 STARTED

LiveData 根本不适合您想要实现的行为。

我建议您改用前景Service。特别是如果提到的“计算过程”是用户应该知道的。

编辑: 假设您正在后台执行一些可能长时间运行的任务,并且即使用户会离开甚至关闭您的Activity,您也希望继续执行此任务。然后使用Service 是一个不错的选择,如果任务是用户操作的结果,尤其是前景Service。例如,用户点击“上传”按钮,前台Service 执行任务,相关联的Notification 显示“上传中”。

你可以选择

  • 任务完成时始终显示新的Notification,无论是否显示Activity。这很常见。
  • 仅当 Activity 当前启动时才显示 Notification,如果已启动,则改为在 Activity 视图中显示某些内容。

为了执行后一个选项,您需要知道ActivityLifecycle 的当前状态。您希望能够以某种方式从您的服务中进行以下检查:getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)

ActivityService 之间进行通信的最佳方式是bindingService 并在服务中扩展Binder 类。

绑定后,您可以将ActivityLifecycle状态存储在Service的变量中,甚至可以将Activity本身提供给Service

【讨论】:

  • 嗨 @Isak,从 MVVM 架构的角度来看,不是从 View 而是从 ViewModelService 触发 Notification 可以吗?如果是这样,我如何知道ViewModelService 中的应用程序状态?谢谢。
  • 编辑后回复:@Isak,如果我将使用绑定到活动的服务,那么我不需要 ViewModel。在这种情况下,这将不是 MVVM 模式 - 这是我的应用程序的强制性要求。如何使用 ViewModel 实现这一点?谢谢。
  • 如果你坚持将它硬塞到 MVVM 中,那么我会这样做:绑定到 ViewModel 中的服务。使用 onCleared 解除绑定。有一个你在 Activity 中观察到的 livedata 变量。在您的视图模型中,使用 LiveData.hasActiveObservers 来了解您的 Activity 当前是否正在观察以了解是否显示通知或只是通知 Activity 事件。要绑定到 ViewModel 中的服务,请扩展 AndroidViewModel 以访问应用程序上下文。
【解决方案2】:

我猜你在 ViewModel 中的 getTestResult() 返回了一些实时数据。

首先,您使用.setValue(some_data) 方法为您的真实数据分配LiveData。并且在应用程序打开时工作正常。 Btu 当您的应用程序在后台时。您需要使用.postValue(some_data) 方法为该 LiveData 分配数据。

检查以下差异:

setValue()

设置值。如果有活跃的观察者,值将被分派给他们。该方法必须从主线程调用。

postValue()

将任务发布到主线程以设置给定值。如果您在主线程执行发布的任务之前多次调用此方法,则只会分派最后一个值。

结论,主要区别在于:

setValue() 方法必须从主线程调用。但是如果你需要从后台线程设置一个值,应该使用 postValue()。

【讨论】:

    【解决方案3】:

    你正在尝试做的事情是可能的,但不是你正在做的事情。

    LiveData API 的全部目的是以生命周期感知的方式将数据层与 UI 链接起来,因此当应用不在前台时,观察者会知道这一点并停止更新 UI。

    观察者的第一个参数是生命周期。

    这是一个很大的改进,因为没有它,由于 UI 不可用而导致的崩溃太频繁,或者它太复杂而无法手动控制(样板、边缘情况等)。

    服务不是一个好主意,因为如果前台应用程序需要内存,服务可能会被 DALVIK 或 ANT 机器杀死。服务不在前台,但这并不意味着它们必须绑定到后台,也不能保证在不确定的时间跨度内工作。

    为了做你想做的事,请使用WorkManager。 WorkManager 允许您安排有条件或无条件的作业,并且您可以从那里向用户发送通知。

    您可以尝试结合使用 Workmanager 和 Viewmodel 来实现前台/后台应用功能。

    为此使用 Activity 生命周期:

    • 使用 onResume 方法删除任何 WorkManager 并使用 ViewModel 加注星标
    • 使用 onPause 方法启动 WorkManager

    【讨论】:

    • 嗨@cutiko,我已经尝试了你的建议。它工作正常,但现在我有另一个问题。我的WorkManager怎么知道应用状态?只有当应用程序处于后台状态时,我才需要 Notification 触发。现在的结果是Notification,即使应用程序也处于前台,也会显示。谢谢!
    【解决方案4】:

    要处理声明,您可以在成功检索数据的 ViewModel 类的函数内部编辑或关闭声明。

    private fun dataShow(list: List<String>) {
       
       //Notification cancel
        NotificationManagerCompat.from(getApplication()).cancel(30)
        
        
        if (list.isNotEmpty()) {
            data.value = list
            progressHome.value = false
        } else {
            progressHome.value = true
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-22
      • 1970-01-01
      • 1970-01-01
      • 2019-06-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多