随着對Android開發的逐漸學習,自己的代碼量也越來越多,功能也越來越複雜,雖然盡量将一些方法封裝或者寫成單獨的根據類,但是一個項目下來自己的代碼還是太雜亂,太臃腫了。而且在多人開發的時候問題更加突出,是以我認為有必要給自己的項目一個合理的架構了,這次要介紹的是MVP模式在Android開發中的應用。
首先介紹一下MVP,其中M全稱呼Model,是整個APP中的資料來源,比如網絡請求類以及資料庫之類的;V指View,當然是指視圖了,在Android中一般為Avtivity及Fragment;P
全稱Presenter,負責處理Model提供的資料,友善View來顯示。這樣一來,整個APP的架構就非常清晰了,三個部分各司其職,這樣友善了代碼的維護和可讀性。
下面我們用MVP架構來實作一個登入功能
首先,我們要建立三個接口,它們是整個工程的MVP接口的父類,是以它隻包含最基本的方法
}
public interface MvpPresenter<V extends MvpView> {
//綁定View
public void attachView(V view);
//解除綁定
public void detachView();
}
public interface MvpModel {
}
可以看到,隻有MvpPresenter裡有兩個方法,它們用來綁定和解綁view,至于MvpView和MvpModel接口如果工程沒有什麼能夠抽象出來的方法就可以不寫
接下來為我們的登入子產品建立接口
public interface LoginView<M> extends MvpView {
//顯示加載中的視圖
public void showLoading(boolean pullToRefresh);
//顯示登入人資訊
public void showInformation(User user);
//登入失敗提示
public void loginFail(String err);
}
Presenter中需要根據不同的View和不同的Model來編寫邏輯代碼,是以這裡隻使用了一個抽象類來實作
public abstract class MvpBasePresenter<V extends MvpView> implements MvpPresenter<V>{
private V view;
@Override
public void attachView(V view) {
this.view = view;
Log.d("@@MVP:","view attached");
}
@Override
public void detachView() {
if (view !=null){
view = null;
Log.d("@@MVP:","view deattached");
}
}
}
}
然後就可以為我們的登入子產品編寫MVP的代碼了,這裡使用了一個User實體類和UserBiz登入工具類,還建立了一個登入狀态的回調接口OnLoginListener和登入方法接口UserLogin
public interface UserLogin {
public void login(String username, String password, OnLoginListener loginListener);
}
public interface OnLoginListener {
void loginSuccess(User user);
void loginFailed();
}
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;
}
}
public class UserBiz implements UserLogin {
@Override
public void login(final String username, final String password, final OnLoginListener loginListener) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (username.equals("327570221") && password.equals("123")) {
User user = new User();
user.setUsername(username);
user.setPassword(password);
loginListener.loginSuccess(user);
}else {
loginListener.loginFailed();
}
}
}).start();
}
}
下面是登入子產品的MVP代碼
Model層僅提供了登入方法
public class LoginModel extends MvpBaseModel {
Context mContext;
public LoginModel(Context mContext){
this.mContext=mContext;
}
public void Login(String name, String psd, OnLoginListener listener){
UserBiz userBiz=new UserBiz();
userBiz.login(name,psd,listener);
}
}
Presenter層負責調用Model層的登入方法并且根據結果改變UI狀态
public class LoginPresenter extends MvpBasePresenter {
private LoginModel loginModel;
Context mContext;
LoginView loginView;
Handler handler;
public LoginPresenter(Context mContext,LoginView v){
this.mContext=mContext;
loginModel=new LoginModel(mContext);
loginView= v;
handler=new Handler();
}
public void Login(String name, String psd){
loginView.showLoading(true);
loginModel.Login(name, psd, new OnLoginListener() {
@Override
public void loginSuccess(final User user) {
handler.post(new Runnable() {
@Override
public void run() {
loginView.showInformation(user);
loginView.showLoading(false);
}
});
Log.d("@@","登入成功");
}
@Override
public void loginFailed() {
handler.post(new Runnable() {
@Override
public void run() {
loginView.loginFail("登入失敗");
loginView.showLoading(false);
}
});
Log.d("@@","登入失敗");
}
});
}
}
BaseActivity在onCreat和onDestory時綁定和解綁Presenter
public abstract class BaseActivity<P extends MvpBasePresenter> extends AppCompatActivity implements MvpView {
P presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
presenter = bindPresenter();
Log.d("@@","onCreated");
//我的presenter中介我是不是管理View---關聯
if (presenter != null){
Log.d("@@","attachView");
presenter.attachView(this);
}
}
//具體的實作我不知道,我給别人實作
public abstract P bindPresenter();
@Override
protected void onDestroy() {
super.onDestroy();
Log.d("@@","onDestory");
//Activity銷毀的時候---解除綁定
if (presenter != null){
Log.d("@@","detachView");
presenter.detachView();
}
}
}
View層僅僅實作了改變View的方法,是不是很清爽
public class MvpLoginActivity extends BaseActivity implements LoginView{
EditText userName;
EditText passWord;
Button loginBtn;
TextView infoTv;
ProgressBar progressBar;
LoginPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mvp_login);
userName= (EditText) findViewById(R.id.editText);
passWord= (EditText) findViewById(R.id.editText2);
loginBtn= (Button) findViewById(R.id.login);
loginBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String name=userName.getText().toString();
String pass=passWord.getText().toString();
Log.d("@@mvpActivity",name+pass);
presenter.Login(name,pass);
}
});
infoTv= (TextView) findViewById(R.id.textView);
progressBar= (ProgressBar) findViewById(R.id.progressBar);
progressBar.setVisibility(View.GONE);
}
@Override
public MvpBasePresenter bindPresenter() {
presenter=new LoginPresenter(MvpLoginActivity.this,this);
return presenter;
}
@Override
public void showLoading(boolean pullToRefresh) {
if (pullToRefresh){
progressBar.setVisibility(View.VISIBLE);}
else {
progressBar.setVisibility(View.GONE);
}
}
@Override
public void showInformation(User user) {
String s=user.getUsername()+"\n"+user.getPassword();
infoTv.setText(s);
}
@Override
public void loginFail(String err) {
infoTv.setText(err);
}
}
這樣我們的demo就完成了,需要的可以下載下傳我的demo:點選打開連結