Project Name | Stars | Downloads | Repos Using This | Packages Using This | Most Recent Commit | Total Releases | Latest Release | Open Issues | License | Language |
---|---|---|---|---|---|---|---|---|---|---|
Mvvmhabit | 7,045 | 7 months ago | 12 | apache-2.0 | Java | |||||
👕基于谷歌最新AAC架构,MVVM设计模式的一套快速开发库,整合Okhttp+RxJava+Retrofit+Glide等主流模块,满足日常开发需求。使用该框架可以快速开发一个高质量、易维护的Android应用。 | ||||||||||
Androidproject | 5,116 | 6 months ago | 1 | apache-2.0 | Java | |||||
Android 技术中台,但愿人长久,搬砖不再有 | ||||||||||
Cloudreader | 4,759 | 9 days ago | 6 | apache-2.0 | Java | |||||
🗡️ 云阅:一款基于网易云音乐UI,使用玩Android Api,Retrofit2 + RxJava2 + Room + MVVM-databinding架构开发的Android客户端 | ||||||||||
Amazefilemanager | 4,399 | 9 days ago | 508 | gpl-3.0 | Java | |||||
Material design file manager for Android | ||||||||||
Qksms | 4,037 | 15 days ago | 467 | gpl-3.0 | Kotlin | |||||
The most beautiful SMS messenger for Android | ||||||||||
Android Mvp Mvvm Flytour | 2,885 | 2 years ago | 8 | apache-2.0 | Java | |||||
🔥🔥🔥 FlyTour是Android MVVM+MVP+Dagger2+Retrofit+RxJava+组件化+插件组成的双编码架构+双工程架构+双语言Android应用开发框架,通过不断的升级迭代该框架已经有了十个不同的版本,5.0之前工程架构采用gradle配置实现组件化,5.0之后的工程架构采用VirtualAPK实现了插件化,5.0之前采用Java编码实现,5.0之后采用Kotlin编码实现,编码架构由MVVM和MVP组成,工程架构和编码架构及编码语言开发者可根据自己具体的项目实际需求去决定选择使用,该框架是Android组件化、Android插件化、Android MVP架构、Android MVVM架构的集大成者,帮助你快速的搭建自己的App项目开发框架,以便把主要的精力放在自己的项目的业务功能实现上,另外在长期的工作实践中总结整理大量的实用工具类在项目lib_common组件的util包当中方便大家调用。 | ||||||||||
Android Mvvm Architecture | 2,856 | 3 months ago | 40 | apache-2.0 | Java | |||||
This repository contains a detailed sample app that implements MVVM architecture using Dagger2, Room, RxJava2, FastAndroidNetworking and PlaceholderView | ||||||||||
Awesome Android Kotlin Apps | 1,947 | 20 days ago | 12 | Kotlin | ||||||
👓 A curated list of awesome android kotlin apps by open-source contributors. | ||||||||||
Mvvm Architecture | 1,778 | a year ago | 5 | Kotlin | ||||||
The practice of MVVM + Jetpack architecture in Android. | ||||||||||
Android Learning Resources | 1,289 | 3 years ago | 2 | |||||||
Android学习资源网站索引大全 |
本项目使用 MVVM 模式架构,使用 Jetpack 组件实现,功能代码实现组件化,目标是编写一个 玩安卓 客户端
目前 MVVM 框架已经完成,Http 框架已经完成。玩安卓客户端功能代码正在进行中,组件化将在基础功能实现之后完成,请持续关注。。。
RHttp 是基于 Retrofit2 + OkHttp3 + RxJava2 +Lifecycle 封装的网络请求框架
//初始化RHttp(必须)
RHttp.Configure.get().init(this);
new RHttp.Builder()
.baseUrl("https://www.wanandroid.com/")
.post()
.apiUrl("user/login")//接口地址
.addParameter(new TreeMap<String, Object>())//参数
.addHeader(new TreeMap<String, Object>())//请求头
.lifecycle(this)//自动管理生命周期
.tag("login_tag")//请求唯一标识,后续根据tag取消请求
.build()
.execute(new HttpCallback<Response<UserBean>>() {
@Override
public void onSuccess(Response<UserBean> object) {
//请求成功
}
@Override
public void onError(int code, String msg) {
//请求失败
}
@Override
public void onCancel() {
//请求取消
}
});
在 Android 项目中理解
Presenter 作为桥梁连接 View 和 Model,解耦模块。 主要职责绑定View/解绑View,同时内部持有 Model 从而链接 V / M
//Presenter
public class MVVMPresenter<V extends IView> implements IPresenter<V> {
//View(传递时对象为Activity/Fragment必须要销毁)
protected V mView;
@Override
public void attachView(@NonNull V view) {
mView = view;
}
@Override
public void detachView() {
mView = null;
}
/**
* 获取View
* 备注: getView() 在组件销毁后可能为 null 使用前通过 isAttached() 判断
*
* @return
*/
public V getView() {
return mView;
}
/**
* View是否已经绑定
*
* @return
*/
public boolean isAttached() {
return mView != null;
}
}
//具体业务Presenter
public class LoginPresenter extends MVVMPresenter<ILoginView> {
/**
* 登录
*/
public void login(String account, String password) {
ModelFactory.getModel(AccountModel.class).login(account, password, getView().getLifecycleOwner(), new IModelCallback.Http<UserBean>() {
@Override
public void onSuccess(UserBean object) {
if (!isAttached()) return;
getView().loginSuccess(object);
}
@Override
public void onError(int code, String msg) {
if (!isAttached()) return;
if (isAttached()) getView().onError(code, msg);
}
@Override
public void onCancel() {
//TODO
}
});
}
}
上述代码可以看出
ILoginView 是什么?
定义一系列界面相关的View接口,然后在 Activity/Fragment 中实现(这里将 Activity/Fragment 角色定为 View,只处理UI展示),该 View 接口与 Presenter 相绑定,在 Presenter 中处理 控制器 相关的逻辑,最终在需要操作UI时调用对应 View 的函数定义
//基础View接口,可以是空内容,此处添加了两个常用的函数定义
public interface IMVVMView {
/**
* LifecycleOwner
*/
LifecycleOwner getLifecycleOwner();
/**
* Activity
*/
Activity getActivity();
}
//具体业务View接口定义,按需实现
public interface ILoginView extends IMVVMView {
//登录成功
public void loginSuccess(UserBean userBean);
//登录失败
public void onError(int code, String desc);
}
//Activity/Fragment 中实现View接口
public class LoginActivity extends BaseActivity implements ILoginView {
@Override
public void onError(int code, String desc) {
//update ui
}
@Override
public void loginSuccess(UserBean userBean) {
//update ui
}
}
上述代码可以看出,View 只负责处理 UI ,何时处理?数据怎么来?都交由 Presenter 完成。职责很单一
数据模型的构建或者获取,提供数据实体。此处并没有太多的限制,只要能构建出数据模型就可以
public interface IModelCallback {
/**
* 网络数据回调,泛指http
*
* @param <T>
*/
public interface Http<T> {
public void onSuccess(T object);
public void onError(int code, String msg);
public void onCancel();
}
/**
* 其他数据回调<本地数据,数据库等>
*
* @param <T>
*/
public interface Data<T> {
public void onSuccess(T object);
}
}
//具体业务Model(实现方式没有规定,合理构造数据即可)
public class AccountModel {
/**
* 登录
*/
public void login(String account, String password, LifecycleOwner lifecycle, final IModelCallback.Http<UserBean> modelCallback) {
BizFactory.getBiz(AccountBiz.class).login(account, password, lifecycle, new HttpCallback<Response<UserBean>>() {
@Override
public void onSuccess(Response<UserBean> value) {
//通过 IModelCallback 回调给调用者(Presenter)
modelCallback.onSuccess(value.getData());
}
@Override
public void onError(int code, String desc) {
//通过 IModelCallback 回调给调用者(Presenter)
modelCallback.onError(code, desc);
}
@Override
public void onCancel() {
//通过 IModelCallback 回调给调用者(Presenter)
modelCallback.onCancel();
}
});
}
}
这里没有对 ViewModel 进行任何封装,在 MVP 的模式下使用 Jetpack 提供的 ViewModel 将 特定的 ViewModel 直接绑定到 View
/**
* ILoginView
*/
public interface ILoginView extends IMVVMView {
public void loginSuccess(UserBean userBean);
public void onError(int code, String desc);
}
public class LoginModel {
/**
* 登录
*/
public void login(String account, String password, LifecycleOwner lifecycle, final IModelCallback.Http<UserBean> modelCallback) {
//构建请求参数
TreeMap<String, Object> request = new TreeMap<>();
request.put("username", account);
request.put("password", password);
//发送请求
new RHttp.Builder()
.post()
.apiUrl("user/login")
.addParameter(request)
.lifecycle(lifecycle)
.build()
.execute(new HttpCallback<Response<UserBean>>() {
@Override
public void onSuccess(Response<UserBean> object) {
modelCallback.onSuccess(object.getData());
}
@Override
public void onError(int code, String msg) {
modelCallback.onError(code, msg);
}
@Override
public void onCancel() {
modelCallback.onCancel();
}
});
}
}
public class LoginPresenter extends MVVMPresenter<ILoginView> {
/**
* 登录
*/
public void login(String account, String password) {
ModelFactory.getModel(LoginModel.class).login(account, password, getView().getLifecycleOwner(), new IModelCallback.Http<UserBean>() {
@Override
public void onSuccess(UserBean object) {
if (!isAttached()) return;
getView().loginSuccess(object);
}
@Override
public void onError(int code, String msg) {
if (isAttached()) getView().onError(code, msg);
}
@Override
public void onCancel() {
}
});
}
}
public class LoginActivity extends BaseActivity<ILoginView, LoginPresenter> implements ILoginView {
private UserViewModel userViewModel;
private LoginDataBinding dataBinding;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//dataBinding
dataBinding = DataBindingUtil.setContentView(this, layoutId());
//ViewModel
userViewModel = new ViewModelProvider(this).get(UserViewModel.class);
getViewDataBinding().setLifecycleOwner(this);
dataBinding.setUserViewModel(userViewModel);
//登录
getMVVMPresenter().login("aaa", "xxx");
}
@Override
protected int layoutId() {
return R.layout.layout_sample;
}
@Override
public LoginPresenter makePresenter() {
return new LoginPresenter();
}
@Override
public void loginSuccess(UserBean userBean) {
//update ui
//findViewById(R.id.tv_user_name).setText(userBean.getNickname());//传统方式更新UI
//dataBinding.tvUserName.setText(userBean.getNickname());//dataBinding获取控件更新UI
userViewModel.getUserBean().setValue(userBean);//ViewModel绑定数据直接更新UI
}
@Override
public void onError(int code, String desc) {
//update ui
Toast.makeText(this, desc, Toast.LENGTH_SHORT).show();
}
}
package com.ruffian.android.mvvm.sample;
public class UserViewModel extends ViewModel {
private MutableLiveData<UserBean> userBeanLiveData;
public MutableLiveData<UserBean> getUserBean() {
if (userBeanLiveData == null) userBeanLiveData = new MutableLiveData<>();
return userBeanLiveData;
}
}
<?xml version="1.0" encoding="utf-8"?>
<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 class="LoginDataBinding">
<variable
name="userViewModel"
type="com.ruffian.android.mvvm.sample.UserViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white">
<TextView
android:id="@+id/tv_user_name"
style="@style/wrap_tv_14_black"
android:text="@{[email protected]/placeholder}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="@string/placeholder" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
MIT License
Copyright (c) 2021 Ruffian-痞子