JetPack架构---LiveDataViewModel搭建MVVM结构工程
Posted 战国剑
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JetPack架构---LiveDataViewModel搭建MVVM结构工程相关的知识,希望对你有一定的参考价值。
一、MVVM与JetPack
MVVM,是Model-View-ViewModel的简写。Model:数据,View:UI相关,ViewModel:UI相关数据与控制。
JetPack提供的组件LiveData与ViewModel,十分契合该模式。
(1)LiveData作为数据驱动的核心,驱动与监听Model数据变化。
(2)ViewModel组件,作为页面数据管理的存储与控制中心。
(3)Activity或Fragment,也就是MVVM中的View。
MVVM的核心在于,通过数据驱动修改UI,实现上数据与UI解耦,方便切面测试,易于扩展,也让开发人员可独立开发数据或者UI相关。
二、JetPack为核心的MVVM架构实现
以下将以一个获取天气预报信息作为例子。从搭建结构到示例各模块的简单实现。
2-0:工程结构
新建工程结构如下:
(1)数据层model中包含本地数据、网络接口数据,以及管理这两个数据源的数据仓库Repository。
(2)UI层,放置Activity、Fragment等页面元素。UI层持有ViewModel的数据引用,监听ViewModel数据的变化。
(3)ViewModel层,作为model与view的中间连接层,持有对model层的引用。但ViewModel不会持有View的引用,避免内存泄漏。
2-1:ViewModel定义
定义一个PlaceViewModel,管理页面数据
public class PlaceViewModel extends ViewModel
//此处定义的LiveData,只在该类内部使用。
//意义在于:通过触发该LiveData的数据改变,联动的驱动apiResponseLiveData从Repository获取数据
private MutableLiveData<Object> queryPlacesLiveData = new MutableLiveData<>();
//UI页面实际监听的LiveData
public LiveData<ApiResponse<PlaceResponse>> apiResponseLiveData = Transformations.switchMap(queryPlacesLiveData, new Function<Object, LiveData<ApiResponse<PlaceResponse>>>()
@Override
public LiveData<ApiResponse<PlaceResponse>> apply(Object input)
//从数据仓库中,获取LiveData格式的数据
return Repository.getInstance().queryPlaces();
);
//UI页面调用该方法,作为查询数据驱动
public void queryPlaces()
queryPlacesLiveData.setValue(queryPlacesLiveData.getValue());
2-2:UI页面对ViewModel的监听与调用
//获取ViewModel
final PlaceViewModel placeViewModel = new ViewModelProvider(MainActivity.this,new ViewModelProvider.androidViewModelFactory(getApplication())).get(PlaceViewModel.class);
//监听该ViewModel中apiResponseLiveData的数据变化
placeViewModel.apiResponseLiveData.observe(this, new Observer<ApiResponse<PlaceResponse>>()
@Override
public void onChanged(ApiResponse<PlaceResponse> placeResponseApiResponse)
Log.e(TAG, "onChanged: ");
);
queryPlaces = findViewById(R.id.query_places);
queryPlaces.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
//调用方法,驱动数据变化
placeViewModel.queryPlaces();
);
2-3:数据仓库Repository的定义
Repository作为数据仓库,在工程中以单例的形式存在即可。该仓库中,可包含多个数据源,如本地数据库、本地缓存、网络接口数据等,该仓库也适合作为测试的切面使用。
获取数据库、缓存等较为简单,参照前文的Room数据库使用即可。此处只介绍如何合理的获取网络接口数据(以Retrofit为例)。
public class Repository
private static final Repository ourInstance = new Repository();
public static Repository getInstance()
return ourInstance;
private Repository()
public LiveData<ApiResponse<PlaceResponse>> queryPlaces()
//获取网络数据
return ServiceManager.getInstance().create(PlaceService.class).queryPlaces();
ServiceManager作为网络接口的管理类,以Retrofit为基础,操作接口。此处有别于通常的Retrofit的地方在于:采用了LiveDataCallAdapterFactory,作为接口数据转换的工厂,该类的作用在于把接口数据全部转为LiveData格式,当ViewModel调用接口方法时,直接能得到LiveData格式的数据。
public class ServiceManager
private Retrofit retrofit;
private PlaceService placeService;
private String baseUrl = "https://api.caiyunapp.com/";
private static final ServiceManager ourInstance = new ServiceManager();
public static ServiceManager getInstance()
return ourInstance;
private ServiceManager()
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
//此处为LiveData格式转换的特殊处理
.addCallAdapterFactory(new LiveDataCallAdapterFactory())
.build();
public <T> T create(Class<T> serviceClass)
return retrofit.create(serviceClass);
2-3-0:LiveDataCallAdapterFactory的定义
该类的定义,参照android系统本身的DefaultCallAdapterFactory即可。只需重写父类中的get方法。
public class LiveDataCallAdapterFactory extends CallAdapter.Factory
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit)
//返回类型必定需要是LiveData
if (getRawType(returnType) != LiveData.class)
return null;
else if (!(returnType instanceof ParameterizedType))
throw new IllegalArgumentException("type must be parameterized as Call<Foo> or Call<? extends Foo>");
else
//首个参数
final Type responseType = getParameterUpperBound(0, (ParameterizedType)returnType);
//获取该参数的类
Class<?> rawResponseType = getRawType(responseType);
//rawResponseType 判断是否符合要求
if(rawResponseType != ApiResponse.class)
throw new IllegalArgumentException("type must be ApiResponse");
return new LiveDataCallAdapter<>(responseType);
2-3-1:LiveDataCallAdapter的定义
//R为传入的的类对象
public class LiveDataCallAdapter<R> implements CallAdapter<R, LiveData<ApiResponse>>
private Type responseType;
public LiveDataCallAdapter(Type responseType)
this.responseType = responseType;
@Override
public Type responseType()
return responseType;
@Override
public LiveData<ApiResponse> adapt(final Call<R> call)
//返回一个LiveData格式数据
return new LiveData<ApiResponse>()
AtomicBoolean started = new AtomicBoolean(false);
@Override
protected void onActive()
super.onActive();
//避免多次调用
if (started.compareAndSet(false, true))
//方法入队,发起请求
call.enqueue(new Callback<R>()
@Override
public void onResponse(Call<R> call, Response<R> response)
ApiResponse responseData = new ApiResponse<>();
if (response.isSuccessful())
responseData = (ApiResponse) response.body();
else
responseData.setData(null);
responseData.setCode(response.code());
responseData.success = true;
responseData.code = response.code();
postValue(responseData);
@Override
public void onFailure(Call<R> call, Throwable t)
ApiResponse responseData = new ApiResponse<>();
responseData.code = -1;
responseData.data = null;
responseData.success = false;
responseData.message = Log.getStackTraceString(t);
postValue(responseData);
);
;
最后,再看下retrofit的接口定义:
public interface PlaceService
@GET("v2.5/"+TOKEN+"/121.6544,25.1552/weather.json")
LiveData<ApiResponse<PlaceResponse>> queryPlaces();
至此,已经完成了一个基于JetPack中的 LiveData与ViewModel的MVVM框架。该框架根据LiveData与ViewModel的特性,十分简单的实现了数据驱动,UI响应数据驱动发生变化。组件本身的生命周期自我控制的特性,也减少了我们工程中可能发生的问题。
三、JetPack趋势
JetPack系列在android上的作用,十分类似Vue,React等在前端的作用。
官方提供组件,实现数据响应式框架。
目前,android-11的beta版本也对JetPack系列做了一系列的升级与更新。后续该系列将会越来趋于完善。
JetPack预计后续将成为android上的主流框架,android也将对这套组件框架做更多的升级与完善。
以上是关于JetPack架构---LiveDataViewModel搭建MVVM结构工程的主要内容,如果未能解决你的问题,请参考以下文章
Android Jetpack架构组件——什么是Jetpack?