MVC --> MVP :
將Activity的View和Controller雙重職責分離,Activity單純負責View邏輯,Presenter層處理Model和View層的交互邏輯,Model層處理數據邏輯。
換言之,MVP類似於MVC++,解決分離不徹底的問題。
同時MVP也有一些值得討論的地方:
- Presenter層與View層是通過接口進行交互,接口粒度控制存在問題。粒度小,接口量過大;粒度大,單一職能性不好。
- Presenter只是解決了功能分離的問題,複雜業務單個類代碼臃腫問題,仍需要分離多個Presenter - View處理同一個複雜頁面。
瑕不掩瑜,MVP仍然是很好的一套Android前端框架。
文件結構如下:
當然實際項目中不可能這樣分包,這裏只是單純MVP結構劃分的效果。
M、V、P 接口以及具體的實現
Model:這裏只有處理登錄邏輯。持有Presenter
package com.example.mvpdemo.model;
/**
* Model層 數據邏輯處理
*/
public interface IUserBiz {
void login(String username, String password);
}
package com.example.mvpdemo.model;
import com.example.mvpdemo.bean.UserBean;
import com.example.mvpdemo.presenter.ILoginPresenter;
/**
* Model層 具體的數據邏輯實現
*/
public class UserBiz implements IUserBiz {
private ILoginPresenter mPresenter;
public UserBiz(ILoginPresenter mPresenter) {
this.mPresenter = mPresenter;
}
@Override
public void login(String username, String password) {
// 假設進行了異步登錄
if ("fengz".equals(username) && "123456".equals(password)) {
// 持久化用戶信息
UserBean userBean = new UserBean();
userBean.setUsername(username);
userBean.setPassword(password);
mPresenter.loginSuccess(userBean);
} else {
mPresenter.loginFail("假設網絡異常吧!");
}
}
}
View:對應登錄邏輯,頁面的不同效果,以及獲取頁面數據。持有Presenter
package com.example.mvpdemo.view;
import com.example.mvpdemo.bean.UserBean;
/**
* View層 分離UI邏輯
*/
public interface ILoginView {
void toSuccessPage(UserBean user);
void showErrMessage(String message);
}
/**
* View層 處理ui邏輯
*/
public class MainActivity extends AppCompatActivity implements ILoginView {
private EditText mEtUsername;
private EditText mEtPassword;
private Button mBtnLogin;
private LoginPresenter mLoginPrinter = new LoginPresenter(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViews();
}
private void findViews() {
mEtUsername = (EditText) findViewById(R.id.editText2);
mEtPassword = (EditText) findViewById(R.id.editText);
mBtnLogin = (Button) findViewById(R.id.button);
mBtnLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mLoginPrinter.login(getUserName(), getPassword());
showLoading();
}
});
}
public String getUserName() {
return mEtUsername.getText().toString();
}
public String getPassword() {
return mEtPassword.getText().toString();
}
public void showLoading() {
Toast.makeText(this, "開始轉菊花", Toast.LENGTH_SHORT).show();
}
public void hideLoading() {
Toast.makeText(this, "結束轉菊花", Toast.LENGTH_SHORT).show();
}
@Override
public void toSuccessPage(UserBean userBean) {
hideLoading();
Toast.makeText(this, userBean.getUsername() + "跳轉去主頁面", Toast.LENGTH_SHORT).show();
}
@Override
public void showErrMessage(String message) {
hideLoading();
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
}
Presenter:同時持有View和Model,關心交互部分,完全無關邏輯。持有Model和View
package com.example.mvpdemo.presenter;
import com.example.mvpdemo.bean.UserBean;
/**
* 登錄Presenter接口,處理交互
*/
public interface ILoginPresenter {
void login(String name,String password);
void loginSuccess(UserBean user);
void loginFail(String errMsg);
}
package com.example.mvpdemo.presenter;
import com.example.mvpdemo.bean.UserBean;
import com.example.mvpdemo.model.IUserBiz;
import com.example.mvpdemo.model.UserBiz;
import com.example.mvpdemo.view.ILoginView;
/**
* Presenter層,同時持有View和Model,只關心交互,不涉及雙方邏輯
*/
public class LoginPresenter implements ILoginPresenter {
private IUserBiz mUserBiz;
private ILoginView mLoginView;
public LoginPresenter(ILoginView mLoginView) {
this.mLoginView = mLoginView;
this.mUserBiz = new UserBiz(this);
}
@Override
public void login(String name, String password) {
mUserBiz.login(name, password);
}
@Override
public void loginSuccess(UserBean user) {
mLoginView.toSuccessPage(user);
}
@Override
public void loginFail(String errMsg) {
mLoginView.showErrMessage(errMsg);
}
}
如上。MVP之外的所有東西都不包含,實現簡單的分層。