Android-MVVM开发模式应用
优快云:https://blog.youkuaiyun.com/chenzhen200638/article/details/82185190
MVVM开发模式,是多种先进的开发思想集成在一起形成的一种高效率开发解决方案。
其中涉及到哪些开发思想呢?
- MVC : 是一种把数据和视图分离解耦的思想,视图的展示由控制器进行分发跳转;
- DI : 依赖注入是指将组件的依赖通过外部以参数或其他形式注入。比如Dagger,就是依赖注入框架;
- IOC : 控制反转,控制反转是将组件间的依赖关系从程序内部提到外部来管理;
开始搭建mvvm开发框架,前提需要了解Dagger的使用。
一、引入第三方库
在Android的工程目录Gradle中加入以下库
project.ext {
retrofitVersion = "2.3.0"
okhttpVersion = "3.9.0"
supportVersion = "27.0.2"
web3jVersion = "3.0.1-android"
gethVersion = "1.7.0"
gsonVersion = "2.8.2"
rxJavaVersion = "2.1.6"
rxAndroidVersion = "2.0.1"
daggerVersion = "2.11"
}
dependencies {
// Http client --网络库
implementation "com.squareup.retrofit2:retrofit:$project.retrofitVersion"
implementation "com.squareup.retrofit2:converter-gson:$project.retrofitVersion"
implementation "com.squareup.retrofit2:adapter-rxjava2:$project.retrofitVersion"
implementation "com.squareup.okhttp3:okhttp:$project.okhttpVersion"
implementation "com.google.code.gson:gson:$project.gsonVersion"
// RxJava 内存优化
implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'
implementation 'com.jakewharton.rxbinding2:rxbinding-support-v4:2.1.1'
implementation 'com.jakewharton.rxbinding2:rxbinding-appcompat-v7:2.1.1'
implementation 'com.jakewharton.rxbinding2:rxbinding-design:2.1.1'
implementation 'com.jakewharton.rxbinding2:rxbinding-recyclerview-v7:2.1.1'
implementation 'com.jakewharton.rxbinding2:rxbinding-leanback-v17:2.1.1'
// RxJava2.x
implementation "io.reactivex.rxjava2:rxjava:$project.rxJavaVersion"
implementation "io.reactivex.rxjava2:rxandroid:$project.rxAndroidVersion"
// Lifecycle 生命周期
implementation "android.arch.lifecycle:runtime:1.0.3"
implementation "android.arch.lifecycle:extensions:1.0.0"
// Dagger 2 DI依赖注入库
// Dagger core
implementation "com.google.dagger:dagger:$project.daggerVersion"
annotationProcessor "com.google.dagger:dagger-compiler:$project.daggerVersion"
// Dagger Android
implementation "com.google.dagger:dagger-android-support:$project.daggerVersion"
annotationProcessor "com.google.dagger:dagger-android-processor:$project.daggerVersion"
// if you are not using support library, include this instead
implementation "com.google.dagger:dagger-android:$project.daggerVersion"
}
现在我们来编写具体的业务代码,包的划分为 di,entity,service,viewmodle,ui几个目录
- di: 依赖注入相关的代码
- entity: 实体类
- service: 网络请求,数据库相关代码
- viewmodle: 业务逻辑代码
- ui : activity界面视图相关代码
二、编写Service数据源API
//数据库操作代码,结合了RxJava2.x返回的都是Observeble对象;
public class RealmService {
public Single<List<Student>> findAllStudent() {
return Single.fromCallable(() -> {
final List<Student> students = new ArrayList<>();
Realm realm = Realm.getDefaultInstance();
try {
realm.executeTransaction(r -> {
RealmResults<Student> rs = realm.where(Student.class).findAll();
students.addAll(realm.copyFromRealm(rs));
});
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (realm != null) {
realm.close();
}
}
return students;
});
}
public Completable addStudent(Student student) {
return Completable.fromAction(() -> {
Realm realm = Realm.getDefaultInstance();
try {
realm.executeTransaction(r -> {
Student s = realm.createObject(Student.class,
UUID.randomUUID().toString());
s.setName(student.getName());
s.setAddress(student.getAddress());
s.setAge(student.getAge());
realm.copyFromRealm(s);
});
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (realm != null) {
realm.close();
}
}
});
}
定义实体类学生
public class Student extends RealmObject {
@PrimaryKey
private String id;
private String name;
private String address;
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setAddress(String address) {
this.address = address;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public String getAddress() {
return address;
}
}
三、编写ViewModle业务逻辑
3.1 工厂类
public class RealmServiceModelFactory implements ViewModelProvider.Factory {
private final RealmService mRealmService;
@Inject
public RealmServiceModelFactory(RealmService mRealmService) {
this.mRealmService = mRealmService;
}
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
return (T)new RealmServiceModel(mRealmService);
}
}
3.2 业务逻辑的基类
基类主要封装好通用的异常,进度条显隐控制逻辑;
public class BaseViewModel extends ViewModel {
protected final MutableLiveData<String> error = new MutableLiveData<>();
protected final MutableLiveData<Boolean> progress = new MutableLiveData<>();
protected Disposable disposable;
@Override
protected void onCleared() {
if (disposable != null && !disposable.isDisposed()) {
disposable.dispose();
}
}
public LiveData<String> error() {
return error;
}
public LiveData<Boolean> progress() {
return progress;
}
protected void onError(Throwable throwable) {
error.postValue(throwable.getMessage());
}
}
3.3 业务逻辑Modle
package realm.com.xn.realmdatabase.viewmodel;
import android.arch.lifecycle.MutableLiveData;
import java.util.List;
import java.util.concurrent.TimeUnit;
import realm.com.xn.realmdatabase.entity.Student;
import realm.com.xn.realmdatabase.service.RealmService;
/**
* Created by xn068074 on 2018/8/24.
*/
public class RealmServiceModel extends BaseViewModel {
private final RealmService mRealmService;
private final MutableLiveData<List<Student>> studentsLiveData = new MutableLiveData<>();
public RealmServiceModel(RealmService mRealmService) {
this.mRealmService = mRealmService;
}
public MutableLiveData<List<Student>> students(){
return this.studentsLiveData;
}
public void fetchAllStudent(){
progress.postValue(true);
mRealmService.findAllStudent()
.delay(2, TimeUnit.SECONDS)
.subscribe(students -> {
progress.postValue(false);
studentsLiveData.postValue(students);
});
}
public void addStudent(){
this.progress.postValue(true);
Student a = new Student();
a.setAge(16);
a.setAddress("中国上海");
a.setName("陈永和");
this.mRealmService.addStudent(a)
.delay(1,TimeUnit.SECONDS)
.subscribe(()->this.progress.postValue(false));
}
public void removeStudents(){
this.progress.postValue(true);
this.mRealmService.deleteAllStudent()
.delay(1,TimeUnit.SECONDS)
.subscribe(()->this.progress.postValue(false));
}
}
3.4 类务工厂类
这个类主要是用来生成modle的实例
public class RealmServiceModelFactory implements ViewModelProvider.Factory {
private final RealmService mRealmService;
@Inject
public RealmServiceModelFactory(RealmService mRealmService) {
this.mRealmService = mRealmService;
}
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
return (T)new RealmServiceModel(mRealmService);
}
}
四、UI界面
在Activity中通过依赖注入调用业务逻辑类
public class MVVMActivity extends AppCompatActivity implements OnClickListener {
private TextView mask;
private LinearLayout container;
RealmServiceModel mRealmServiceModel;
@Inject
RealmServiceModelFactory mRealmServiceModelFactory;
@Override
protected void onCreate(Bundle savedInstanceState) {
//这里是重点,需要注入
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_vvm);
mRealmServiceModel = ViewModelProviders.of(this,mRealmServiceModelFactory).get(RealmServiceModel.class);
this.mask = this.findViewById(R.id.mask);
this.container = this.findViewById(R.id.container);
this.findViewById(R.id.query).setOnClickListener(this);
this.findViewById(R.id.add).setOnClickListener(this);
this.findViewById(R.id.clear).setOnClickListener(this);
//进度条显示和隐藏
mRealmServiceModel.progress().observe(this,this::progress);
//异常信息提示
mRealmServiceModel.error().observe(this,this::error);
//学生数据更新
mRealmServiceModel.students().observe(this,this::onStudentsChanged);
}
public void progress(boolean show){
this.mask.setVisibility(show ? View.VISIBLE : View.GONE);
}
public void error(String error){
Toast.makeText(this,error,Toast.LENGTH_LONG).show();
}
/**
* 查询所有学生数据,并更新界面
*/
public void onStudentsChanged(List<Student> students) {
container.removeAllViews();
for (Student s : students) {
container.addView(buildTextView(s.toString()));
}
}
public TextView buildTextView(String text) {
TextView txt = new TextView(this);
txt.setText(text);
txt.setTextColor(Color.BLACK);
txt.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
txt.setLayoutParams(lp);
return txt;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.add:
this.mRealmServiceModel.addStudent();
break;
case R.id.query:
this.mRealmServiceModel.fetchAllStudent();
break;
case R.id.clear:
this.mRealmServiceModel.removeStudents();
break;
}
}
}
五、依赖注入DI
5.1 Module依赖注入
@Module
public class RealmServiceModule {
@Provides
public RealmServiceModelFactory provideRealmServiceModelFactory(RealmService realmService){
return new RealmServiceModelFactory(realmService);
}
@Provides
RealmService provideRealmService() {
return new RealmService();
}
}
5.2 BuildersModule
这个主要是建立Activity和module的联系,是一个枢纽中心
先定义一个通用的注解
@Scope
@Retention(RUNTIME)
public @interface ActivityScope {
}
然后编写BuildersModule,建立Activity和Module的联系
@Module
public abstract class BuildersModule {
@ActivityScope
@ContributesAndroidInjector(modules = RealmServiceModule.class)
abstract MVVMActivity bindMVVMActivityModule();
}
5.3 AppComponent
这种写法是Dagger2的最新的用法,具体详情需要去了解Dagger2的使用了.
@Singleton
@Component(modules = {
BuildersModule.class,
AndroidSupportInjectionModule.class,
RealmServiceModule.class })
public interface AppComponent {
@Component.Builder
interface Builder {
@BindsInstance
Builder application(RealmApp app);
AppComponent build();
}
void inject(RealmApp app);
}
5.4 Application
最后一步要建立Activity生命周期和各个Module的关系,这样可以自动在onDestroy中销毁对象
public class RealmApp extends Application implements HasActivityInjector {
@Inject
DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;
@Override
public void onCreate() {
super.onCreate();
//数据库相关的初始化
Realm.init(this);
RealmConfiguration configuration = new RealmConfiguration.Builder()
.name("realm.realm")
.schemaVersion(1)
.build();
Realm.setDefaultConfiguration(configuration);
//自动生成的DaggerAppComponent类,调用方法初始化
DaggerAppComponent
.builder()
.application(this)
.build()
.inject(this);
}
@Override
public AndroidInjector<Activity> activityInjector() {
return dispatchingAndroidInjector;
}
}