-
MVVM开发模式
2021-01-09 16:50:08MVVM开发模式的主要目的和其他两种模式相同,都是为了分离模型和视图,主要有以下的优势: (1)低耦合 在MVVM模式中,当Model发生变化的时候View可以不变化,而当View发生变化的时候Model也可以不变,也就是View...MVVM开发模式的主要目的和其他两种模式相同,都是为了分离模型和视图,主要有以下的优势:
(1)低耦合
在MVVM模式中,当Model发生变化的时候View可以不变化,而当View发生变化的时候Model也可以不变,也就是View可以独立于Model修改和变化,同时同一个ViewModel可以绑定到多个不同的View上。
(2)独立开发
MVVM开发模式可以使设计人员和开发人员各司其职,设计人员可以集中精力进行页面元素的设计,开发工程师可以全身心投入业务逻辑的开发。
(3)可重用
MVVM开发模式中可以把一些视图逻辑放在ViewModel里面,让多个View来重用这些视图逻辑,从而提高页面性能和效率。
(4)可测试
在以前的MVC及MVP等传统开发模式中,界面测试是非常困难的工作,而在MVVM模式中测试可以专门针对ViewModel来写。 -
iOS OC - MVVM开发模式
2020-06-19 15:32:21一个使用MVVM开发模式的小demo,里面注释写的已经很详细了,有哪里看不懂的小伙伴可以在评论区留言。 -
WPF的MVVM开发模式简单示例
2019-03-23 12:26:33WPF的MVVM开发模式简单示例,详情见 https://blog.csdn.net/wf824284257/article/details/88758707 -
一个浅封装、快速开发的 Android MVVM 开发框架
2020-04-17 11:38:37简介: 一个浅封装、快速开发的 Android MVVM 开发框架 更多:作者提 Bug 标签: 上手特别容易,不会 MVVM 开发模式的都可以快速上手。 一个浅封装、快速开发的 Android MVVM 开发框架。 基于 Android ...FastAAC
项目地址:ldlywt/FastAAC
简介: 一个浅封装、快速开发的 Android MVVM 开发框架
标签:
- 上手特别容易,不会 MVVM 开发模式的都可以快速上手。
- 一个浅封装、快速开发的 Android MVVM 开发框架。
- 基于 Android Architecture Components(AAC)。
- 项目使用 Androidx 搭建。
- 只使用官方部分的 MVVM 和 databind 的部分特性。
Lib 结构
优点
-
简单、浅封装、扩展性强
代码简单,没有过度的封装,上手非常容易,Lib 只有十几个类。
除了 Android 原生的依赖以外, 只集成了一个工具库
utilcodex
,事件总线live-event-bus
,页面状态管理loadsir
, 状态栏沉浸式工具immersionbar
,并且都是可以插拔的,不需要替换即可。图片加载库,网络请求库等其他第三方 Lib 可根据个人兴趣自己选择集成即可。
-
快速开发
通过泛型可以减少很多不必要的重复代码,以前每个 Activity 都需要写如下重复代码,例如:
ActivityMainBinding dataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main); MainVm mainVm = ViewModelProviders.of(this).get(MainVm.class);
现在只需要在类名上面写上泛型即可,自动解析:
public class MainActivity extends AbsMvvmActivity<MainVm, ActivityMainBinding> {}
-
自动页面状态管理
日常开发 Activity 的页面状态有:有网、无网络、空页面、loading 加载页面等各种页面。
使用 LiveData 的监听集成在 BaseActivity 中,根据 BaseResult 返回的 code 来自动管理页面显示状态。
switch (httpResult.getErrorCode()) { case BaseResult.SUCCESS_CODE: if (httpResult.getData() != null) { resultCode = SuccessCallback.class; } else { resultCode = EmptyCallback.class; } break; default: resultCode = ErrorCallback.class; }
如果想手动改变页面状态,只需在 ViewModel 中非常简单的设置,例如:
无网络时:
postPageState(new BaseResult(-1));
数据为空时:
public void clickNoData() { BaseResult<Object> baseResult = new BaseResult<>(); baseResult.setErrorCode(0); baseResult.setData(null); postPageState(baseResult); }
具体使用
见 demo 中的 MainActivity。
END
大家有什么更好的建议请提出,一起学习进步。
既然来了,麻烦动动手指,点个 star,非常感谢。
License
Copyright 2019 Wutao
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
-
Android-JetPack+MVVM开发示例Demo
2020-08-02 11:51:48Demo采用Retrofit+RxJava+Okhttp网络请求,演示了JetPack中Navigation、LifeCycle+ViewModel+LiveData+Room+DataBinding+MVVM开发使用示例。 -
swift-Objective-c的MVVM开发框架
2019-08-15 00:39:30LPDMvvmKit 提供了一些常用的工具类,还有一些很轻巧的控件,以及最主要的是提供了MVVM开发框架,一直比较喜欢采用MVVM的框架来开发前端产品,所以会希望在iOS下也能找到类似的框架可以采用,但是一直没有找到合适的 -
MVVM开发模式DEMO
2020-02-26 16:40:01用style框架 实现MVVM模式开发,逻辑清晰、便于理解,对于学习MVP模式有很大帮助!开发基于 vs2015 IDE -
Android-MVVM开发模式应用
2018-08-29 16:21:31Android-MVVM开发模式应用 MVVM开发模式,是多种先进的开发思想集成在一起形成的一种高效率开发解决方案。 其中涉及到哪些开发思想呢? - MVC : 是一种把数据和视图分离解耦的思想,视图的展示由控制器进行分发...Android-MVVM开发模式应用
CSDN:https://blog.csdn.net/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; } }
-
Android MVVM 开发新姿势 一
2019-06-24 17:04:32Android MVVM 开发新姿势 一 1. 前言 网上有不少关于Android架构的讨论,如MVC, MVP,MVVM,最近还有MVI,emmm…不得不感慨时代变化太快。MVVM出来也有一段很长的时间了,接触时间不长,写一篇文章记录一下。同时也...Android MVVM 开发新姿势 一
1. 前言
网上有不少关于Android架构的讨论,如MVC, MVP,MVVM,最近还有MVI,emmm…不得不感慨时代变化太快。MVVM出来也有一段很长的时间了,接触时间不长,写一篇文章记录一下。同时也作为一个思路,抛砖引玉。
2. MVVM概略
首先,要了解一个架构思想那么首先要看一下相关文章,其中又以谷歌为佳,下面就是MVVM(Model-View-ViewModel)结构的架构图。
相关链接:https://developer.android.google.cn/jetpack
简单介绍一下各个模块:View层 绿色框中的Activity/Fragment,继承至LifecycleActivity\LifecycleFragment,是UI控件的宿主。
核心职责是:
更新UI控件显示,包括状态及数据,由ViewModel驱动
监听UI事件及其生命周期,驱动ViewModel
View层不直接处理任何业务逻辑及数据加工。尽量做到瘦身,代码逻辑简约,减轻UI线程负担。ViewModel层 蓝色框的ViewModel。只做业务逻辑操作,不持有任何UI控件的引用。那数据的更新如何通知到View层,这就要仰仗LiveData,具体使用后面会提及。
Model层 橘黄色框的Repository及其下都是Model层。Model层就是数据层。数据来源有:
本地存储数据,如数据库,文件,SharedPreferences(本质也是文件)
内存的缓存或临时数据
通过各种网络协议获取的远程数据Repository是数据仓库,整合各路来源的数据,再统一暴露给ViewModel层使用。官方新框架在这一层只提供给了一个新的SQLite数据库封装类库Room,这是可选的。换言之,Model层,官方只提供指导思想,并未有具体实现方案。也就是可以自由发挥,各种嗨,Emm
各个层次的依赖如图:
3. 框架搭建
首先解决一下依赖最底层model的问题。
一般而言,model一般用于从数据源获取数据。当然也可以从本地获取数据
数据源一般就是后台服务器。
我们抽象一下,抽出来就是一个抽象类。public abstract class BaseModel { public void getData(int code, BaseSubscriber subscriber , Object... parameter){ //TODO 调用网络请求前的操作 requestInNet(code, subscriber ,parameter); } /** * 网络请求 * @param code 请求对应的code用于区分不同的请求 * @param subscriber 回调 * @param parameter 可变参数列表 存放请求所需参数 */ protected abstract void requestInNet(int code,BaseSubscriber subscriber ,Object... parameter); }
接下来需要思考一个问题,下层不存在上层依赖,那么viewmodel和model之间该怎么通讯呢?思索一番,决定用rxjava的回调。Emmm,那么肯定要根据需求改造一番。代码如下:
public abstract class BaseSubscriber<T> extends ResourceSubscriber<T> { protected BaseViewModel vm; public BaseSubscriber(BaseViewModel vm) { this(vm, null); } public BaseSubscriber(BaseViewModel vm, @Nullable String requestKey) { this.vm = vm; this.vm.subscribe(this, requestKey); } @Override public void onStart() { super.onStart(); //TODO 此处可以判断网络,无网络调用onStartOffline onStartRequest(); } @Override public void onNext(T t) { onSuccess(t); } /** * 请求失败 * 可重写复用 */ @Override public void onError(Throwable t) { vm.onError(t); } /** * 完成时回调 */ @Override public abstract void onComplete(); /** * 当开始请求时没有网络 * 可重写复用 */ public void onStartOffline(){ } /** * 当开始请求时时 * 可重写复用 */ public void onStartRequest(){ } /** * 当成功返回时 * @param t 返回的数据 */ public abstract void onSuccess(T t); }
回调改造完成,那么我们就写一个viewmodel。
public abstract class BaseViewModel<M extends BaseModel> extends AndroidViewModel { /* RX相关注册 */ /** * 一次性容器,可以容纳多个其他一次性用品和提供I/O添加和移除复杂性。 */ private CompositeDisposable mCompositeDisposable; private ArrayMap<String, Disposable> mDisposableMap; protected M model; protected final MutableLiveData<Intent> startIntent = new MutableLiveData<>(); protected final MutableLiveData<ArrayList<Object>> messageToContext = new MutableLiveData<>(); public BaseViewModel(Application application){ super(application); model = setModel(); } /** * 设置model * @return model */ protected abstract M setModel(); protected void getData(int code , BaseSubscriber subscriber , Object... param){ if (model == null){ throw new NullPointerException("进行获取数据的操作前,检查Model是否赋值"); } model.getData(code,subscriber,param); } protected void sendMessageToContext(ArrayList<Object> params){ messageToContext.setValue(params); } /** * 注册RX可处理的线程 * @param disposable 可处理的线程 * @param requestKey 请求键 */ public void subscribe(Disposable disposable, @Nullable String requestKey) { if (null == mCompositeDisposable) { mCompositeDisposable = new CompositeDisposable(); } mCompositeDisposable.add(disposable); if (null == mDisposableMap){ mDisposableMap = new ArrayMap<>(); } if (!TextUtils.isEmpty(requestKey)){ mDisposableMap.put(requestKey, disposable); } } /** * 注销所有线程 */ public void unsubscribe() { if (null != mCompositeDisposable) { mCompositeDisposable.clear(); } } /** * 移除线程 * @param requestKey 请求键 */ public void removeDisposable(@NotNull String requestKey) { if (null != mCompositeDisposable && null != mDisposableMap && mDisposableMap.containsKey(requestKey)) { mCompositeDisposable.remove(mDisposableMap.get(requestKey)); mDisposableMap.remove(requestKey); } } /** * 请求时客户端错误处理 */ @CallSuper public void onError(Throwable throwable) { throwable.printStackTrace(); // 当在主线程时显示异常Toast if (Looper.getMainLooper() == Looper.myLooper()) { //TODO 后面添加 } } }
最后搞定activity
public abstract class BaseMvvmActivity <VM extends BaseViewModel,VDB extends ViewDataBinding> extends AppCompatActivity { protected VDB binding; protected VM viewModel; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); viewModel = setViewModel(); doBeforeBinding(); onBinding(); initUI(); setDefaultObservers(); } protected void setDefaultObservers() { } /** * 设置布局文件id * @return layout id */ protected abstract int getLayoutId(); protected void doBeforeBinding(){} protected void onBinding(){ binding = DataBindingUtil.setContentView(this, getLayoutId()); binding.setLifecycleOwner(this); binding.setVariable(BR.viewModel,viewModel); } /** * 设置ViewModel * @return viewModel */ protected abstract VM setViewModel(); /** * 初始化ui的方法 */ protected abstract void initUI(); public void changeIntoLightStatusBar(boolean isLight){ if (isLight){ getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); }else{ getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE); } } }
4. 实现简单功能
网络加载一张图片&获取一段数据显示
首先图片加载库glide,
配置glide balabala…此处省略1000字
然后新建一个类,ViewUtils 名字随意呀public class ViewUtils { @BindingAdapter({"imageUrl"}) public static void loadImageOnTheInternet(final ImageView imageView, final String url) { if (null != url && url.startsWith("http")) { imageView.post(() -> Glide.with(imageView.getContext()).load(url).into(imageView)); } } }
图片加载搞定了,下面是网络数据加载
同样省略1000字public class NetworkClient { private static Retrofit retrofit; private static final int TIME_OUT = 60*5; /** * 私有化构造方法 */ private NetworkClient(){ HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(message -> LogUtil.i("HttpLog",message)); loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); OkHttpClient okHttpClient = new OkHttpClient() .newBuilder() .connectTimeout(TIME_OUT, TimeUnit.SECONDS) .readTimeout(TIME_OUT, TimeUnit.SECONDS) .addInterceptor(loggingInterceptor) .build(); retrofit = new Retrofit.Builder() .baseUrl(Constant.BASE_URL) .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); } private static class SingletonHolder{ private static final NetworkClient INSTANCE = new NetworkClient(); } public static NetworkClient getNetworkClient (){ return SingletonHolder.INSTANCE; } /** * 获取api * @param service * @param <T> * @return */ public <T> T createApi(Class<T> service){ return retrofit.create(service); } } public interface UserApi { /** * 测试,获取公众号列表 * @return */ @GET("wxarticle/chapters/json") Flowable<ResponseBean<ArrayList<PublicNumBean>>> wxarticle(); }
关键代码如上。
下面前期准备工作都搞定了,我们开始写布局<?xml version="1.0" encoding="utf-8"?> <layout xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <import type="android.view.View"/> <import type="java.lang.String"/> <variable name="viewModel" type="com.tao.androidx_mvvm.viewmodel.ViewModelOfMain"/> </data> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".activity.MainActivity"> <Button android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{viewModel.text}" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" android:onClick="@{(view)->viewModel.onClick(view)}"/> <ImageView app:layout_constraintTop_toBottomOf="@id/text" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:imageUrl="@{viewModel.text}" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </androidx.constraintlayout.widget.ConstraintLayout> </layout>
一个button一个imageView搞定
ViewModelpublic class ViewModelOfMain extends BaseViewModel<ModelOfMain> { public final MutableLiveData<String> text = new MutableLiveData<>(); public ViewModelOfMain(Application application) { super(application); text.setValue("Hello"); } public void getData(){ getData(TEXT, new BaseSubscriber(this) { @Override public void onComplete() { } @Override public void onSuccess(Object o) { LogUtil.i("ViewModelOfMain",o.toString()); text.setValue(o.toString()); } @Override public void onError(Throwable t) { super.onError(t); LogUtil.i("ViewModelOfMain",t.getMessage()); } }); } @Override protected ModelOfMain setModel() { return new ModelOfMain(); } public void onClick(View v){ if (v.getId() == R.id.text){ getData(); } } }
Model:
public class ModelOfMain extends BaseModel { public static final int TEXT = 1001; @Override protected void requestInNet(int code, BaseSubscriber subscriber, Object... parameter) { switch (code) { case TEXT: LogUtil.i("ModelOfMain", "requestInNet"); NetworkClient.getNetworkClient().createApi(UserApi.class) .wxarticle() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(subscriber); break; default: LogUtil.i("ModelOfMain", "default"); break; } } }
Ativity:
class MainActivity : BaseMvvmActivity<ViewModelOfMain,ActivityMainBinding>() { override fun setViewModel(): ViewModelOfMain { return ViewModelOfMain(application) } override fun initUI() { viewModel.text.value = "http://img5.imgtn.bdimg.com/it/u=3300305952,1328708913&fm=26&gp=0.jpg" } override fun getLayoutId(): Int { return R.layout.activity_main } }
简单效果就如上面一样。
关于recyclerview,fragment,dialog的使用就下次再写。github:https://github.com/huangtaoOO/AndroidXMVVM
接口:https://www.wanandroid.com/ -
WPF MVVM开发框架
2018-03-20 12:55:54WPF编写的MVVM框架,可以拿来直接修改成自己的项目(框架比较基础,但大部分功能已经可以实现) -
android MVVM开发模式(一)
2016-07-22 12:04:44android MVVM开发模式 概念 mvvm 是一个在 mvp 架构上修改,目标是将view的一些更改,跟model关联起来,使得model的数据改变,直接通知到view上面来,从而解决mvp架构里面的v-p之间的接口太重问题。 所以mvvm的... -
android MVVM开发模式(三)
2016-07-26 09:40:33android MVVM开发模式(三) 为了更好地理解@BindingAdapter,github地址里面提交了一个adapters目录,将系统提供的适配提交上去,以便查阅。回顾 我们前两节讲了哪些内容呢? mvvm模型概念 dataBinding是什么 ... -
MVC、MVP和MVVM开发模式对比
2020-06-28 23:50:13MVC、MVP和MVVM开发模式对比1.MVC(Model View Controller)模式2.MVP(Model View Presenter)模式3.MVVM(Model View ViewModel)模式 1.MVC(Model View Controller)模式 MVC架构模式为,用户操作—>View(接收用户的... -
navigation单页面应用开发过程---入门篇(非MVVM开发模式)
2020-08-18 19:33:33介绍 在学习jetpack之后,了解navigation组件,navigation...建议使用该组件学习MVVM开发模式,MVVM开发模式就是基于jetpack框架,使用livedata+viewmodel+databinding开发 navigation开发步骤 建立Activity,进入A -
SilverLight在MVVM开发模式下对MySQL数据库操作源码
2013-01-14 09:50:36SilverLight在MVVM开发模式下对MySQL数据库操作源码,VS2012+silverLight5 -
MVVM开发模式简单实例MVVM Demo
2019-09-22 17:18:34本文主要是翻译Rachel Lim的一篇有关MVVM模式介绍的博文A Simple ...在我看来,如果你使用的是WPF或Sliverlight来开发程序就应该使用MVVM设计模式。它是你的代码清晰明了并易于维护。 可问题是网上有很多有关MVVM... -
MVVM开发模式实例解析
2013-01-14 09:54:25此实例为本人依托网上原有资料,加以个人理解整合,在MVVM模式下写的一个基于MySQL数据库的小Demo,...MVVM开发模式 概述 MVVM(Model-View-ViewModel)是在WPF/Silverlight一种很常见的开发模式,是MVC模式的一种变 -
mvvm开发模式
2019-02-25 18:23:18MVVM 模式将 Presenter 改名为 ViewModel,基本上与 MVP 模式完全一致。唯一的区别是,它采用双向绑定(data-binding):View的变动,自动反映在 ViewModel,反之亦然。Angular 和 Ember 都采用这种模式。 说明... -
android MVVM开发框架——(3)DataBinding 应用于RecyclerView
2017-10-31 21:25:45android MVVM开发框架——(1)DataBinding 基础应用android MVVM开发框架——(2)DataBinding 应用于ListView如果你对mvvm或者databinding不太熟悉的,建议先去看看前两篇博文 -
在WinForm程序中使用MVVM开发模式
2016-12-09 15:45:53在WinForm程序中使用MVVM开发模式 熟悉WPF的朋友一定在WPF程序中使用了MVVM的开发模式,因为MVVM可以带来以下几个优点: 1. 低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的"View... -
安卓Kotlin+组件化+MVVM开发项目基础搭建
2020-12-01 15:36:46安卓Kotlin+组件化+MVVM开发项目基础搭建 1.commen 公共业务 供上层业务调用 2.home | user 首页和个人中心模块 3. isDebug, true-home模块可进行单独编译 ,false- 所有模块融合到app模块 项目地址:... -
android MVVM开发框架——(2)DataBinding 应用于ListView
2017-10-31 20:29:35android MVVM开发框架——(1)DataBinding 基础应用 附上mvvm中databinding的基本应用链接,只有找到了基本用法才能继续进阶 -
sanic+mvvm开发案例
2018-01-22 09:49:02最近在学习sanic的开发,从网上找到了一个不错的案例,所以放来给大家参考 -
DataBinding玩转MVVM开发实战
2017-01-18 01:10:39使用它我们可以轻松实现MVVM(模型-视图-视图模型)模式,来实现应用之间数据与视图的分离、视图与业务逻辑的分离、数据与业务逻辑的分离,从而达到低耦合、可重用性、易测试性等好处。而使用DataBinding不仅减少了... -
iOS OC mvvm开发模式
2020-06-19 16:28:36相信大家对MVC开发都已经不陌生了,最经典开发模式 MVC构成: M:model也就是数据模型 V:View视图 C:Controller控制器 Model和View是相互独立的。View只负责页面展示,Model只是数据的存储,那么也就达到... -
Android之MVVM开发模式
2018-12-06 14:26:00MVVM 模式简介 MVVM模式是指Model-View-ViewModel。相信看过笔者关于MVP的文章的读者也会发现,无论如何抽象化,在我们的View层中是无法避免的要处理一部分逻辑的。而MVVM模式中的View是将View的状态和行为完全... -
js架构设计模式——理解javascript中的MVVM开发模式
2015-12-02 17:25:00理解javascript中的MVVM开发模式 http://blog.csdn.net/slalx/article/details/7856769 MVVM的全称是Model View ViewModel,这种架构模式最初是由微软的MartinFowler作为微软软件的展现层设计模式的规范提出,... -
MVVM开发模式MVVM Light Toolkit
2012-05-02 15:09:00MVVM模式就不细说了 个人理解 M是Model,是业务实体model,包含了数据的存取访问 V是View,是页面,是展示,是数据的显示,应该是单纯的xaml代码 VM是ViewModel,他应该是View上数据,方法,事件的抽象集合,是...
-
OPPO R11维修指导
-
MySQL中常用字符串函数
-
家庭管理系统、通讯录、时钟的C编程
-
大学生求职面试宝典60页
-
(新)备战2021软考软件设计师学习教程培训套餐
-
Anniversary Cake (深搜)
-
STM32-HMC5883L.rar
-
OPPO R15标准版(MT6771方案)原厂原理图维修图(PDF格式)
-
基于Android的音视频学习资料代码集合
-
原创 《深入理解 Java 虚拟机》阅读笔记3系列:虚拟机调优案例分析
-
跟我练内测小分队学习礼包
-
ubuntu16.04安装ros
-
vue端口号被占用报错npm ERR! @1.0.0 dev: `node build/dev-server.js`
-
Mysql IN查询过长报错解决
-
[笔记] 狂神 js 视频笔记 04
-
(新)备战2021软考网络规划设计师终极解密套餐
-
docker compose 容器编排工具
-
合工大机器人技术实验报告
-
2021-01-17
-
TensorFLow-Learning深度学习入门的一些简单例子