Android MVP架構搭建
阿新 • • 發佈:2018-12-16
一、 MVP概念
M : Model (資料層) 用於載入資料,
V:View(檢視層) 載入介面及檢視
P:Presenter(互動層) 進行邏輯操作
二、MVP的優點
1.Model層與View層完全分離( 不用擔心改需求了)
2.分工更加明確,邏輯更加清晰,易於維護程式碼
3.便於單元測試
其他……
三、例項(簡單的登入)
1.新建專案,建立如下的包及專案結構:
2.Bean包中包含兩個類,分別是User 和 LoginResult,程式碼如下:
public class LoginResult { public boolean success; public boolean nameErr; public boolean passwordErr; public String errMsg; public LoginResult(boolean success, boolean nameErr, boolean passwordErr, String errMsg) { this.success = success; this.nameErr = nameErr; this.passwordErr = passwordErr; this.errMsg = errMsg; } }
public class User { public User(String username, String password) { this.username = username; this.password = password; } public String username; public String password; }
3.Model層中,建立IUserModel介面,UserModel繼承該介面,並實現userLogin方法。
public interface IUserModel { void Login(User user , UserLoginCompleteListener listener); interface UserLoginCompleteListener{ void onUserLoginCompleted(LoginResult result); } }
import android.os.Handler; import android.shinetech.com.finalmvpdemo.Bean.LoginResult; import android.shinetech.com.finalmvpdemo.Bean.User; import android.text.TextUtils; public class UserModel implements IUserModel{ @Override public void Login( final User user, final UserLoginCompleteListener listener) { Handler handler = new Handler() ; handler.post(new Runnable() { @Override public void run() { LoginResult result = new LoginResult(true, false ,false,""); if(TextUtils.isEmpty(user.username) ){ result.success = false; result.nameErr = true; result.errMsg = "Username is empty"; } if(TextUtils.isEmpty(user.password) ){ result.success = false; result.passwordErr = true; result.errMsg = "Password is empty"; } listener.onUserLoginCompleted(result); } }); } }
4.Presenter層建立抽象類BasePresenter,並實現UserLoginPresenter.其中BasePresenter可以是所有Presenter的父類,該類中用WeakReference(弱引用)來減少記憶體洩漏的風險。
import java.lang.ref.WeakReference; public class BasePresenter<V> { WeakReference<V> weakReference; public void detachView(){ if(weakReference != null){ weakReference.clear(); } } public void attachView(V view){ weakReference = new WeakReference<V>((V)view); } public V getView(){ return weakReference.get(); } }
UserLoginPresenter類繼承自BasePresenter,並實現了ILoginView的介面,該介面包含了介面顯示的一些方法,如showProgressBar等。
import android.shinetech.com.finalmvpdemo.Bean.LoginResult; import android.shinetech.com.finalmvpdemo.Bean.User; import android.shinetech.com.finalmvpdemo.LoginActivity; import android.shinetech.com.finalmvpdemo.Model.IUserModel; import android.shinetech.com.finalmvpdemo.Model.UserModel; import android.shinetech.com.finalmvpdemo.View.ILoginView; import android.view.View; public class UserLoginPresenter extends BasePresenter<LoginActivity> implements ILoginView { IUserModel model = new UserModel(); public void login(User user) { showProgress(View.VISIBLE); model.Login(user, new IUserModel.UserLoginCompleteListener() { @Override public void onUserLoginCompleted(LoginResult result) { if (result.success) { showSuccess(); } else if (result.nameErr) { showNameError(); showError(result.errMsg); } else if (result.passwordErr) { showPasswordError(); showError(result.errMsg); } showProgress(View.INVISIBLE); } }); } @Override public void showNameError() { getView().showNameError(); } @Override public void showPasswordError() { getView().showPasswordError(); } @Override public void showProgress(int visiblity) { getView().showProgress(visiblity); } @Override public void showSuccess() { getView().showSuccess(); } @Override public void showError(String errMsg) { getView().showError(errMsg); } }
5.在View層,建立了BaseActivity,所有的Activity都可以繼承自此類,減少重複程式碼,並用泛型將presenter例項化推層到具體的介面層。
import android.os.Bundle; import android.shinetech.com.finalmvpdemo.Presenter.BasePresenter; import android.support.v7.app.AppCompatActivity; public abstract class BaseActivity<V, P extends BasePresenter> extends AppCompatActivity { protected BasePresenter p; protected abstract P createPresenter(); @Override protected void onCreate( Bundle savedInstanceState) { super.onCreate(savedInstanceState); p = createPresenter(); p.attachView((V)this); } }
public interface ILoginView { void showNameError(); void showPasswordError(); void showProgress(int visiblity); void showSuccess(); void showError(String errMsg); }
6.LoginActivity 此處為專案入口(通常是MainActivity),展示介面,並處理觸發的事件。
import android.os.Bundle; import android.shinetech.com.finalmvpdemo.Bean.User; import android.shinetech.com.finalmvpdemo.Presenter.UserLoginPresenter; import android.shinetech.com.finalmvpdemo.View.BaseActivity; import android.shinetech.com.finalmvpdemo.View.ILoginView; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.Toast; public class LoginActivity extends BaseActivity<LoginActivity, UserLoginPresenter > implements ILoginView { private ImageView err_username; private ImageView err_password; private Button btn_login; private EditText txt_username; private EditText txt_password; private ProgressBar progressBar; @Override protected UserLoginPresenter createPresenter() { return new UserLoginPresenter(); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); err_username = findViewById(R.id.err_username); err_password = findViewById(R.id.err_password); txt_username = findViewById(R.id.txtUsername); txt_password = findViewById(R.id.txtPassword); btn_login = findViewById(R.id.btn_login); progressBar = findViewById(R.id.progressBar); btn_login.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { User user = new User(txt_username.getText().toString(), txt_password.getText().toString()); ((UserLoginPresenter)p).login(user); } }); } @Override public void showNameError() { err_username.setVisibility(View.VISIBLE); } @Override public void showPasswordError() { err_password.setVisibility(View.VISIBLE); } @Override public void showProgress(int visiblity) { progressBar.setVisibility(visiblity); } @Override public void showSuccess() { err_username.setVisibility(View.INVISIBLE); err_password.setVisibility(View.INVISIBLE); progressBar.setVisibility(View.INVISIBLE); Toast.makeText(this, "Login success.",Toast.LENGTH_LONG).show(); } @Override public void showError(String errMsg) { Toast.makeText(this, errMsg,Toast.LENGTH_LONG).show(); } }
7.最後貼上activity_login.xml的layout程式碼 ,如下:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".LoginActivity"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Login" android:textAllCaps="false" android:textSize="40dp" android:layout_margin="10dp" android:textAlignment="center" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" android:id="@+id/lblTitle" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" app:layout_constraintTop_toBottomOf="@+id/lblTitle" android:id="@+id/line_username" > <TextView android:layout_weight="1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Username:" android:textAlignment="center" /> <EditText android:layout_weight="4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/txtUsername" /> <ImageView android:layout_width="20dp" android:layout_height="20dp" android:src="@mipmap/x" android:visibility="invisible" android:layout_gravity="center" android:id="@+id/err_username" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" app:layout_constraintTop_toBottomOf="@+id/line_username" android:id="@+id/line_password" > <TextView android:layout_weight="1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Password:" android:textAlignment="center" /> <EditText android:layout_weight="4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/txtPassword" /> <ImageView android:layout_width="20dp" android:layout_height="20dp" android:src="@mipmap/x" android:visibility="invisible" android:layout_gravity="center" android:id="@+id/err_password" /> </LinearLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintTop_toBottomOf="@+id/line_password" android:textAlignment="center" > <ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/progressBar" android:layout_toLeftOf="@+id/btn_login" android:visibility="gone" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btn_login" android:textAlignment="center" android:text="Login" android:layout_centerHorizontal="true" /> </RelativeLayout> </android.support.constraint.ConstraintLayout>