Android_MVP開發模式登入註冊案例
阿新 • • 發佈:2019-01-24
首先MVP 是從經典的MVC架構演變而來
系統C/S(Client/Server)三層架構模型:
1)檢視層(View):一般採用XML檔案對應用的介面進行描述,使用的時候可以直接引入,極為方便,可以的大大縮短開發時間,也可以使用JavaScript+HTML等的方式作為View層,當然這裡需要進行Java和JavaScript之間的通訊,幸運的是,Android提供了非常方便的通訊實現。業務邏輯層(BLL):它的關注點主要集中在業務規則的制定、業務流程的實現等與業務需求有關的系統設計,也即是說它是與系統所應對的領域(Domain)邏輯有關,很多時候,也將業務邏輯層稱為領域層。
2)控制層(Controller):Android的控制層的重任通常落在了眾多的Acitvity的肩上,這句話也就暗含了不要在Acitivity中寫程式碼,要通過Activity交割Model業務邏輯層處理。
3)模型層(Model):對資料庫的操作、以及其他和資料有關的的操作都應該在Model裡面處理,當然對業務計算等操作也是必須放在的該層的。就是應用程式中二進位制的資料。
三層結構架構三層間的互動及作用如下圖所示:
在MVP中View並不直接使用Model,它們之間的通訊是通過Presenter (MVC中的Controller)來進行的,所有的互動都發生在Presenter內部,而在MVC中View會從直接Model中讀取資料而不是通過 Controller。
在MVP裡,Presenter完全把Model和View進行了分離,主要的程式邏輯在Presenter裡實現。而且,Presenter與具體的View是沒有直接關聯的,而是通過介面進行互動,從而使得在變更View時候可以保持Presenter的不變,可以多次複用。
開始例項
一:佈局
1:登入頁面佈局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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"
tools:context="activity.example.com.mvpframework.view.MainActivity">
<EditText
android:id="@+id/ed_phone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="請輸入手機號"
android:layout_above="@+id/ed_pass"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="55dp" />
<EditText
android:id="@+id/ed_pass"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="請輸入密碼"
android:layout_above="@+id/btn_login"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="94dp" />
<Button
android:id="@+id/btn_login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="登入"
android:layout_marginLeft="65dp"
android:layout_marginStart="65dp"
android:layout_alignBaseline="@+id/btn_regis"
android:layout_alignBottom="@+id/btn_regis"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<Button
android:id="@+id/btn_regis"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="註冊"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginRight="43dp"
android:layout_marginEnd="43dp"
android:layout_marginBottom="130dp" />
</RelativeLayout>
2:註冊頁面佈局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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"
tools:context="activity.example.com.mvpframework.view.RegisActivity">
<EditText
android:id="@+id/ed_phone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="請輸入手機號"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="61dp" />
<EditText
android:id="@+id/ed_pass"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="請輸入密碼"
android:layout_marginBottom="63dp"
android:layout_above="@+id/btn_regis"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<Button
android:id="@+id/btn_regis"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="註冊"
android:layout_marginBottom="169dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginLeft="130dp"
android:layout_marginStart="130dp" />
</RelativeLayout>
3:登入成功跳轉的頁面,在此就不寫了
二:定義了兩個介面1:登入、註冊 成功或失敗的介面
public interface Login {
void succeed(String data);
void failed(String message);
}
2:請求網路成功或失敗的介面
public interface Http {
void onSuccess(String data);
void onFiled(String message);
}
三:M(model)層,提供資料,單例模式
public class HttpUtils {
private static volatile HttpUtils instance;
private HttpUtils(){
}
public static HttpUtils getInstance(){
if(instance==null){
synchronized (HttpUtils.class){
if(instance==null){
instance = new HttpUtils();
}
}
}
return instance;
}
public void get(String url, Map<String, String> map, final Http http) {
RequestParams params = new RequestParams(url);
for (Map.Entry<String, String> entry : map.entrySet()) {
params.addQueryStringParameter(entry.getKey(), entry.getValue());
}
x.http().get(params, new Callback.CommonCallback<String>() {
@Override
public void onSuccess(String result) {
http.onSuccess(result);
}
@Override
public void onError(Throwable ex, boolean isOnCallback) {
http.onFiled(ex.getMessage());
}
@Override
public void onCancelled(CancelledException cex) {
}
@Override
public void onFinished() {
}
});
}
}
四:P(Presenter)層,邏輯處理
public class LoginPresenter {
private Login login;
private Context context;
// 提供初始化IView物件的一個方法
public LoginPresenter() {
}
public LoginPresenter(Login login,Context context) {
this.login = login;
this.context=context;
}
public boolean checkData(String phone,String pass) {
if(TextUtils.isEmpty(phone)||TextUtils.isEmpty(pass)){
Toast.makeText(context,"使用者名稱或密碼不能為空",Toast.LENGTH_SHORT).show();
return false;
}
//驗證是否為手機號的正則表示式
String regex = "^1[3|4|5|7|8]\\d{9}";
if(!Pattern.matches(regex,phone)){
Toast.makeText(context,"手機號格式不正確",Toast.LENGTH_SHORT).show();
return false;
}
if(pass.length()<6){
Toast.makeText(context,"密碼長度需要大於6位",Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
public void login(String url,String username, String password) {
Map<String, String> map = new HashMap<>();
map.put("mobile", username);
map.put("password", password);
HttpUtils.getInstance().get(url, map,
new Http() {
@Override
public void onSuccess(String data) {
//解析
Gson gson = new Gson();
DataBean dataBean = gson.fromJson(data, DataBean.class);
//獲取code值,返回0為成功,1為失敗
if(dataBean.getCode().trim().equals("0")){
login.succeed(data);
Toast.makeText(context,dataBean.getMsg(),Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(context,dataBean.getMsg(),Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFiled(String message) {
login.failed(message);
}
});
}
//防止記憶體洩漏
public void detatch(){
if (login != null) {
login = null;
}
}
}
五:V(View)層,展示頁面,不做邏輯處理
1:MainActivity登入頁面
public class MainActivity extends AppCompatActivity implements Login,View.OnClickListener{
private EditText ed_phone;
private EditText ed_pass;
private Button btn_login;
private Button btn_regis;
private LoginPresenter presenter1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
//獲取id
ed_phone = (EditText)findViewById(R.id.ed_phone);
ed_pass = (EditText)findViewById(R.id.ed_pass);
btn_login = (Button)findViewById(R.id.btn_login);
btn_regis = (Button)findViewById(R.id.btn_regis);
//點選監聽
btn_login.setOnClickListener(this);
btn_regis.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.btn_login:
String user = ed_phone.getText().toString().trim();
String pass = ed_pass.getText().toString().trim();
//例項化p層
presenter1 = new LoginPresenter(this,MainActivity.this);
//效驗輸入的值是否符合格式
boolean b = presenter1.checkData(user, pass);
if(b){
presenter1.login("http://120.27.23.105/user/login",user,pass);
}
break;
case R.id.btn_regis:
//跳到註冊頁面
startActivity(new Intent(MainActivity.this,RegisActivity.class));
break;
}
}
@Override
public void succeed(String data) {
//登入成功跳到另一個頁面
startActivity(new Intent(MainActivity.this,ShopActivity.class));
}
@Override
public void failed(String message) {
//正常情況不會執行,只有請求網路失敗的時候才會執行,這裡的失敗是指網頁打不開的失敗
Toast.makeText(MainActivity.this,"網路異常,登入失敗",Toast.LENGTH_SHORT).show();
}
//防止記憶體洩漏
@Override
protected void onDestroy() {
super.onDestroy();
if (presenter1 != null) {
presenter1.detatch();
}
}
}
2:註冊頁面
public class RegisActivity extends AppCompatActivity implements Login,View.OnClickListener{
private EditText ed_phone;
private EditText ed_pass;
private Button btn_regis;
private LoginPresenter presenter1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_regis);
ed_phone = (EditText)findViewById(R.id.ed_phone);
ed_pass = (EditText)findViewById(R.id.ed_pass);
btn_regis = (Button)findViewById(R.id.btn_regis);
btn_regis.setOnClickListener(this);
}
@Override
public void onClick(View view) {
String user = ed_phone.getText().toString().trim();
String pass = ed_pass.getText().toString().trim();
presenter1 = new LoginPresenter(this,RegisActivity.this);
boolean b = presenter1.checkData(user, pass);
if(b){
presenter1.login("http://120.27.23.105/user/reg",user,pass);
}
}
@Override
public void succeed(String data) {
finish();
}
@Override
public void failed(String message) {
//正常情況不會執行,只有請求網路失敗的時候才會執行,這裡的失敗是指網頁打不開的失敗
Toast.makeText(RegisActivity.this,"網路異常,註冊失敗",Toast.LENGTH_SHORT).show();
}
//防止記憶體洩漏
@Override
protected void onDestroy() {
super.onDestroy();
if (presenter1 != null) {
presenter1.detatch();
}
}
}