前言
用了几百年的mvp和mvc了,这和我的业务环境脱不了关系,维护老旧项目的时间很多,导致一直没什么机会来写一个mvvm标准架构的应用,
我开个帖子记录一下使用安卓组件化和mvvm模式来从头做一个项目
开始
1.将会使用jectpact来作为核心的库,这是一个安卓官方出品的帮助mvvm搭建的库。
将会使用开眼的openapi来进行编写,项目中所有api接口都是抓取自开眼app,目前最新版的开眼api是加了验证的,但是所有版权均归属开眼app所有,仅供学习借鉴使用,请勿用做商业用途,若有侵权,请联系作者删除。
2.使用阿里巴巴开源的Arouter来作为在组件之间进行交互的框架。
3.注意可能含有低质量代码
目录结构
依赖关系
这些模组尽量做到互相不影响,app入口的模组在open_main里,里面包含整个app的ui页面框架,而名称为app的模组只是存放自定义的application域做一些初始化操作和到欢迎界面的操作而已。
MVVM工具编写
上面搭建好项目后,进行一个简单mvvm的工具编写。
mvvm是界面与数据模型进行的一个双向绑定,这里面我们的着重点就是绑定后在数据更新结束时能进行对视图的变化,
这里我们使用安卓jectpack里的viewmodel来进行视图双向绑定,viewmodel它的好处是可以完美契合数据模型与ui视图的生命周期
有效减少了内存泄漏的问题,我这里简单的利用retrofit+viewmodel来写一个典型的mvvm通信。
代码示例
1.view层
SplashActivity(开屏页面,加载广告)
@Route(path=UiPaths.Splash.path)
class SplashActivity : AppCompatActivity() {
var configBean:ConfigBean?=null
lateinit var videoView: SplashVideoView
var mVideoWidth:Int = 0
var mVideoHeight:Int = 0
lateinit var viewModel:ViewModelCenter
override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_splash)videoView = findViewById(R.id.video_view)//隐藏状态栏hiddeBar()//加载开屏视频广告laodingopeningVideo()}private fun laodingopeningVideo() {//这里viewmodel与视图绑定viewModel = ViewModelCenter()//初始化viewmodelviewModel.init(ConfigBean::class.java)//在这里对数据进行与视图的互动viewModel.data.observe(this,{if (it is String){ToastUtils.showShort(it)}else{videoView.setActivity(this)videoView.setAdConfig(it as ConfigBean)}})}override fun onBackPressed() {if (Jzvd.backPress()) {return}super.onBackPressed()
}override fun onPause() {super.onPause()Jzvd.releaseAllVideos()
}
}
2.viewmodel层
ViewModelCenter
按照正常的写法应该是一个model对应一个具体的viewmodel而不是我这种写法,因为项目体量不大所以这边就暂时不采用正规的写法。
viewmodel层包含数据处理和数据存放的空间,我们可以执行网络请求来获取数据
/**
不用单例@param*/
public class ViewModelCenter extends ViewModel
{private NetWorkCenter center;public static final String LOADING_STATUE="LOADING_STATUE";public static final String FAILED_STATUE="FAILED_STATUE";public static final String SUCCESS_STATUE="SUCCESS_STATUE";public static final String OTHER_STATUE="OTHER_STATUE";public MutableLiveData<String> loading_statue=new MutableLiveData<>();public MutableLiveData data = new MutableLiveData<>();public ViewModelCenter(){center = new NetWorkCenter(this);loading_statue.setValue(LOADING_STATUE);}/*** 初始化方法* 按照传统的请求网络查询* 可以传入参数在其中*/public void init(Class clazz){center.startRequest(clazz);}/*** 初始化方法* 按照传统的请求网络查询* 可以传入参数在其中*/public void init(Class clazz,int page,int pagesize){center.startRequest(clazz,page,pagesize);}}
3.viewmodel层里的网络服务处理层
通过在viewmodel里init方法获取的model名称来请求对应的接口,最后在回调里进行数据的处理
利用了Gson来处理请求获取到的响应,数据处理代码就不贴了。
class NetWorkCenter(modelCenter: ViewModelCenter)
{var modelCenter_: ViewModelCenter = modelCenter
fun<T> startRequest(initModel:Class<T>) {when(initModel.name){CommnutiyPageBean::class.java.name->{ApiService.startRequest().getHomePage().enqueue(NetResult(modelCenter_))}DayDataPageBean::class.java.name->{ApiService.startRequest().getDayData().enqueue(NetResult(modelCenter_))}CategoryList::class.java.name->{ApiService.startRequest().getCategories().enqueue(NetResult(modelCenter_))}DisCoverPageBean::class.java.name->{ApiService.startRequest().getDiscover().enqueue(NetResult(modelCenter_))}ConfigBean::class.java.name->{ApiService.startRequest().getAdConfigs().enqueue(NetResult(modelCenter_))}}
}fun<T> startRequest(initModel: Class<T>,page:Int,pageSize:Int) {}
}
4.model层
很普通的一个javabean对象,利用gson解析可以生成对应对象
public class CommnutiyPageBean
{@SerializedName("itemList")private List<ItemListDTOX> itemList;@SerializedName("count")private int count;@SerializedName("total")private int total;@SerializedName("nextPageUrl")private String nextPageUrl;@SerializedName("adExist")private boolean adExist;public List<ItemListDTOX> getItemList() {return itemList;}public void setItemList(List<ItemListDTOX> itemList) {this.itemList = itemList;}public int getCount() {return count;}public void setCount(int count) {this.count = count;}public int getTotal() {return total;}public void setTotal(int total) {this.total = total;}public String getNextPageUrl() {return nextPageUrl;}public void setNextPageUrl(String nextPageUrl) {this.nextPageUrl = nextPageUrl;}public boolean isAdExist() {return adExist;}public void setAdExist(boolean adExist) {this.adExist = adExist;}}