1、架构
1、架构:将系统进行模块/组件/角色的划分,建立角色之间(数据结构/事件等)的通信机制。
2、需求
1、用户输入账号名称->点击查询账户信息->展示查询成功失败结果。
3、不使用架构
1、activity_architecture.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<android.support.v7.widget.AppCompatEditText
android:id="@+id/etAccount"
android:layout_width="match_parent"
android:layout_height="80dp"
android:hint="请输入查询信息?" />
<android.support.v7.widget.AppCompatButton
android:id="@+id/btnGetAccount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="获取账号信息" />
<android.support.v7.widget.AppCompatTextView
android:id="@+id/tvResult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="--" />
</android.support.v7.widget.LinearLayoutCompat>
2、NormalActivity.java
public class NormalActivity extends AppCompatActivity implements View.OnClickListener {
/**
* 输入查询信息
*/
private AppCompatEditText etAccount;
/**
* 展示查询结果
*/
private AppCompatTextView tvResult;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_architecture);
initView();
}
/**
* 初始化数据
*/
private void initView() {
etAccount = findViewById(R.id.etAccount);
tvResult = findViewById(R.id.tvResult);
findViewById(R.id.btnGetAccount).setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnGetAccount:
getAccountData(getAccount(), new ICallback() {
@Override
public void onSuccess(Account account) {
showSuccess(account);
}
@Override
public void onFailed() {
showFailed();
}
});
break;
}
}
/**
* 查询获取用户数据
*
* @param accountName
* @param callback
*/
private void getAccountData(String accountName, ICallback callback) {
Random random = new Random();
boolean isSuccess = random.nextBoolean();
if (isSuccess) {
Account account = new Account();
account.setName(accountName);
account.setLevel(100);
callback.onSuccess(account);
} else {
callback.onFailed();
}
}
/**
* 获取用户输入信息
*
* @return
*/
private String getAccount() {
return etAccount.getText().toString();
}
/**
* 获取用户信息成功
*
* @param account
*/
private void showSuccess(Account account) {
tvResult.setText("账户名:" + account.getName() + ",账户等级:" + account.getLevel());
}
/**
* 获取用户信息失败
*/
private void showFailed() {
tvResult.setText("获取数据失败!");
}
}
4、MVC 模型
1、MVC (Model-View-Controller):模型-视图-控制器。
2、Model:获取数据(网络请求,SQL等);View:layout、View控件;Controller:Activity、Fragment;数据通信:数据结构 和 事件。
3、优点:实现 Model 与 View 分离,降低代码耦合。
4、缺点:Controller 与 View 难以解耦,项目越复杂 Controller 越臃肿。
5、例子:
- View:activity_architecture.xml 见 上文。
- Model:MvcModel
public class MvcModel {
/**
* 查询获取用户数据
*
* @param accountName
* @param callback
*/
public void getAccountData(String accountName, ICallback callback) {
Random random = new Random();
boolean isSuccess = random.nextBoolean();
if (isSuccess) {
Account account = new Account();
account.setName(accountName);
account.setLevel(100);
callback.onSuccess(account);
} else {
callback.onFailed();
}
}
}
- Controller
public class MvcActivity extends AppCompatActivity implements View.OnClickListener {
/**
* 输入查询信息
*/
private AppCompatEditText etAccount;
/**
* 展示查询结果
*/
private AppCompatTextView tvResult;
private MvcModel mMvcModel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_architecture);
initView();
}
/**
* 初始化数据
*/
private void initView() {
etAccount = findViewById(R.id.etAccount);
tvResult = findViewById(R.id.tvResult);
findViewById(R.id.btnGetAccount).setOnClickListener(this);
mMvcModel = new MvcModel();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnGetAccount:
mMvcModel.getAccountData(getAccount(), new ICallback() {
@Override
public void onSuccess(Account account) {
showSuccess(account);
}
@Override
public void onFailed() {
showFailed();
}
});
break;
}
}
/**
* 获取用户输入信息
*
* @return
*/
private String getAccount() {
return etAccount.getText().toString();
}
/**
* 获取用户信息成功
*
* @param account
*/
private void showSuccess(Account account) {
tvResult.setText("账户名:" + account.getName() + ",账户等级:" + account.getLevel());
}
/**
* 获取用户信息失败
*/
private void showFailed() {
tvResult.setText("获取数据失败!");
}
}
5、MVP 模型
1、MVP (Model-View-Presenter):模型-视图-控制器。
2、MVP 与 MVC 差异:Modle 与 View 不直接通信,通过 Presenter 实现通信;Activity 功能简化,主要负责 View 层的工作。
3、优点:解决 MVC 中 Controller 与 View 耦合的缺点,职责划分明显,更易于维护。
4、缺点:接口数量多,项目越复杂 Presenter 层越臃肿。
5、例子:
- Model
public class MvpModel {
/**
* 查询获取用户数据
*
* @param accountName
* @param callback
*/
public void getAccountData(String accountName, ICallback callback) {
Random random = new Random();
boolean isSuccess = random.nextBoolean();
if (isSuccess) {
Account account = new Account();
account.setName(accountName);
account.setLevel(100);
callback.onSuccess(account);
} else {
callback.onFailed();
}
}
}
- Presenter
public class MvpPresenter {
private IMvpView mView;
private MvpModel mModel;
public MvpPresenter(IMvpView view) {
this.mView = view;
mModel = new MvpModel();
}
public void getAccountData(String accountName) {
mModel.getAccountData(accountName, new ICallback() {
@Override
public void onSuccess(Account account) {
mView.showSuccess(account);
}
@Override
public void onFailed() {
mView.showFailed();
}
});
}
}
- View:activity_architecture.xml 见 上文。
public interface IMvpView {
/**
* 获取用户输入信息
* @return
*/
String getAccount();
/**
* 获取用户信息成功
* @param account
*/
void showSuccess(Account account);
/**
* 获取用户信息失败
*/
void showFailed();
}
public class MvpActivity extends AppCompatActivity implements View.OnClickListener, IMvpView {
/**
* 输入查询信息
*/
private AppCompatEditText etAccount;
/**
* 展示查询结果
*/
private AppCompatTextView tvResult;
private MvpPresenter mPresenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_architecture);
initView();
}
/**
* 初始化数据
*/
private void initView() {
etAccount = findViewById(R.id.etAccount);
tvResult = findViewById(R.id.tvResult);
findViewById(R.id.btnGetAccount).setOnClickListener(this);
mPresenter = new MvpPresenter(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnGetAccount:
mPresenter.getAccountData(getAccount());
break;
}
}
/**
* 获取用户输入信息
*
* @return
*/
@Override
public String getAccount() {
return etAccount.getText().toString();
}
/**
* 获取用户信息成功
*
* @param account
*/
@Override
public void showSuccess(Account account) {
tvResult.setText("账户名:" + account.getName() + ",账户等级:" + account.getLevel());
}
/**
* 获取用户信息失败
*/
@Override
public void showFailed() {
tvResult.setText("获取数据失败!");
}
}
6、dataBinding 使用
1、DataBinding:谷歌推出的数据绑定框架。
2、使用:
- 启用 DataBinding
// build.gradle
android {
// 1.启用dataBinding
dataBinding{
enabled = true
}
}
- 布局转为 DataBinding 布局:alt+enter->Convert to data binding layout。
- 数据绑定
7、MVVM 模型
1、MVVM (Model-View-ViewModel):模型-视图-视图模型。实现数据视图绑定(DataBinding),数据变化视图自定更新,视图变化数据也会自动更新。
2、MVVM 优点:实现数据和视图的双向绑定简化代码;减少接口数量;不需要 findViewById 操作。
3、MVVM 缺点:bug 难调试,dataBinding 编译不及时。
4、例子:
- Model
public class MvvmModel {
/**
* 查询获取用户数据
*
* @param accountName
* @param callback
*/
public void getAccountData(String accountName, ICallback callback) {
Random random = new Random();
boolean isSuccess = random.nextBoolean();
if (isSuccess) {
Account account = new Account();
account.setName(accountName);
account.setLevel(100);
callback.onSuccess(account);
} else {
callback.onFailed();
}
}
}
- View
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="viewModel"
type="com.strugglelin.architecture.mvvm.MvvmViewModel" />
</data>
<android.support.v7.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<android.support.v7.widget.AppCompatEditText
android:id="@+id/etAccount"
android:layout_width="match_parent"
android:layout_height="80dp"
android:hint="请输入查询信息?"
android:text="@={viewModel.userInput}" />
<android.support.v7.widget.AppCompatButton
android:id="@+id/btnGetAccount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{viewModel.getAccountData}"
android:text="获取账号信息" />
<android.support.v7.widget.AppCompatTextView
android:id="@+id/tvResult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@{viewModel.result}" />
</android.support.v7.widget.LinearLayoutCompat>
</layout>
- ViewModel
public class MvvmViewModel extends BaseObservable {
private Application application;
private MvvmModel model;
private ActivityMvvmBinding binding;
private String result;
private String userInput;
@Bindable
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
notifyPropertyChanged(BR.result);
}
@Bindable
public String getUserInput() {
return userInput;
}
public void setUserInput(String userInput) {
this.userInput = userInput;
notifyPropertyChanged(BR.userInput);
}
public MvvmViewModel(Application application) {
this.application = application;
model = new MvvmModel();
}
public MvvmViewModel(Application application, ActivityMvvmBinding binding) {
this.application = application;
model = new MvvmModel();
this.binding = binding;
}
public void getAccountData(View view) {
// final String accountName = binding.etAccount.getText().toString();
model.getAccountData(userInput, new ICallback() {
@Override
public void onSuccess(Account account) {
String info = account.getName() + "|" + account.getLevel();
setResult(info);
}
@Override
public void onFailed() {
setResult("获取数据失败!");
}
});
}
}
public class MvvmActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMvvmBinding binding;
binding = DataBindingUtil.setContentView(this, R.layout.activity_mvvm);
MvvmViewModel model = new MvvmViewModel(getApplication());
binding.setViewModel(model);
}
}