Android从零开始搭建MVVM架构(6) ———— 使用玩Android API带你搭建MVVM框架(初级篇)

在经历了半个月的AAC组件的学习,终于来到了最后一步。希望本文能够帮助到你。本demo架构RxJava + Retrofit + MVVM,并且围绕玩安卓API(感谢鸿洋)带大家一起搭建我们的MVVM项目。

从零开始搭建MVVM架构系列文章(持续更新):
Android从零开始搭建MVVM架构(1)————DataBinding
Android从零开始搭建MVVM架构(2)————ViewModel
Android从零开始搭建MVVM架构(3)————LiveData
Android从零开始搭建MVVM架构(4)————Room(从入门到进阶)
Android从零开始搭建MVVM架构(5)————Lifecycles
Android从零开始搭建MVVM架构(6)————使用玩Android API带你搭建MVVM框架(初级篇)
Android从零开始搭建MVVM架构(7) ———— 使用玩Android API带你搭建MVVM框架(终极篇)

在写文章之前我在想,为什么MVP之后还有MVVM框架呢,我们为什么要用MVVM呢?

在MVC衍变到MVP时。只是代码逻辑简洁了,View和Model也有解耦了,接手别人的项目时你的苦恼减少了。但是代价就是,接口爆炸,这也是做小项目的时候,根本不用它的原因。那么今天我们要讲的是MVVM。MVVM具备了MVP的优点外,而且不用像MVP那样写那么多接口了。ViewModel配合LiveData完成所有,又因为它具备生命周期,程序更健壮了,也不用写那么多判断代码了,更关键的是LiveData替代了那些接口,简直神奇了。

这里我想说下我的感受,框架的使用是个人的见解。每个人都不同。我这里搭建,是我的见解和想法。你可以借鉴我的思路,去搭建你自己的MVVM项目。


一、创建一个新项目(本节将完成一个banner广告的功能)

打开DataBinding

//加载项目build.gradle的anroid标签下
dataBinding {enabled = true}

添加相关依赖

 //okhttp、retrofit、rxjavaimplementation 'com.squareup.okhttp3:okhttp:3.8.0'implementation 'com.squareup.retrofit2:retrofit:2.3.0'implementation 'com.squareup.retrofit2:converter-gson:2.3.0'implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'implementation 'io.reactivex.rxjava2:rxjava:2.1.7'//放着没有及时回收造成RxJava内存泄漏implementation 'com.trello.rxlifecycle2:rxlifecycle-components:2.1.0'implementation 'android.arch.lifecycle:extensions:1.1.1'//Room的依赖引用implementation 'android.arch.persistence.room:runtime:2.1.4'annotationProcessor 'android.arch.persistence.room:compiler:2.1.4'//Room配合RxJava使用implementation 'android.arch.persistence.room:rxjava2:2.1.4'implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'//广告bannerimplementation 'com.youth.banner:banner:1.4.10'//glideimplementation 'com.github.bumptech.glide:glide:4.9.0'annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'

二、创建我们的Base

2.1 创建BaseViewModel

因为创建BaseActivity时,肯定要引入我们的BaseViewModel。所以我们要先创建BaseViewModel。我们知道,我们要把公共代码和重复代码全部封装在我们的Base里。当然这里我们还不知道我们的BaseViewModel要干嘛,先创建吧,之后要什么,补什么

//继承AndroidViewModel,是因为里面要用context时候直接可以getApplication()
public abstract class BaseViewModel extends AndroidViewModel {public BaseViewModel(@NonNull Application application) {super(application);}@Overrideprotected void onCleared() {super.onCleared();}
}

2.2 创建BaseActivity

baseActivity里有2个引用,DataBinding 和 ViewModel,用泛型把他添加进来,

//ViewDataBinding 是所有DataBinding的父类
public abstract class BaseActivity<VM extends BaseViewModel, VDB extends ViewDataBinding> extends AppCompatActivity {   //获取当前activity布局文件,并初始化我们的bindingprotected abstract int getContentViewId();//处理逻辑业务protected abstract void processLogic();protected VM mViewModel;protected VDB binding;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(getContentViewId());//初始化我们的bingingbinding = DataBindingUtil.setContentView(this, getContentViewId());//给binding加上感知生命周期,AppCompatActivity就是lifeOwner,之前解释过了,不懂看前面binding.setLifecycleOwner(this);//创建我们的ViewModel。createViewModel();processLogic();}public void createViewModel() {if (mViewModel == null) {Class modelClass;Type type = getClass().getGenericSuperclass();if (type instanceof ParameterizedType) {modelClass = (Class) ((ParameterizedType) type).getActualTypeArguments()[0];} else {//如果没有指定泛型参数,则默认使用BaseViewModelmodelClass = BaseViewModel.class;}mViewModel = (VM) ViewModelProviders.of(this).get(modelClass);}}
}

三、简单封装我们的Retrofit

我这里只是简单封装我们的Retrofit。本文终极篇demo RxJava + Retrofit联网(如果不熟悉,请看我另一篇解读)RxJava + Retrofit + MVP(看完还不明白,吐槽我。适合初学者,VIP版MVP框架!!)
其中封装包括的内容有:

  • 支持所有网络请求类型,get,post,put…(废话了!!Retrofit已经干了所有事情)
  • 支持上传文件并监听上传进度
  • 支持下载文件和断点下载并监听下载进度
  • 有网络时,支持在线缓存(连接网络时的有效期)
  • 断开网络,支持离线缓存(离线缓存有效期)
  • 多次请求同一url,在网络还在请求时,是否只请求一次
  • 支持网络请求失败,自动重连
  • 支持取消网络请求

Retrofit的接口如下:

public interface RetrofitApiService {//wanAndroid的banner@GET("banner/json")Observable<ResponModel<List<BannerBean>>> getBanner();
}

简单封装如下,封装一个单例的RetrofitManager:

public class RetrofitManager {private static RetrofitManager retrofitManager;private Retrofit retrofit;private RetrofitApiService retrofitApiService;private RetrofitManager() {initRetrofit();}public static RetrofitManager getInstance() {if (retrofitManager == null) {synchronized (RetrofitManager.class) {if (retrofitManager == null) {retrofitManager = new RetrofitManager();}}}return retrofitManager;}public static RetrofitApiService getApiService() {return retrofitManager.retrofitApiService;}private void initRetrofit() {retrofit = new Retrofit.Builder().baseUrl(SystemConst.DEFAULT_SERVER).addConverterFactory(GsonConverterFactory.create()).addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build();retrofitApiService = retrofit.create(RetrofitApiService.class);}
}

四、实现我们的功能

4.1 创建MainViewModel

首先是创建我们的MainViewModel,并添加,加载banner接口。(Repository数据层,也可以说是model层,放在后一篇)如下:

public class MainViewModel extends BaseViewModel {public MainViewModel(@NonNull Application application) {super(application);}@Overrideprotected void onCleared() {super.onCleared();}public MutableLiveData<List<BannerBean>> getBanners(){//因为用到LiveData,我觉得都不需要切换到主线程了。LiveData可以帮我们做//调用接口,返回我们的MutableLiveData>final MutableLiveData<List<BannerBean>> liveData = new MutableLiveData<>();RetrofitManager.getInstance().getApiService().getBanner().subscribeOn(Schedulers.io()).subscribe(new Consumer<ResponModel<List<BannerBean>>>() {@Overridepublic void accept(ResponModel<List<BannerBean>> listResponModel) throws Exception {liveData.postValue(listResponModel.getData());}}, new Consumer<Throwable>() {@Overridepublic void accept(Throwable throwable) throws Exception {}});return liveData;}
}

4.2 MainActivity里

  • 首先把xml改成我们的DataBinding布局
  • 添加一个按钮,点击去请求我们的接口
  • 增加第三方Banner去展示我们的数据

xml如下:

<layout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"><data>data><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><com.youth.banner.Bannerandroid:id="@+id/banner"android:layout_width="match_parent"android:layout_height="180dp"/><Buttonandroid:text="点击请求"android:id="@+id/btn"android:layout_width="wrap_content"android:layout_height="wrap_content"/>RelativeLayout>
layout>

MainActivity继承我们的BaseActivity,并指明我们的 ViewModel 和DataBinding。

    public class MainActivity extends BaseActivity<MainViewModel, ActivityMainBinding> {@Overrideprotected int getContentViewId() {return R.layout.activity_main;}@Overrideprotected void processLogic() {initBanner();binding.btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {getBanner();}});}private void getBanner() {mViewModel.getBanners().observe(this, new Observer<List<BannerBean>>() {@Overridepublic void onChanged(List<BannerBean> bannerBeans) {updateBanner(bannerBeans);}});}private void initBanner() {binding.banner.setBannerStyle(BannerConfig.CIRCLE_INDICATOR_TITLE_INSIDE);//这是给banner添加图片加载器binding.banner.setImageLoader(new GlideImageLoader());}private void updateBanner(List<BannerBean> data) {if (data == null || data.size() <= 0) {return;}List<String> urls = new ArrayList<>();List<String> titles = new ArrayList<>();for (int i = 0; i < data.size(); i++) {urls.add(data.get(i).getImagePath());titles.add(data.get(i).getTitle());}binding.banner.setBannerTitles(titles);binding.banner.setImages(urls);binding.banner.start();}
}

跟着项目走,你会跑通一个简单的MVVM项目。下一篇,将是最后终结篇。如果MVVM系列能帮到你的话,请帮楼主点个赞吧。谢谢

因为跟本文走,简单的MVVM会跑通。我这里就不贴demo链接了。下一篇,终结篇,将会放上终结篇demo链接。



本文还涉及到的类有
ResponModel

public class ResponModel<T> implements Serializable {public static final int RESULT_SUCCESS = 0;private T data;private int errorCode;private String errorMsg;public T getData() {return data;}public void setData(T data) {this.data = data;}public int getErrorCode() {return errorCode;}public void setErrorCode(int errorCode) {this.errorCode = errorCode;}public String getErrorMsg() {return errorMsg;}public void setErrorMsg(String errorMsg) {this.errorMsg = errorMsg;}public boolean isSuccess(){return RESULT_SUCCESS == errorCode;}
}

BannerBean:

public class BannerBean implements Serializable {/*** desc : Android高级进阶直播课免费学习* id : 23* imagePath : https://wanandroid.com/blogimgs/67c28e8c-2716-4b78-95d3-22cbde65d924.jpeg* isVisible : 1* order : 0* title : Android高级进阶直播课免费学习* type : 0* url : https://url.163.com/4bj*/private String desc;private int id;private String imagePath;private int isVisible;private int order;private String title;private int type;private String url;public String getDesc() {return desc;}public void setDesc(String desc) {this.desc = desc;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getImagePath() {return imagePath;}public void setImagePath(String imagePath) {this.imagePath = imagePath;}public int getIsVisible() {return isVisible;}public void setIsVisible(int isVisible) {this.isVisible = isVisible;}public int getOrder() {return order;}public void setOrder(int order) {this.order = order;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public int getType() {return type;}public void setType(int type) {this.type = type;}public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}
}

GlideImageLoader:

public class GlideImageLoader extends ImageLoader {@Overridepublic void displayImage(Context context, Object path, ImageView imageView) {Glide.with(context).load(path).placeholder(R.mipmap.ic_launcher).error(R.mipmap.ic_launcher).centerCrop().into(imageView);}
}

最后别忘记加上网络权限。加油~(是不是发现接口被LiveData取代了呢!)


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部