3

建议的实现方式是通过使用对象到活动、片段和视图ViewModel来公开变化的数据。LiveData在某些情况下,当LiveData不是一个理想的答案或根本没有答案时。

自然的替代方法是将观察者模式应用于ViewModel,使其成为可观察的。当向 注册观察者时ViewModelViewModel将持有回调引用以通知观察者。

文档说,aViewModel不得包含对活动、片段或视图的引用。我发现“为什么”这个问题的唯一答案是,这可能会导致内存泄漏。那么如何清理引用以避免内存泄漏呢?

对于视图,这是一个困难。当视野消失时,没有明确的时刻。但是活动和片段具有定义的生命周期。所以有些地方可以取消注册为观察员。

你怎么看?ViewModels如果您注意始终取消注册活动,那么将活动注册为观察者是否有效?您是否找到有关此问题的任何有效信息?

我为最佳答案设置了一个小奖励。这不是因为我认为它是推荐的解决方案(因为它不适用于视图)。我只想知道并扩展我的选择。

public class ExampleViewModel extends ViewModel {

    public interface OnEndListener {
        public void onEnd();
    }

    private List<OnEndListener> onEndListeners = new ArrayList<>();

    public void setOnEndListener(OnEndListener onEndListener) {
        onEndListeners.add(onEndListener);
    }

    public void removeOnEndListener(OnEndListener onEndListener) {
        onEndListeners.remove(onEndListener);
    }

    public void somethingHappens() {
        for (OnEndListener onEndListener: new ArrayList<OnEndListener>(onEndListeners) ) {
            onEndListener.onEnd();
        }
    }
}

public class ExampleActivity extends AppCompatActivity {

    ExampleViewModel exampleViewModel;
    ExampleViewModel.OnEndListener onEndListener;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        onEndListener = new ExampleViewModel.OnEndListener() {
            @Override
            public void onEnd() {
                finish();
            }
        };
        exampleViewModel = ViewModelProviders.of(this).get(ExampleViewModel.class);
        exampleViewModel.setOnEndListener(onEndListener);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        exampleViewModel.removeOnEndListener(onEndListener);
    }
}
4

1 回答 1

2

问“我被允许......”并不是一个真正有用的问题,IMO。文档很清楚,不鼓励您提出的建议以及原因。也就是说,我希望您的代码可能会按预期工作,因此是“允许的”(即不受技术限制的阻碍)。

一个可能的问题场景:InstanceAExampleActivity已启动并在ExampleViewModel. 然后,在任务完成之前,设备旋转,InstanceA 因配置更改而被销毁。然后,在销毁 InstanceA 和创建新 InstanceB 之间,长时间运行的任务完成并且您的视图模型调用onEndListener.onEnd(). 除了:哦不!这onEndListenernull因为它在InstanceA被销毁并且尚未被InstanceB设置时被清除:NullPointerException

ViewModel被设计(部分)精确地处理像上面的陷阱场景这样的边缘情况。因此,与其违背 . 的预期用途ViewModel,不如直接使用它提供的工具LiveData来完成同样的事情?(我可能会添加更少的代码。)

public class ExampleActivity extends AppCompatActivity {

    ExampleViewModel exampleViewModel;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        exampleViewModel = ViewModelProviders.of(this).get(ExampleViewModel.class);
        exampleViewModel.getOnEndLive().observe(this, new Observer<Boolean>() {
            @Override
            public void onChanged(@Nullable Boolean onEnd) {
                if (onEnd != null && onEnd) {
                    finish();
                }
            }
        });

    }
}

public class ExampleViewModel extends ViewModel {

    private MutableLiveData<Boolean> onEndLive = new MutableLiveData<>();

    public MutableLiveData<Boolean> getOnEndLive() {
        return onEndLive;
    }

    public void somethingHappens() {
        onEndLive.setValue(true);
    }
}

在这种情况下,不应将 LiveData 视为实际的“数据”本身,而是将其视为可以从 ViewModel 传递到 Activity 的信号。我一直使用这种模式。

于 2018-05-03T06:25:49.917 回答