Android MVC,MVP,MVVM模式入门——重构登陆注册功能

时间:2022-04-12 15:16:40

一  MVC模式:

M:model,业务逻辑

V:view,对应布局文件

C:Controllor,对应Activity

Android MVC,MVP,MVVM模式入门——重构登陆注册功能

项目框架:

Android MVC,MVP,MVVM模式入门——重构登陆注册功能

代码部分:

  layout文件(适用于MVC和MVP两个Demo):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> <EditText
android:id="@+id/edit_username"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="username"/> <EditText
android:id="@+id/edit_password"
android:layout_width="match_parent"
android:layout_height="50dp"
android:inputType="textPassword"
android:hint="password"/> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"> <Button
android:id="@+id/login"
android:layout_marginLeft="10dp"
android:layout_width="120dp"
android:layout_height="50dp"
android:text="Login"/> <Button
android:id="@+id/clear"
android:layout_width="120dp"
android:layout_height="50dp"
android:layout_marginLeft="100dp"
android:text="Clear"/> </LinearLayout> <ProgressBar
android:id="@+id/login_progressbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="invisible"
/>
</LinearLayout>

  User类,定义成员对象:

package com.example.liang.userloginformvc.modle;

/**
* Created by liang on 2016/8/22.
*/
public class User {
private String username;
private String password; public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
}
}

  OnLoginListener,j监听登陆状态:

package com.example.liang.userloginformvc.modle;

/**
* Created by liang on 2016/8/22.
*/
public interface OnLoginListener {
void loginSuccess(User user);
void loginFailed();
}

  UserBiz,登陆逻辑:

package com.example.liang.userloginformvc.modle;

/**
* Created by liang on 2016/8/22.
*/
public class UserBiz { public void login(final String username,final String password,final OnLoginListener loginListener){
new Thread(){
@Override
public void run() {
try{
Thread.sleep(2000);
}catch(InterruptedException e){
e.printStackTrace();
}
//模拟登陆
if("lqy".equals(username)&&"123".equals(password)){
User user=new User();
user.setUsername(username);
user.setPassword(password);
loginListener.loginSuccess(user);
}else{
loginListener.loginFailed();
}
}
}.start(); }
}

MVC模式总结:

  首先从响应用户点击事件,到MainActivity,获取View中的数据再交给Model层处理,通过返回的数据,MainActivity再改变视图。

从MVC到MVP:由于View和Model之间的依赖还是太强,希望他们可以绝对独立的存在,慢慢的就演化出了MVP

二  MVP模式

M:业务逻辑与实体模型

V:负责View的绘制以及用户交互,对应Activity

P:负责完成View与Modle之间的交换

Android MVC,MVP,MVVM模式入门——重构登陆注册功能

项目框架:

Android MVC,MVP,MVVM模式入门——重构登陆注册功能

代码部分:

  user:

package com.example.liang.userloginformvp.bean;

/**
* Created by liang on 2016/8/22.
*/
public class User{
private String username;
private String password; public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
}
}

  IUserBiz:

package com.example.liang.userloginformvp.biz;

/**
* Created by liang on 2016/8/22.
*/
public interface IUserBiz{
public void login(String username,String password,OnLoginListener onLoginListener);
}

  OnLoginListener:

package com.example.liang.userloginformvp.biz;

/**
* Created by liang on 2016/8/22.
*/
public interface IUserBiz{
public void login(String username,String password,OnLoginListener onLoginListener);
}

  UserBiz:

package com.example.liang.userloginformvp.biz;

import com.example.liang.userloginformvp.bean.User;

/**
* Created by liang on 2016/8/22.
*/
public class UserBiz implements IUserBiz {
//在这里重写IUserBiz中的方法
@Override
public void login(final String username, final String password, final OnLoginListener loginListener) {
//注意,这里并没有new OnLoginListener的对象,所以也没有重写方法
//要留在UserLoginPresenter中重写,并通过登陆的状态调用相应的视图
new Thread(){
@Override
public void run() {
try{
Thread.sleep(2000);
}catch(InterruptedException e){
e.printStackTrace();
}
//模拟登陆成功
if("lqy".equals(username)&&"123".equals(password)){
User user=new User();
user.setUsername(username);
user.setPassword(password);
loginListener.loginSuccess(user);
}else{
loginListener.loginFailed();
}
}
}.start();
}
}

  UserLoginPresenter:

public class UserLoginPresenter {
private IUserBiz userBiz;
private IUserLoginView userLoginView;
private Handler mHandler = new Handler(); public UserLoginPresenter(IUserLoginView userLoginView) {
this.userLoginView = userLoginView; //给userBiz一个子类的空间,此时方法已经被重写,登陆逻辑已被判断
this.userBiz = new UserBiz();
} public void login() {
userLoginView.showLoading();
userBiz.login(userLoginView.getUserName(), userLoginView.getPassword(), new OnLoginListener() {
@Override
public void loginSuccess(final User user) {
//需要在UI线程执行
mHandler.post(new Runnable() {
@Override
public void run() {
userLoginView.toMainActivity(user);
userLoginView.hideLoading();
}
}); } @Override
public void loginFailed() {
//需要在UI线程执行
mHandler.post(new Runnable() {
@Override
public void run() {
userLoginView.showFailedError();
userLoginView.hideLoading();
}
}); }
});
} public void clear() {
userLoginView.clearUserName();
userLoginView.clearPassword();
} }

  IUserLoginPresenter:

package com.example.liang.userloginformvp.view;

import com.example.liang.userloginformvp.bean.User;

/**
* Created by liang on 2016/8/22.
*/
public interface IUserLoginView {
String getUserName(); String getPassword(); void clearUserName(); void clearPassword(); void showLoading(); void hideLoading(); void toMainActivity(User user); void showFailedError();
}

  MainActivity:

package com.example.liang.userloginformvp;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast; import com.example.liang.userloginformvp.bean.User;
import com.example.liang.userloginformvp.presenter.UserLoginPresenter;
import com.example.liang.userloginformvp.view.IUserLoginView; public class MainActivity extends ActionBarActivity implements IUserLoginView{ private EditText usernaem_edit,password_edit;
private Button login_btn,clear_btn;
private ProgressBar loading; private UserLoginPresenter userLoginPresenter=new UserLoginPresenter(this); @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); initViews();
} private void initViews(){
usernaem_edit=(EditText)findViewById(R.id.edit_username);
password_edit=(EditText)findViewById(R.id.edit_password); login_btn=(Button)findViewById(R.id.login);
clear_btn=(Button)findViewById(R.id.clear); loading=(ProgressBar)findViewById(R.id.login_progressbar);
loading.setVisibility(View.INVISIBLE);
login_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
userLoginPresenter.login();
}
}); clear_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
userLoginPresenter.clear();
}
}); } @Override
public String getUserName() {
return usernaem_edit.getText().toString();
} @Override
public String getPassword() {
return password_edit.getText().toString();
} @Override
public void clearUserName() {
usernaem_edit.setText("");
} @Override
public void clearPassword() {
password_edit.setText("");
} @Override
public void showLoading() {
loading.setVisibility(View.VISIBLE);
} @Override
public void hideLoading() {
loading.setVisibility(View.GONE);
} @Override
public void toMainActivity(User user) {
Toast.makeText(this,user.getUsername()+" login success , to MainActivity",Toast.LENGTH_SHORT)
.show();
} @Override
public void showFailedError() {
Toast.makeText(this, "login failed", Toast.LENGTH_SHORT).show();
}
}

MVP总结:Activity作为View加载视图并响应点击事件(直接想登陆),点击事件交由Presenter处理,Presenter将登陆逻辑交给Model处理,并根据model处理结果告诉View改返回什么试图。

Android MVC,MVP,MVVM模式入门——重构登陆注册功能

------------------------------------分隔线

Android MVC,MVP,MVVM模式入门——重构登陆注册功能

从MVP到MVVM中:至于MVVM基本上和MVP一模一样,感觉只是名字替换了一下。他的关键技术就是今天的主题(Data Binding)。View的变化可以自动的反应在ViewModel,ViewModel的数据变化也会自动反应到View上。这样开发者就不用处理接收事件和View更新的工作,框架已经帮你做好了。

三  MVVM模式

M:model,业务逻辑

V:加载视图,和layout通信,进行数据绑定与更新,对应Activity(由于代码是在太少,有时自带启动自己的方法)

VM:判断条件,逻辑实现

Android MVC,MVP,MVVM模式入门——重构登陆注册功能

项目框架:

Android MVC,MVP,MVVM模式入门——重构登陆注册功能

首先配置环境

Android MVC,MVP,MVVM模式入门——重构登陆注册功能

加一句:

Android MVC,MVP,MVVM模式入门——重构登陆注册功能

  LoginViewModel

package com.example.liang.userloginformvvm.viewmodel;

import android.content.Context;
import android.databinding.ObservableField;
import android.databinding.ObservableInt;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View; import com.example.liang.userloginformvvm.modle.User;
import com.example.liang.userloginformvvm.view_activity.MainActivity; /**
* Created by liang on 2016/8/23.
*/
public class LoginViewModel implements ViewModel {
private Context context;
//用于数据刷新的便捷类型:ObservableField,ObservableInt····
public ObservableField<String> loginMessage;
public ObservableInt loginMessageVisibility;
private String editTextUsernameValue = "";
private String editTextPasswordValue = ""; public LoginViewModel(Context context) {
this.context = context;
this.loginMessage = new ObservableField<>("");
this.loginMessageVisibility = new ObservableInt(View.INVISIBLE);
} //登陆,实际上这个方法是在layout文件中调用的 public void loginAuthentication(View view) {
if ((editTextUsernameValue.equals("lqy")) && (editTextPasswordValue.equals("123"))) {
loginMessage.set("");
loginMessageVisibility.set(View.INVISIBLE);
User user = new User(editTextUsernameValue, editTextPasswordValue);
context.startActivity(MainActivity.newIntent(context, user));
} else if ((editTextUsernameValue.equals("")) || (editTextPasswordValue.equals(""))) {
loginMessage.set("Username or Password can't be empty!");
loginMessageVisibility.set(View.VISIBLE);
} else {
loginMessage.set("Username = lqy \n Password = 123");
loginMessageVisibility.set(View.VISIBLE);
}
} //观察Text变化的TextWatcher
public TextWatcher getUsernameUpdate() {
return new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
editTextUsernameValue = charSequence.toString();
} @Override
public void afterTextChanged(Editable editable) { }
};
} public TextWatcher getPasswordUpdate() {
return new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
editTextPasswordValue = charSequence.toString();
} @Override
public void afterTextChanged(Editable editable) { }
};
} @Override
public void destroy() { }
}

  MainViewModel:

package com.example.liang.userloginformvvm.viewmodel;

import android.content.Context;

import com.example.liang.userloginformvvm.modle.User;

/**
* Created by liang on 2016/8/23.
*/
public class MainViewModel {
private Context context;
private User user; public MainViewModel(Context context, User user) {
this.context = context;
this.user = user;
} public String getUsername(){
return user.username;
}
public String getPassword(){
return user.password;
}
}

  ViewModel:

package com.example.liang.userloginformvvm.viewmodel;

/**
* Created by liang on 2016/8/23.
*/
public interface ViewModel {
void destroy();
}

  User:

package com.example.liang.userloginformvvm.modle;

import android.os.Parcel;
import android.os.Parcelable; /**
* Created by liang on 2016/8/23.
*/
//实现Parcelable接口,可以让类在网络或进程中传递
public class User implements Parcelable{
public String username;
public String password; public User(String username,String password){
this.username=username;
this.password=password;
} public User(Parcel in) {
username = in.readString();
password = in.readString();
} public static final Creator<User> CREATOR=new Creator<User>() {
@Override
public User createFromParcel(Parcel parcel) {
return new User(parcel);
} @Override
public User[] newArray(int i) {
return new User[i];
}
}; @Override
public int describeContents() {
return 0;
} @Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(this.username);
parcel.writeString(this.password);
}
}

  

  LoginActivity

package com.example.liang.userloginformvvm.view_activity;

import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity; import com.example.liang.userloginformvvm.R;
import com.example.liang.userloginformvvm.databinding.ActivityLoginBinding;
import com.example.liang.userloginformvvm.viewmodel.LoginViewModel; /**
* Created by liang on 2016/8/23.
*/
public class LoginActivity extends AppCompatActivity{
//当给布局指定格式之后会产生相应的Bing类,例如activity_login.xml会产生ActivityLoginBinding类
ActivityLoginBinding loginBinding;
LoginViewModel viewModel; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//指定布局,没有XXX.findViewById了
loginBinding = DataBindingUtil.setContentView(this, R.layout.activity_login); viewModel=new LoginViewModel(this);
loginBinding.setViewmodel(viewModel);
}
}

  MainActivity

package com.example.liang.userloginformvvm.view_activity;

import android.content.Context;
import android.content.Intent;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity; import com.example.liang.userloginformvvm.R;
import com.example.liang.userloginformvvm.databinding.ActivityMainBinding;
import com.example.liang.userloginformvvm.modle.User;
import com.example.liang.userloginformvvm.viewmodel.MainViewModel; /**
* Created by liang on 2016/8/23.
*/
public class MainActivity extends AppCompatActivity{
ActivityMainBinding activityMainBinding;
MainViewModel mainViewModel; //传递数据的标志
private static final String EXTRA_USER = "extra_user"; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activityMainBinding= DataBindingUtil.setContentView(this, R.layout.activity_main); User user=getIntent().getParcelableExtra(EXTRA_USER); mainViewModel=new MainViewModel(this,user);
activityMainBinding.setMainviewmodel(mainViewModel);
} //viewmodel唤醒这个Activity的方法
public static Intent newIntent(Context context, User user){
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra(EXTRA_USER,user);
return intent;
}
}

  下面就是非常重要的layout文件了:

activity_mian.xml

<?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>
<variable
name="viewmodel"
type="com.example.liang.userloginformvvm.viewmodel.LoginViewModel"> </variable>
</data>
<!--先要指定绑定的类-->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view_activity.LoginActivity"> <TextView
android:id="@+id/loginmessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewmodel.loginMessage}"
android:textAlignment="center"
android:textColor="@color/colorAccent"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"/> <!--监听text的变化-->
<EditText
android:id="@+id/login_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="textPersonName"
android:ems="10"
android:layout_centerHorizontal="true"
android:layout_below="@+id/loginmessage"
android:hint="UserName"
android:layout_marginBottom="10dp"
app:addTextChangedListener="@{viewmodel.usernameUpdate}"/> <EditText
android:id="@+id/login_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:hint="Password"
android:ems="10"
android:layout_below="@id/login_username"
android:layout_centerHorizontal="true"
android:layout_marginBottom="10dp"
app:addTextChangedListener="@{viewmodel.passwordUpdate}" /> <Button
android:layout_width="210dp"
android:layout_height="wrap_content"
android:text="LOGIN"
android:layout_below="@id/login_password"
android:layout_centerHorizontal="true"
android:onClick="@{viewmodel.loginAuthentication}"/> </RelativeLayout>
</layout>

activity_login.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="mainviewmodel"
type="com.example.liang.userloginformvvm.viewmodel.MainViewModel"></variable>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view_activity.MainActivity"> <LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:text="Welcome"
android:layout_weight="1"/> <TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:text="@{mainviewmodel.username}"/>
</LinearLayout> <LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="horizontal"> <TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:text="Password is"
android:layout_weight="1"/> <TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
android:text="@{mainviewmodel.password}"/>
</LinearLayout>
</LinearLayout> </layout>

MVVM总结:通过View加载布局,并通过布局调用ViewModel中的方法,VeiwModel可以通过调用后的结果决定启动什么视图,同时ViewModel保持和model的通信。

2016.8.24首次截稿

有什么错误麻烦大家指出来,在线更新。

参考资料:

鸿洋老师的博客: http://blog.csdn.net/lmj623565791/article/details/46596109

胡笛老师的微信推文

还有github上的资源

以及http://my.oschina.net/u/1175007/blog/613889

Android MVC,MVP,MVVM模式入门——重构登陆注册功能的更多相关文章

  1. 浅析前端开发中的 MVC&sol;MVP&sol;MVVM 模式

    MVC,MVP和MVVM都是常见的软件架构设计模式(Architectural Pattern),它通过分离关注点来改进代码的组织方式.不同于设计模式(Design Pattern),只是为了解决一类 ...

  2. android MVC &amp&semi;&amp&semi; MVP &amp&semi;&amp&semi; MVVM分析和对比

    相关:http://www.cnblogs.com/wytiger/p/5305087.html 出处http://blog.csdn.net/self_study,对技术感兴趣的同鞋加群544645 ...

  3. mvc mvp mvvm模式的区别

    mvc模式中,Model不依赖于View,但是View是依赖于Model的,m和v没有进行完全的分离,三者之间是单向的操作 mvp模式中,m和v之间的交互是双向的,m和v完全分离,m和v的交互是通过P ...

  4. Android MVC MVP MVVM &lpar;三&rpar;

    MVVM Model-View-ViewModel的简写 在MVP基础上实现数据视图的DataBinding,数据变化,视图自动变化,反之也成立. DataBinding 启用DataBinding ...

  5. Android MVC MVP MVVM &lpar;一&rpar;

    示例效果 一共三个控件,EditText,Button,TextView 成功显示账号信息,查询失败显示错误信息. <?xml version="1.0" encoding= ...

  6. Android MVC MVP MVVM &lpar;二&rpar;

    MVP模型 View主要是Activity,Fragment MVP和MVC的差别 1.Model和View不再直接通信,通过中间层Presenter来实现. 2.Activity的功能被简化,不再充 ...

  7. Android App的设计架构:MVC&comma;MVP&comma;MVVM与架构经验谈

    相关:http://www.cnblogs.com/wytiger/p/5996876.html 和MVC框架模式一样,Model模型处理数据代码不变在Android的App开发中,很多人经常会头疼于 ...

  8. Android App的设计架构:MVC&comma;MVP&comma;MVVM与架构AAAAA

    1. 架构设计的目的1.1 通过设计使程序模块化,做到模块内部的高聚合和模块之间的低耦合.1.2 这样做的好处是使得程序在开发的过程中,开发人员只需要专注于一点,提高程序开发的效率,并且更容易进行后续 ...

  9. 前端mvc mvp mvvm 架构介绍(vue重构项目一)

    首先 我们为什么重构这个项目 1:我们现有的技术是前后台不分离,页面上采用esayUI+jq构成的单页面,每个所谓的单页面都是从后台胜场的唯一Id 与前端绑定,即使你找到了那个页面元素,也找不到所在的 ...

随机推荐

  1. asp&period;net与Matlab类型转换&lpar;待补全&rpar;

    上上篇的博客已经提到如何配置环境,即如何在asp.net中调用matlab生成的dll文件.这篇博客打算做个笔记,那就是matlab和C#数据类型如何转换.随着需求的增加,我会不断增加新的类型转换. ...

  2. Codeforces Round &num;348 &lpar;VK Cup 2016 Round 2&comma; Div&period; 2 Edition&rpar; D&period; Little Artem and Dance

    题目链接: http://codeforces.com/contest/669/problem/D 题意: 给你一个初始序列:1,2,3,...,n. 现在有两种操作: 1.循环左移,循环右移. 2. ...

  3. &lbrack;旧博客&rsqb;Python 第一天总结

    语法部分: 3**4 表示3的四次方 -1**3 结果是-1 raw_input 输入文本 input 输入值,input 3*3 结果为9 pow(5,5) 等于 5*5 abs(-1.8) 等于 ...

  4. Raspberry Pi无线路由器篇

    RaspberryPi可以折腾的方法很多,我将会吧自己的折腾经验与大家分享.   作为无线路由器,需要提供dhcp的功能和无线ap的能力,我们分别通过isc-dhcp-server和hostapd这两 ...

  5. 【LeetCode】26&period; Remove Duplicates from Sorted Array

    Given a sorted array, remove the duplicates in place such that each element appear only once and ret ...

  6. Spring线程池开发实战

    Spring线程池开发实战 作者:chszs,转载需注明. 作者博客主页:http://blog.csdn.net/chszs 本文提供了三个Spring多线程开发的例子,由浅入深,由于例子一目了然, ...

  7. vue项目中引入mint-ui的方式(全部引入与按需引入)

    参考哦 https://blog.csdn.net/qq_36742720/article/details/83620584 https://jingyan.baidu.com/article/c1a ...

  8. MySQLSource-Flume

    1. 自定义Source说明 实时监控MySQL,从MySQL中获取数据传输到HDFS或者其他存储框架,所以此时需要我们自己实现MySQLSource. 2. 自定义MySQLSource步骤 根据官 ...

  9. mvn打包到私服的命令

    1.mvn clean package install -Dmaven.test.skip=true deploy 2.docker清楚Nexus私服上包的命令: a) docker exec -it ...

  10. String、StringBuffer、StringBulider

    三者都实现了CharSequence接口,因此CharSequence可认为是一个字符串的协议接口 1.String类是不可变类,即一旦一个String对象被创建后,包含在这个对象中的字符序列是不可改 ...