如果我清理后面的引用,是否可以观察ViewModel? [英] Am I allowed to observe a ViewModel, if I clean up the back references?

查看:74
本文介绍了如果我清理后面的引用,是否可以观察ViewModel?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

The suggested way to implement ViewModel is to expose the changing data by using LiveData objects to activities, fragments and views. There are cases, when LiveData is not an ideal answer or no answer at all.

自然的选择是将观察者模式应用于ViewModel,使其可观察.将观察者注册到ViewModel时,ViewModel将保留回调引用以通知观察者.

The natural alternative would be, to apply the observer pattern to the ViewModel, make it an observable. When registering observers to the ViewModel, the ViewModel will hold callback references to notify the observers.

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

The documentation says, a ViewModel must not hold references to activities, fragments or views. The only answer to the question "why" I found is, that this may cause memory leaks. Then how about cleaning up the references to avoid memory leaks?

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

For views this is a difficulty. There is no defined moment, when the view goes away. But activities and fragments have a defined lifecycle. So there are places to unregister as observers.

您怎么看?如果您要始终注销活动,则将其注册为观察者作为ViewModels是否有效?您是否找到了有关此问题的任何有效信息?

What do you think? Is it valid to register activities as observers to ViewModels if you take care to always unregister them? Did you hit upon any valid information about this question?

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

I set a small reward for the best answer. It's not because I think it a recommended solution (as it does not work with views). I just want to know and extend my options.

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);
    }
}

IMO,

推荐答案

问我被允许..."并不是一个真正有用的问题.该文档很明显,您的建议是不鼓励的,为什么.就是说,我希望您的代码可能会按预期工作,因此是允许的"(即不受技术限制).

To ask "am I allowed..." is not really a useful question, IMO. The docs are clear that what you are suggesting is discouraged and why. That said, I expect that your code would probably work as expected and is therefore "allowed" (i.e. not prevented by a technical constraint).

一个可能的陷阱场景:ExampleActivity的InstanceA启动并启动了ExampleViewModel上一些长时间运行的任务.然后,在任务完成之前,由于配置更改,设备已旋转并且InstanceA被销毁.然后,在销毁InstanceA到创建新InstanceB的时间之间长时间运行的任务完成,并且视图模型调用onEndListener.onEnd().除了:哦,不! onEndListener之所以是null,是因为当InstanceA被销毁并且尚未由InstanceB设置时,它已被清除:NullPointerException

One possible gotcha scenario: InstanceA of ExampleActivity is started and kicks off some long-running task on the ExampleViewModel. Then, before the task completes, the device is rotated and InstanceA is destroyed because of the configuration change. Then, in between the time when InstanceA is destroyed and a new InstanceB is created, the long-running task completes and your view model calls onEndListener.onEnd(). Except: Oh no! The onEndListener is null because it was cleared when InstanceA was destroyed and hasn't yet been set by InstanceB: NullPointerException

ViewModel被(部分地)精确地设计为 ,以处理诸如上述陷阱"场景之类的极端情况.因此,为什么不仅仅使用它与LiveData一起提供的工具来完成同一件事,而不是违反ViewModel的预期用途? (并且用更少的代码,我可能会添加.)

ViewModel was designed (in part) precisely to handle edge cases like the gotcha scenario above. So instead of working against the intended use of the ViewModel, why not just use the tools it offers along with LiveData to accomplish the same thing? (And with less code, I might add.)

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的信号.我一直在使用这种模式.

Think of the LiveData in this case not as actual "data" per se, but as a signal that you can pass from your ViewModel to your Activity. I use this pattern all the time.

这篇关于如果我清理后面的引用,是否可以观察ViewModel?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆