App有一个好的架构,它可以带来如下的好处:容易扩展;容易维护。如果一个App没有一个好的架构,那么,耦合的代码会到处出现。没有一个架构,那么,代码会是各种混乱,我深有体会。
混乱,看起来问题不大,对于小规模的app,因为,我始终还是可以花时间读懂它。但是,随着app的功能越来越多,那么,你每次添加一个功能或者修改一个功能的时候,你会发现:1.你做的功能和之前做的功能,有重复代码。2.你难以快速完好,正确的修改一个功能,因为代码过于耦合,因为代码层次不清楚。
总之,过去的经验告诉我,要对一个App进行架构,划分好层次,然后,按照定义好的架构模式去开发,这可以带来好处。我在确定了架构的重要性之后,那么接下来当然是学习它。
我今天学习的架构模式是MVP。
MVP模式:
一个软件被划分成三层,View层,Presenter层,Model层。
View层的职责是展示界面,界面绘制。
Presenter层的职责是,实现各种业务逻辑,业务逻辑的代码都放在这一层。
Model层的职责是数据的存储,修改,获取。
各层之间的交互:
View层和Presenter层之间的通信是双向的。
Presenter层和Model层之间的通信是双向的。
View层不与Model层发生交互。
MVP模式应用到Android app:
View层:activity,fragment,其中的界面展示,就是View层的内容。
Presenter层:点击一个按钮要执行的业务逻辑,则是由Presenter层来实现。也就是说,Presenter层抽象,提取出activity,fragment中的业务逻辑。这样就可以将业务逻辑代码与界面展示代码解耦掉。可以重用业务逻辑。
Model层:这一层,则是数据存取,数据修改层。配置信息,获取数据源的数据,获取服务器数据,获取数据库的数据,更新数据库的数据,这些实现代码都由这一层来提供。
MVP模式应用到Android app的一个例子分析:
例子分析:
1.每个层要做的事情,用接口声明好。
2.接口声明好之后,就用实际的类来实现。
比如登陆界面:
1.要确定出登陆界面,它的View有哪些行为。
2.登陆界面的业务逻辑实现,是通过调用presenter层的方法来进行的。
3.presenter与view之间是相互通信的。
Login这个模块,把View层和presenter层放在了一起:
package com.antonioleiva.mvpexample.app.Login;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;
import com.antonioleiva.mvpexample.app.R;
import com.antonioleiva.mvpexample.app.main.MainActivity;
public class LoginActivity extends Activity implements LoginView, View.OnClickListener {
private ProgressBar progressBar;
private EditText username;
private EditText password;
private LoginPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
progressBar = (ProgressBar) findViewById(R.id.progress);
username = (EditText) findViewById(R.id.username);
password = (EditText) findViewById(R.id.password);
findViewById(R.id.button).setOnClickListener(this);
presenter = new LoginPresenterImpl(this);
}
@Override public void showProgress() {
progressBar.setVisibility(View.VISIBLE);
}
@Override public void hideProgress() {
progressBar.setVisibility(View.GONE);
}
@Override public void setUsernameError() {
username.setError(getString(R.string.username_error));
}
@Override public void setPasswordError() {
password.setError(getString(R.string.password_error));
}
@Override public void navigateToHome() {
startActivity(new Intent(this, MainActivity.class));
finish();
}
@Override public void onClick(View v) {
presenter.validateCredentials(username.getText().toString(), password.getText().toString());
}
}
一、View层和presenter的交互:
View到presenter的调用(View--->presenter):
上述代码,当用户点击按钮的时候,会执行一个账号和密码验证的业务逻辑。这个业务逻辑是封装在presenter中的。我们调用presenter的validateCredentials方法,传递参数,就可以执行账号和密码验证的业务逻辑。
将业务逻辑封装到presenter层的好处是,我们可以在任何地方重用一个业务逻辑。比如,这个validateCredentials的业务逻辑,就可以被重用。
presenter到View的调用(presenter--->view):
在实例化presenter的时候,要提供一个LoginView的实现。
public LoginPresenterImpl(LoginView loginView) {
this.loginView = loginView;
this.loginInteractor = new LoginInteractorImpl();
}
然后,LoginView接口定义了各种行为。presenter通过调用LoginView提供的行为,来实现presenter对View的控制。
在这里,进行验证的时候,会有不同的情况,针对不同的情况,presenter层会调用LoginView中不同的方法,来告知用户当前的验证结果。
如下:
@Override public void onUsernameError() {
loginView.setUsernameError();
loginView.hideProgress();
}
@Override public void onPasswordError() {
loginView.setPasswordError();
loginView.hideProgress();
}
@Override public void onSuccess() {
loginView.navigateToHome();
}
1).presenter层的业务逻辑实现:
Presenter层只有一个业务逻辑,它由接口LoginPresenter接口声明:
public interface LoginPresenter {
public void validateCredentials(String username, String password);
}
public class LoginPresenterImpl implements LoginPresenter, OnLoginFinishedListener {
private LoginView loginView;
private LoginInteractor loginInteractor;
public LoginPresenterImpl(LoginView loginView) {
this.loginView = loginView;
this.loginInteractor = new LoginInteractorImpl();
}
@Override public void validateCredentials(String username, String password) {
loginView.showProgress();
loginInteractor.login(username, password, this);
}
@Override public void onUsernameError() {
loginView.setUsernameError();
loginView.hideProgress();
}
@Override public void onPasswordError() {
loginView.setPasswordError();
loginView.hideProgress();
}
@Override public void onSuccess() {
loginView.navigateToHome();
}
}
它的业务逻辑实现是由成员loginInterator来做的。
然后,loginInterator要将判断结果通知LoginPresenterImpl,它通过调用OnLoginFinishedListener的接口中的方法。LoginPresenterImpl实现了OnLoginFinishedListener接口。
通信由LoginInteratorImpl到LoginPresenterImpl(LoginInteratorImpl--->LoginPresenterImpl):
OnLoginFinishedListener接口,定义了LoginPresenterImpl可以被LoginInteratorImpl调用的行为,用来告知LoginPresenterImpl验证的结果。
public interface OnLoginFinishedListener {
public void onUsernameError();
public void onPasswordError();
public void onSuccess();
}
public class LoginInteractorImpl implements LoginInteractor {
@Override
public void login(final String username, final String password, final OnLoginFinishedListener listener) {
// Mock login. I‘m creating a handler to delay the answer a couple of seconds
new Handler().postDelayed(new Runnable() {
@Override public void run() {
boolean error = false;
if (TextUtils.isEmpty(username)){
listener.onUsernameError();
error = true;
}
if (TextUtils.isEmpty(password)){
listener.onPasswordError();
error = true;
}
if (!error){
listener.onSuccess();
}
}
}, 2000);
}
}
通信由LoginPresenterImpl到LoginInteratorImpl(LoginPresenterImpl--->LoginInteratorImpl):
@Override public void validateCredentials(String username, String password) {
loginView.showProgress();
loginInteractor.login(username, password, this);
}
二、View层:
当前的Activity实现了LoginView接口,那么当前Activity是是LoginView,作为View层。
它定义了供presenter调用的行为。
public interface LoginView {
public void showProgress();
public void hideProgress();
public void setUsernameError();
public void setPasswordError();
public void navigateToHome();
}
---------------------------------------------------------------------
Main模块
一、View层:
public interface MainView {
public void showProgress();
public void hideProgress();
public void setItems(List<String> items);
public void showMessage(String message);
}
这些是供presenter层调用的方法。
这些方法中的代码是跟界面展示有关的。
View层到Presenter层的通信,及View层的实现:
public class MainActivity extends Activity implements MainView, AdapterView.OnItemClickListener {
private ListView listView;
private ProgressBar progressBar;
private MainPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.list);
listView.setOnItemClickListener(this);
progressBar = (ProgressBar) findViewById(R.id.progress);
presenter = new MainPresenterImpl(this);
}
@Override protected void onResume() {
super.onResume();
presenter.onResume();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override public void showProgress() {
progressBar.setVisibility(View.VISIBLE);
listView.setVisibility(View.INVISIBLE);
}
@Override public void hideProgress() {
progressBar.setVisibility(View.INVISIBLE);
listView.setVisibility(View.VISIBLE);
}
@Override public void setItems(List<String> items) {
listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items));
}
@Override public void showMessage(String message) {
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
@Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
presenter.onItemClicked(position);
}
}
红色部分是MainView的行为,都是界面展示方面的代码。
蓝色部分,是View层到Presenter通信的实现(View--->Presenter)。
二、Presenter层:
public interface MainPresenter {
public void onResume();
public void onItemClicked(int position);
}
它有两个业务逻辑要实现,一个是onResume(),一个是onItemClicked(int position)。
Presenter层到View层的通信,及Presenter层的实现:
public class MainPresenterImpl implements MainPresenter, OnFinishedListener {
private MainView mainView;
private FindItemsInteractor findItemsInteractor;
public MainPresenterImpl(MainView mainView) {
this.mainView = mainView;
findItemsInteractor = new FindItemsInteractorImpl();
}
@Override public void onResume() {
mainView.showProgress();
findItemsInteractor.findItems(this);
}
@Override public void onItemClicked(int position) {
mainView.showMessage(String.format("Position %d clicked", position + 1));
}
@Override public void onFinished(List<String> items) {
mainView.setItems(items);
mainView.hideProgress();
}
}
红色部分是Presenter层到View层的通信实现(Presenter--->View)。
onResume()方法和onItemClicked(int position)方法是Presenter实现的业务逻辑。
其中FindItemsInteractor成员,负责创建一个List的实现。
参考资料:
http://antonioleiva.com/mvp-android/