【问题标题】:Android ViewModel: Should I "borrow" the observe() method from LiveData like in the official example?Android ViewModel:我应该像官方示例中那样从 LiveData“借用”observe() 方法吗?
【发布时间】:2018-09-05 19:05:33
【问题描述】:

当使用 ViewModel 时,View 会观察 ViewModel。它必须注册为观察者。在 Google 的 official tutorial 中,此注册被委托给 LiveData 对象的 observe() 方法。

public class MyViewModel extends ViewModel {
    private MutableLiveData<List<User>> users;
    public LiveData<List<User>> getUsers() {
        if (users == null) {
            users = new MutableLiveData<List<Users>>();
            loadUsers();
        }
        return users;
    }

    private void loadUsers() {
        // Do an asynchronous operation to fetch users.
    }
}

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        // Create a ViewModel the first time the system calls an activity's onCreate() method.
        // Re-created activities receive the same MyViewModel instance created by the first activity.

        MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
        model.getUsers().observe(this, users -> {
            // update UI
        });
    }
}

getUsers() 方法返回 LiveData 对象本身。它的observe() 方法用于注册观察者。 View 没有观察到ViewModel,而是它的实现的一部分。

现在这是最佳实践,当与ViewModels 合作时,不是观察自己,而是以LiveData 对象的形式观察它们的部分实现?还是这是低质量的介绍?

【问题讨论】:

    标签: android observer-pattern android-livedata android-viewmodel


    【解决方案1】:

    我会说是的,ViewModel 的最佳做法是通过某种形式的 Observable 公开其数据,无论是 LiveData 还是类似于 RX Observable 的东西。

    这与 MVP 等其他架构不同,在这种架构中,演示者通常会引用视图,当某些事情发生变化时会调用该视图。该指南对 ViewModel 应参考的内容非常具体。

    A ViewModel must never reference a view, Lifecycle, or any class that may hold a reference to the activity context.
    

    通过 ViewModel 将您的数据公开为 Observable,这意味着视图可以来来去去,一旦订阅,将收到最新数据和任何后续更新。再次,指南有一些细节。

    If the activity is re-created, it receives the same MyViewModel instance that was created by the first activity. When the owner activity is finished, the framework calls the ViewModel objects's onCleared() method so that it can clean up resources
    

    https://developer.android.com/topic/libraries/architecture/viewmodel.html

    【讨论】:

    • 首先它打破了面向对象编程的一个非常基本的原则,即实现细节的封装。我还是挠头。你说的对。如果视图应该观察ViewModel,则ViewModel 将在观察者注册后持有对视图/活动的引用。尽管如此,如果我以传统的封装方式实现它,一切都会继续工作。 View 和 ViewModel 被清理,当上下文消失时,onCleared() 被按预期调用,如果我愿意,我什至可以清理 onCleared() 中的引用。
    • 我猜我的经典实现工作的原因是,新的参考取代了旧的参考。例如,在旋转之后,新的观察者替换了旧的观察者并且参考消失了。这仍然不是很干净。我可能会迟到。
    • 我能想到一个干净的解决方案。为此,观察者的注册必须看起来就像注册LiveData observe(LifecycleOwner owner, Observer&lt;T&gt; observer) 本身一样,另外需要LifecycleOwner。然后我有我需要的所有成分,在内部委托给LiveData而不暴露实现本身。
    【解决方案2】:

    根据克里斯的回答,我给出了自己的答案。我认为本教程不是最佳实践,原因很简单,一个对象不应该暴露它的内部实现。基于 Chris 的论证,我正在寻找一种在不丢失命名功能的情况下进行封装的选项。结果是方法observerUsers() 在内部委托给LiveData 对象。

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            MainActivityViewModel model = ViewModelProviders.of(this).get(MainActivityViewModel.class);
            model.observeUsers(this,
                    new Observer<List<User>>() {
                        @Override
                        public void onChanged(@Nullable List<User> users) {
                            updateUI();
                        }
                    }
            );
        }
    
        void updateUI() {
    
        }
    
        static class MainActivityViewModel extends ViewModel {
            private MutableLiveData<List<User>> users;
    
            public void observeUsers(@NonNull LifecycleOwner owner,
                                     @NonNull Observer<List<User>> observer) {
                getUsers().observe(owner, observer);
            }
    
            private LiveData<List<User>> getUsers() {
                if (users == null) {
                    users = new MutableLiveData<>();
                    loadUsers();
                }
                return users;
            }
    
            private void loadUsers() {
                // Do an asynchronous operation to fetch users.
            }
        }
    
        static class User {
        }
    
    }
    

    仍然List&lt;User&gt; 公开内部实现。可以改进为 Users 类。

    我将所有内容放入一个文件并使用内部静态类。这并不意味着最佳实践。只是为了能够快速编辑一个文件中的所有内容。尤其是模型User属于它自己的文件,而我经常把ViewModel放到它所属的View类中。

    我的第二个批评点与ViewModel 本身观察底层模型的情况相匹配。在这种情况下,观察者方法onChange() 非常通用,需要一个非常通用的更新方法,例如updateUI()。您可能希望观察模型的更具体事件以进行具体更新。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-23
      • 1970-01-01
      相关资源
      最近更新 更多