Android Mvp初探體驗
MVP的架構概念已經出現很長時間了,但是小的一直沒有實際的應用的項目中,最近找到了新工作,頭兒要求我們新項目必須採用mvp架構,並且要出一份架構設計文檔,所以小的趕緊研究起來,正好與大家一起分享。
轉載請註明出處,雖然也不會有人轉```
mvp已經出現很久相信大家其實已經對mvp有了一些瞭解,所以我也就不貼一些非常專業的但是一下子看不懂的圖了,mvp的原理其實用一句話概括的話就是:把所有的邏輯都放在presenter層裏。
傳統的mvc模式大家共同的認識基本上是xml佈局是v,activity是c,這就導致了activity非常的臃腫,有的比較複雜的activity設置多達上千,幾千行的也有,導致臃腫的原因,其實是xml佈局不能完全的滿足我們對佈局的需求,非常多的時候我都需要在activity寫邏輯的同時又要寫佈局相關的代碼。
然後大牛們發現了這個問題,咋解決呢,很簡單就是在拿出一個presenter層來專門處理邏輯,activity你不是沒事兒就愛弄弄佈局,擺弄擺弄控件嗎?自己玩去吧,so:
原來是:
我們以爲activity是c其實activity又是c又是v:
但是mvp被提出以後,直接暴露了activity的本質,activity你就是v,別在這裝了,我們找了帥小夥小p替代你,老老實實做的v吧,所以變成了這樣:
這篇亂碼七糟,瞎扯犢子博文寫到這兒相信各位懂的都當笑話看了,沒懂的還是沒懂,so,我還有代碼啊,哈哈,這你敢信。
我們用傳統的mvc的方式做一個,登錄頁面,有清空輸入框,有登陸然後本地做個延時模擬一下網絡連接,showtime:
這是佈局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context="com.ly.mvclogindemo.MainActivity">
<ProgressBar
android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:visibility="gone"
/>
<EditText
android:id="@+id/et_username"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="請輸入用戶名"
/>
<EditText
android:id="@+id/et_pass"
android:layout_width="match_parent"
android:layout_height="50dp"
android:hint="請輸入密碼"
/>
<Button
android:id="@+id/btn_login"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="登錄"
/>
<Button
android:id="@+id/btn_clear"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="清空"
/>
</LinearLayout>
so easy的一個佈局文件兩個輸入框倆按鈕一個progress,沒啥說的
下面是mvc的代碼:
package com.ly.mvclogindemo;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
EditText et_username,et_pass;
ProgressBar pbar;
Handler handler;
{
handler = new Handler();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init(){
et_username = (EditText) findViewById(R.id.et_username);
et_pass = (EditText) findViewById(R.id.et_pass);
pbar = (ProgressBar) findViewById(R.id.progress);
findViewById(R.id.btn_clear).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
et_username.setText("");
et_pass.setText("");
}
});
findViewById(R.id.btn_login).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
pbar.setVisibility(View.VISIBLE);
String user = et_username.getText()+"";
String pass = et_pass.getText()+"";
if (!TextUtils.isEmpty(user) && user.equals("ly") && !TextUtils.isEmpty(pass) && pass.equals("123")) {
handler.postDelayed(new Runnable() {
@Override
public void run() {
pbar.setVisibility(View.GONE);
Toast.makeText(MainActivity.this,"登錄成功",Toast.LENGTH_SHORT).show();
}
}, 1000);
}else{
handler.postDelayed(new Runnable() {
@Override
public void run() {
pbar.setVisibility(View.GONE);
Toast.makeText(MainActivity.this,"登錄失敗",Toast.LENGTH_SHORT).show();
}
},1000);
}
}
});
}
}
這麼簡單的一個頁面這麼簡單的邏輯和需求,相信很多同學都像我這樣寫一下就ok了,代碼習慣比較好的同學可能會多搞出幾個方法,做做優化基本也就那樣,最後就是做完就是一個xml一個activity可能還有一個userBean這裏我沒寫也沒貼,userbean大家都懂(getUserName(),setUserName(),全是這玩意),可以看出來代碼是稍微有點亂的,不排除我奔來寫的就亂,但是相信很多同學在面對非常簡單的需求的時候,在加上比較忙可能也會像我這樣寫一下。
然後來看mvp:
1,MVP的類會增加很多所以,我先貼一下目錄
可以看出來多了很多類,具體都多了哪些呢,LoginViewInter,LoginPresenterInter,ILoginPresenter,以Base開頭的類請大家自動無視一下3q。
我們逐個講解一下:
1.首先講解一下,我們發現多了好多接口,這些接口是幹什麼的,顯然我們希望用接口實現m,v,p各層之間的通信,或者說聯繫,這樣還不用暴露具體的實現。
2。LoginViewInter這個就是v的接口當然是由activity來實現它:
package com.ly.demo.view;
/**
* Created by txw_pc on 16/11/17.
*/
public interface LoginViewInter {
void clearUserAndPass();
void login();
void loginSucceed();
void loginFailed();
String getUsername();
String getPass();
}
非常簡單,定義了activity所有有關ui的可能出先的操作,但是也只限於有關ui的,那個login是指的點登陸按鈕時ui的變化```
實現了這個接口的activity:
package com.ly.demo;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.ly.demo.presenter.ILoginPersenter;
import com.ly.demo.view.LoginViewInter;
public class MainActivity extends BaseActivity implements LoginViewInter{
Button clearbtn,loginbtn;
EditText username_et,pass_et;
ProgressBar pbar;
ILoginPersenter iLoginPersenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
iLoginPersenter = new ILoginPersenter(this);
initView();
}
private void initView(){
clearbtn = (Button) findViewById(R.id.login_clear_btn);
loginbtn = (Button) findViewById(R.id.email_sign_in_button);
username_et = (EditText) findViewById(R.id.login_username_et);
pass_et = (EditText) findViewById(R.id.login_pass_et);
pbar = (ProgressBar) findViewById(R.id.login_progress);
clearbtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
iLoginPersenter.clear();
}
});
loginbtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
iLoginPersenter.login();
}
});
}
@Override
public void clearUserAndPass() {
username_et.setText("");
pass_et.setText("");
}
@Override
public void login() {
pbar.setVisibility(View.VISIBLE);
}
@Override
public void loginSucceed() {
pbar.setVisibility(View.GONE);
Toast.makeText(this, "登錄成功", Toast.LENGTH_SHORT).show();
}
@Override
public void loginFailed() {
pbar.setVisibility(View.GONE);
Toast.makeText(this, "登錄失敗", Toast.LENGTH_SHORT).show();
}
@Override
public String getUsername() {
return username_et.getText()+"";
}
@Override
public String getPass() {
return pass_et.getText()+"";
}
}
可以看出來感覺這個類變長了```但是也能感覺出來一下子就變的簡單清晰了(沒錯mvc寫那麼亂就是爲了對比 嘿嘿),我覺得這個也是mvp這麼受推崇的原因之一就是可以讓比較新手的同學,專注於方法的實現,而不是其它亂碼七糟的東西
接着來搞這個LoginPresenterInter,有了之前的LoginViewInter這個應該就不難理解了,這個是presenter的接口,用來定義presenter會用到的邏輯,上代碼:
package com.ly.demo.presenter;
/**
* Created by txw_pc on 16/11/17.
*/
public interface LoginPresenterInter {
void login();
void clear();
}
簡單到變態```就一個登陸的邏輯和一個清除輸入框內容的邏輯簡直不知道該說啥 我擦
接着來看他的實現類ILoginPresenter
package com.ly.demo.presenter;
import android.os.Handler;
import android.text.TextUtils;
import com.ly.demo.view.LoginViewInter;
/**
* Created by ly on 16/11/17.
* login邏輯
*/
public class ILoginPersenter extends BasePresenter implements LoginPresenterInter {
User user;
private LoginViewInter loginViewInter;
private Handler handler;
{
handler = new Handler();
user = new UserBean;
}
public ILoginPersenter(LoginViewInter loginview) {
this.loginViewInter = loginview;
}
@Override
public void login() {
loginViewInter.login();
String user = loginViewInter.getUsername();
String pass = loginViewInter.getPass();
user.setUserName(user);
user.setPass(pass);
if (!TextUtils.isEmpty(user) && user.equals("ly") && !TextUtils.isEmpty(pass) && pass.equals("123")) {
handler.postDelayed(new Runnable() {
@Override
public void run() {
loginViewInter.loginSucceed();
}
}, 1000);
}else{
handler.postDelayed(new Runnable() {
@Override
public void run() {
loginViewInter.loginFailed();
}
},1000);
}
}
@Override
public void clear() {
user.setUserName("");
user.setPass("");
loginViewInter.clearUserAndPass();
}
}
可以看出來就是模擬了一下網絡 然後做了一下判斷,沒有了,看上去也很簡單。
代碼貼完了,總結一下,mvp的方式做出來的程序確實是,肯上去可讀性很好,而且很清晰,還可以幫助同學們專注於功能的開發上,避免邏輯和ui邏輯進行混雜。但是也有缺點,那就是會多出來很多的接口和類,而且用接口來回溝通的方式實話確實很不錯,但是也有弊端,我感覺這樣寫的比較多的時候很容易因爲來回改接口來回跳類而邏輯混亂(我感覺我會那樣```,畢竟腦袋有點笨),但是較大型的項目使用mvp就可以很好的進行約束了,同樣如果太小的項目也感覺沒有必要這樣搞,但是仁者見仁智者見智,說實話我自己寫了一次感覺還真是挺好的。