背景
随着Android的成熟Android的应用架构越来越多受到重视,因为程序的维护和扩展远远比开发成本要高很多,选用良好的的设计架构能很好地维护和扩展程序
1.MVC 模式
(1)Model 我们针对业务模型,建立数据结构和相关的类
(2)View 一般可以表达为xml文件的布局
(3)Controller 在Activity的逻辑处理可以认为是控制层
优缺点
MVC 模式的一个优点就是使用简单,我们最简单的一个入门demo就是一个mvc模式,但是存在的缺点就是view和model层存在耦合,然后就是Activity的逻辑结构太复杂,它既要承当页面的展示又要处理逻辑功能,当页面复杂之后逻辑将变得难以维护。
2.MVP模式
Model 主要提供提供数据的存储功能,presenter需要通过model层来存储数据,获取数据
View 负责处理用户事件和视图部分的展示,在Android可能是Activity,Fragment
Presenter:作为View和Model之间的桥梁,它从model层检索数据后返回view,使得view和model之间没有耦合
在MVP中 Presenter 完全将model和View进行了分离,主要的程序逻辑在Presenter里面实现,P与V没有直接关联,而是通过接口进行交互,从而使在变更view时候可以保持P不变。
2.1 应用MVP模式
自己随意定义的实体类
public class IpData {
private String country;
private String city;
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
public class Model {
private int code;
private IpData data;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public IpData getData() {
return data;
}
public void setData(IpData data) {
this.data = data;
}
}
抽取出一部分网络请求的定义和实现
public interface LoadTaskCallBack<T> {
void onSuccess(T t);
void onStart();
void onFailed();
void onFinish();
}
public interface NetTask<T> {
void execute(T data,LoadTaskCallBack callback);
}
public class IpInfoTask implements NetTask<String> {
private static IpInfoTask mInstance = null;
private static final String HOST = "http:www.baidu.com";
private LoadTaskCallBack loadTaskCallBack;
private IpInfoTask() {
}
public static IpInfoTask getmInstance() {
if (mInstance == null) {
mInstance = new IpInfoTask();
}
return mInstance;
}
@Override
public void execute(String data, final LoadTaskCallBack callback) {
RequestParams requestParams = new RequestParams();
requestParams.addFormDataPart("ip", data);
HttpRequest.post(HOST, requestParams, new BaseHttpRequestCallback<IpData>() {
@Override
public void onStart() {
super.onStart();
callback.onStart();
}
@Override
protected void onSuccess(IpData ipData) {
super.onSuccess(ipData);
callback.onSuccess(ipData);
}
@Override
public void onFailure(int errorCode, String msg) {
super.onFailure(errorCode, msg);
callback.onFailed();
}
@Override
public void onFinish() {
super.onFinish();
callback.onFinish();
}
});
}
}
定义p层与v层的接口
public interface IpInfoContract {
interface Presenter {
void getIpInfo(String ip);
}
interface View extends BaseView<Presenter> {
void setIpInfp(IpData ipInfp);
void showLoader();
void hideLoading();
void showError();
boolean isActive();
}
}
让P层去实现接口实现各种逻辑操作 然后调用v层的接口
public class IpInfoPresenter implements IpInfoContract.Presenter, LoadTaskCallBack {
private NetTask netTask;
private IpInfoContract.View addTaskView;
public IpInfoPresenter(NetTask netTask, IpInfoContract.View addTaskView) {
this.netTask = netTask;
this.addTaskView = addTaskView;
}
@Override
public void getIpInfo(String ip) {
netTask.execute(ip, this);
}
@Override
public void onSuccess(Object o) {
addTaskView.setIpInfp((IpData) o);
}
@Override
public void onStart() {
addTaskView.showLoader();
}
@Override
public void onFailed() {
addTaskView.showError();
}
@Override
public void onFinish() {
addTaskView.hideLoading();
}
}
我们可以看到 在view层只是实现了view接口然后实现了各种接口的ui上的实现细节,需要实现什么方法就调用P层的什么方法,p层处理完逻辑之后就会通过传入的view接口来实现ui上的改变,实现逻辑的分离。
public class MainActivity extends AppCompatActivity implements IpInfoContract.View {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IpInfoTask ipInfoTask = IpInfoTask.getmInstance();
IpInfoPresenter ipInfoPresenter = new IpInfoPresenter(ipInfoTask, this);
ipInfoPresenter.getIpInfo("地址");
}
Override
public void setIpInfp(IpData ipInfp) {
//做ui上的操作
}
@Override
public void showLoader() {
//做ui上的操作
}
@Override
public void hideLoading() {
//做ui上的操作
}
@Override
public void showError() {
//做ui上的操作
}
@Override
public boolean isActive() {
return false;
}
@Override
public void setPresenter(IpInfoContract.Presenter presenter) {
}
}
3.MVVM 模式
学习MVVM之前需要理解DataBind这个东西
我们先定义一个随意的实体类
package com.example.weihuada.mvvm;
public class Swordsman {
private String name;
private String level;
public Swordsman(String name, String level) {
this.name = name;
this.level = level;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLevel() {
return level;
}
public void setLevel(String level) {
this.level = level;
}
}
定义一个布局文件
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="sowrdsman"
type="com.example.weihuada.mvvm.Swordsman"></variable>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{sowrdsman.name}" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{sowrdsman.level}" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/bt_next"
/>
</LinearLayout>
</layout>
通过Activity将布局文件和实体类联系起来
import com.example.weihuada.mvvm.databinding.ActivityMain2Binding;
public class Main2Activity extends AppCompatActivity {
private ActivityMain2Binding mBind;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBind = DataBindingUtil.setContentView(this, R.layout.activity_main2);
Swordsman swordsman = new Swordsman("张无忌", "s");
mBind.setSowrdsman(swordsman);
mBind.btNext.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(Main2Activity.this, "点击了", Toast.LENGTH_SHORT).show();
}
});
}
}
上面的代码就是dataBind基本用法,也有其他的用法
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<data>
<import type="java.util.ArrayList"></import>
<import type="java.util.Map"></import>
<variable
name="list"
type="ArrayList"></variable>
<variable
name="map"
type="Map"></variable>
<variable
name="arrays"
type="String[]"></variable>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{list.get(1)}" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{map.get(`map`)}" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{arrays[1]}" />
</LinearLayout>
</layout>
一些运算符
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{`age`+String.valueOf(age)}"></TextView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="三目运算符"
android:visibility="@{man?View.VISIBLE:View.GONE}" />
双向绑定数据
第一种绑定方法 使用BaseObservable
public class ObSwordsman extends BaseObservable {
private String name;
private String level;
public ObSwordsman(String name, String level) {
this.name = name;
this.level = level;
}
@Bindable
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
@Bindable
public String getLevel() {
return level;
}
public void setLevel(String level) {
this.level = level;
notifyPropertyChanged(BR.name);
}
}
第二种绑定的方法 使用ObservableField
package com.example.weihuada.mvvm;
import android.databinding.BaseObservable;
import android.databinding.Bindable;
import android.databinding.ObservableField;
public class ObFSwordsman {
public ObservableField<String> name = new ObservableField<>();
public ObservableField<String> level = new ObservableField<>();
ObFSwordsman(String name,String level){
this.name.set(name);
this.level.set(level);
}
public ObservableField<String> getName() {
return name;
}
public void setName(ObservableField<String> name) {
this.name = name;
}
public ObservableField<String> getLevel() {
return level;
}
public void setLevel(ObservableField<String> level) {
this.level = level;
}
}
前面讲到model实体改变如何影响到ui反过来 如果ui发生改变如何影响model呢?
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@={sowrdsman.name}"
/>
这样就实现了双向绑定了