第一次写文章~,废话少说。先给大家拜个早年 2020 年新年快乐~
2018 年Google I/O 大会推出了 JetPack 框架。旨在帮助开发者更轻松地开发出色的 Android 应用。
作为一名Android开发还不赶紧尝试一波~
下面摘自Google:
- Jetpack 是 Android 软件组件的集合,使您可以更轻松地开发出色的 Android 应用。这些组件可帮助您遵循最佳做法、让您摆脱编写样板代码的工作并简化复杂任务,以便您可以专注于您关心的代码。
- Jetpack 包含与平台 API 解除捆绑的 androidx.* 软件包库。这意味着,它提供向后兼容性并且比 Android 平台更频繁地更新,从而确保您始终可以获取最新且最好的 Jetpack 组件版本。
目前开发中常用的设计模式 无非MVP、MVVM 关于各自的优缺点。相信每个开发都各有各的看法与观点,VM模式在我看来也是MVP的变种,能够更好地去和View解耦,可以极大地给View层减负。
以下摘自百度:
MVVM优点:
1. 低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
2. 可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。
3. 独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计,使用Expression Blend可以很容易设计界面并生成xaml代码。
4. 可测试。界面素来是比较难于测试的,而现在测试可以针对ViewModel来写
简介
只使用3个注解也可以轻松完成MVVM框架的搭建,让你的代码也可以看起来很骚~~~
本项目根据Google 新框架JepPack基本模式搭配dagger2 (地址) 完成 ViewModel 与 Respository (数据层) 的解耦。
使用 APT (Annotation Processing Tool) 注解处理工具,配合 Javapoet 构建完成。
项目整体架构参照Google的模式,基本保持一致。
项目地址: MvvmKotlin
? ? ? ? ? ? 喜欢记得 Star~ 点赞 ? ? ? ? ? ?
下面分为几个步骤大致说明一下实现过程~
直接引用原图(数据库部分没做处理 后续再说~~~)
- 整体框架结构
Respository (数据层)
Respository(数据处理层): 是用来处理网络数据、数据库、本地等数据的逻辑。(目前仅实现了网络部分)
数据层,依然是经典的搭配组合:retrofit + rxjava 使用dagger 来提供实例对象。
自定义的Repository只需继承BaseRepository,BaseRepository由APT自动生成,并且提供所有网络(Retrofit)接口实例。在BaseRepository中提供各个接口数据。
- 处理retrofit接口。在接口类中添加注解@ApiFactory即可
@ApiFactory
interface DemoService {
@GET("users/{user}")
fun getUser(@Path("user") user: String): Flowable<Any>
}
- APT会找到注解ApiFactory 并自动生产一些重复的代码,生成的代码会对接口进行简单处理。
代码注释中包含每个函数来自那个接口的方法,方便快速定位。手动 ?
public class DemoServiceFactory extends BaseHttpFactory<DemoService> {
@Inject
public DemoServiceFactory(RetrofitInterface retrofitInterface) {
super(retrofitInterface);
}
/**
* @apt生产的接口方法 {@link DemoService#getUser}
*/
public Flowable<Object> getUser(String user) {
return mObtainService.getUser(user).compose(RxThread.Companion.applyAsync());
}
}
- APT自动生成BaseRepository,并且通过dagger注入所有接口工厂
BaseRepository抽象类中拥有所有retrofit接口工厂的实例,方便调用网络接口。
public abstract class BaseRepository implements RepositoryInterface {
/**
* @apt生产 注入 @{@link com.m.mvvmkotlin.sample.DemoService} 的网络请求工厂
*/
@Inject
public DemoService2Factory mDemoServiceRepository;
/**
* @apt生产 注入 @{@link com.m.mvvmkotlin.smaple2.DemoService2} 的网络请求工厂
*/
@Inject
public DemoService2Factory mDemoService2Repository;
public CompositeDisposable mSubscription;
public BaseRepository() {
this.mSubscription = new CompositeDisposable();
DaggerBaseRepositoryComponent.builder().build().inject(this);
}
@Override
public void onCleared() {
mSubscription.clear();
}
}
至此,网络请求部分已经全部结束了。
可是我们好像还没做什么东西~~~ 还没开始,怎么就结束了~。???
是的。我们要做的仅仅是 在retrofit 接口 添加一个注解,剩下的都有APT帮我们做完了~
ViewModel (Model层)
ViewModel模块无须关心自身Factory的生产过程。只需在构造函数中传入自身所需要的Respository(数据层)使用即可,
在ViewModle的构造中可同时传入多个数据源,Factory将自动获取数据实例传入ViewModel中。
~~~~废话少说, 直接上代码~
- ViewModel构造中传入需要的数据源获取数据
ViewModel的基本使用方式、在构造函数中,我们传入自己所需要的Repository(数据层) ,此处可以是多个或者不传。
有些使用过Jetpack框架的小伙伴可能会说了。ViewModel是需要相对应的ViewModelFactory的,以便对Model和View进行绑定。 带着问题我们往下看step2~~~
class DemoViewModel(private var demoRepository: DemoRepository) : ViewModel(),
DemoTaskInterface.RespositoryTask {
val data = ObservableField<String>()
override fun result(result: String) { data.set(result) }
fun get(user: String) { demoRepository.getUser(user, this) }
override fun onCleared() {
super.onCleared()
demoRepository.onCleared()
}
}
- APT将自动生成ViewModel对应的ViewModelFactory
终于ViewModelFactory来了,是不是很亲切~~~
Factory 会将Model需要的参数在 create 过程中将Model需要的数据源传入
ViewModelFactory 的生产过程是利用了 @InjectViewModel @BindViewModel 这两个注解(至此三个注解都已出现)
新出现的两个注解的使用 我们去看View层。我们的ViewModel最终都是要在View层出现的。
/**
* @ViewModelFactory工厂 此类由apt自动生成 {@link DemoViewModel} 的工厂类
*/
public class DemoViewModelFactory extends ViewModelProvider.NewInstanceFactory {
private DemoRepository demoRepository;
@Inject
public DemoViewModelFactory(DemoRepository demoRepository) {
this.demoRepository = demoRepository;
}
/**
* @ {@link ViewModelProvider.NewInstanceFactory} 中的方法
*/
@Override
public <T extends ViewModel> T create(Class<T> modelClass) {
return (T) new DemoViewModel(demoRepository);
}
}
Activity/Fragment (View层)
利用注解 @InjectViewModel @BindViewModel 配合APT自动完成ViewModel 与Respository 的注入过程,
利用控制反转轻松实现Activity/Fragment与ViewModel的关联,类似ButterKnife。
同时View可支持多个ViewModel的注入
- APT自动生成ViewModelFactoryTools类
由于这个类较长 仅截取部分展示。查看完整过程。clone 项目 然后 build 即可
代码中可以看到,我们将View(Activity/Fragment) 通过bind方法传入。然后将ViewModelFactory 与View进行绑定,并且为ViewModel进行了赋值。我们可以在一个View中使用多个ViewModel。
public class ViewModelFactoryTools {
private static ViewModelFactoryTools mViewModelTools;
/**
* @ 注入 {@link DemoViewModel} 对应的: {@link DemoViewModelFactory }
*/
@Inject
DemoViewModelFactory mDemoViewModelFactory;
....
....
....
public void bind(AppCompatActivity baseActivity) {
if(baseActivity instanceof MainActivity) {
MainActivity mMainActivity = (MainActivity)baseActivity;
mMainActivity.demoViewModel = ViewModelProviders.of(mMainActivity, mDemoViewModelFactory).get(DemoViewModel.class);
}
if(baseActivity instanceof MainActivity) {
MainActivity mMainActivity = (MainActivity)baseActivity;
mMainActivity.demoViewModel2 = ViewModelProviders.of(mMainActivity, mDemoViewModel2Factory).get(DemoViewModel2.class);
}
}
-
View基类中获取ViewModelFactoryTools的实例
在我们的基类中获取ViewModelFactoryTools的实例,通过bind方法实现View与ViewModel绑定,并且给View中带有 @BindViewModel注解的 ViewModel赋值。
ViewModelFactoryTools.getInstance().bind(this)
-
View中使用注解 @InjectViewModel @BindViewModel
@InjectViewModel
class MainActivity : BaseActivity(), View.OnClickListener {
@BindViewModel
lateinit var demoViewModel: DemoViewModel
//绑定多个model
@BindViewModel
lateinit var demoViewModel2: DemoViewModel2
...
...
... 省略
}
至此。整体大致讲完了。好像也没说什么~~~ (第一次写~~~难免紧张 ☺️ ☺️ ☺️ ☺️)
关于 APT 的生产部分。项目 MvvmKotlin 中有源码 ,可以自行查看。 喜欢记得 star ~~ ? 。
后续 ~~
Gif
Thanks
-
Google官方Jetpack框架 android-sunflower
-
感谢 T-MVP 学习参考