您的位置:首页 > 运维架构 > 网站架构

[译]Android架构组件 – 查看ViewModel – 第二部分

2017-06-12 20:33 656 查看
原文链接:https://riggaroo.co.za/android-architecture-components-looking-viewmodels-part-2/

如果你回忆上一篇文章,下图指出了我们将如何组织我们的“日期倒计时”应用。



本文我们将创建上图显示的
EventListViewModel
AddEventViewModel
。可在这篇文章找到所有源码。在开始创建
ViewModels
之前,我们需要首先看看什么是
ViewModel


什么是ViewModel?

ViewModel
既不是新的概念,也不是Android的概念。 名
ViewModel
来自于2005年左右的Microsoft设计的MVVM模式。新的架构组件中,一个新类是
ViewModel
类。

ViewModel
负责为
View
准备数据。它们将数据暴露给正在监听更改的任何视图。在Android中,使用
ViewModel
类时应该记住一些具体的事实:

ViewModel
可以在Activity配置更改中保留其状态。它保存的数据立即可用于下一个Activity实例,而需要在
onSaveInstanceState()
中保存数据,并手动还原。

ViewModel
与特定的Activity或Fragment实例无关。

ViewModel
允许在Fragment之间轻松共享数据(意味着您不再需要通过ctivity来协调动作)。

ViewModel
将保持在内存中,直到
Lifecycle
范围永远消失 - Activity调用finish; 在Fragment调用ditached。

因为
ViewModel
独立于Activity或Fragment实例,它不直接引用其中的任何View或保持上下文的引用。真会导致内存泄漏

如果
ViewModel
需要应用的上下文(例如查找系统服务),它可继承
AndroidViewModel
类,并有一个构造函数来接收Application实例。

创建ViewModel

EventListViewModel

EventListViewModel
类用于打开日期倒计时应用打开时展示事件列表。

创建名为
EventListViewModel
的类。确保它从架构组件类继承
ViewModel
。类中,我们打算将之前放在
EventListFragment
中的代码迁移到
ViewModel
中。

EventListViewModel
中添加
LiveData
变量。EventRepository变量使用Dagger注入。
EventListViewModel
现在长这样:

public class EventListViewModel extends ViewModel implements CountdownComponent.Injectable {

private LiveData<List<Event>> events = new MutableLiveData<>();

@Inject
EventRepository eventRepository;

@Override
public void inject(CountdownComponent countdownComponent) {
countdownComponent.inject(this);
events = eventRepository.getEvents();
}

public LiveData<List<Event>> getEvents() {
return events;
}
}


现在在
EventListFragment
中,我们打算使用
ViewModel
替换事件加载代码:

public class EventListFragment extends LifecycleFragment {

private EventListViewModel eventListViewModel;

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//.. inflate view etc
eventListViewModel = ViewModelProviders.of(this, new CountdownFactory(countdownApplication).get(EventListViewModel.class);

eventListViewModel.getEvents().observe(this, events -> {
adapter.setItems(events);
});
return v;
}
}


包含
ViewModelProvider.of(..)
的行将创建一个新的
EventListViewModel
类(如果不存在),或者它将获取存在于定义的作用域(在这种情况下是
EventListFragment
)的类。这是神奇的地方。当设备旋转并且Fragment被重新创建时,将在此处返回的
ViewModel
是之前使用的。这允许我们保留屏幕的状态,而无需手动将信息保存到
Bundle
并自己恢复。

事件数据现在从
EventListViewModel
获取。如前所述,通过将其作为第一个参数,
LiveData
observable将自动为您管理。这意味着当Fragment不再使用时,Fragment将会处理可观察物。如果Fragment未启动或恢复,则不可调用observable回调。

创建一个Dagger组件
CountdownComponent
。我们将使用它来注入
ViewModel
的依赖。

@Singleton
@Component(modules = {CountdownModule.class})
public interface CountdownComponent {

void inject(EventListViewModel eventListViewModel);

void inject(AddEventViewModel addEventViewModel);

interface Injectable {
void inject(CountdownComponent countdownComponent);
}
}


创建自定义
ViewModelProvider.NewInstanceFactory
用于实例化
ViewModel
。当
ViewModelProvider
需要创建新的
ViewModel
实例,它将调用工厂类的
create
方法。

public class CountdownFactory extends ViewModelProvider.NewInstanceFactory {

private CountdownApplication application;

public CountdownFactory(CountdownApplication application) {
this.application = application;
}

@Override
public <T extends ViewModel> T create(Class<T> modelClass) {
T t = super.create(modelClass);
if (t instanceof CountdownComponent.Injectable) {
((CountdownComponent.Injectable) t).inject(application.getCountDownComponent());
}
return t;
}
}


删除
Event
,可以在
ViewModel
中添加一个方法。该方法委托
EventRepository
删除事件。本例中,使用Rxjava来代理后台线程。

public class EventListViewModel extends ViewModel implements CountdownComponent.Injectable {
//..
public void deleteEvent(Event event) {
eventRepository.deleteEvent(event)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
}

@Override
public void onComplete() {
Timber.d("onComplete - deleted event");
}

@Override
public void onError(Throwable e) {
Timber.e("OnError - deleted event: ", e);
}
});
}
}


在Fragment中,我们使用委托给ViewModel的删除方法:

View.OnClickListener deleteClickListener = v -> {
Event event = (Event) v.getTag();
eventListViewModel.deleteEvent(event);
};


对于
AddEventViewModel
的实现,查看完整代码示例

总结

新的Android架构组件解决了我们以前无法处理的常见情况。现在通过使用
ViewModel
ViewModelProvider
来处理屏幕旋转非常简单。

参考

ViewModel文档

Android架构组件文档

日期倒计时应用-完整代码

Dagger2 测试实例
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android