編輯:關於Android編程
MVP(Model View Presenter)的設計模式是從MVC中演化而來的,主要作用是能夠:
劃分模塊職責,
降低模塊耦合
易測試,提高代碼復用
Model:數據:負責數據的檢索
View: 視圖:負責視圖的繪制,和用戶的交互
presenter: 控制器:負責在Model和View之間交互,負責兩者業務的邏輯處理
在MVC中,在Controller中,有View和Model的部分處理邏輯,在View處理時間的過程中,也有Model操作的過程,
該模式看起來模式簡單,層級關系不多,而且代碼量少,但是大部分邏輯都雜糅到了一起,
在測試和調試的過程中較之MVP而言很不方便
在MVC中,數據,控制器,視圖之間互相操作的關系是這樣的:
而在MVP中,presenter單線操作數據Model部分的數據,
同樣的presenter也是單線的操作視圖View模塊的東西,但是中間是是通過調用接口的方式,
當View界面和數據有交互的時候,再通過接口調用Presenter,再由Presenter調用Model來進行數據的改變
在MVP中,數據,控制器,視圖之間相互操作的關系是這樣的:
簡單的演示一個登陸操作的界面,用戶輸入用戶名密碼,然後模擬操作訪問服務器驗證用戶名密碼的操作,此過程顯示進度條,登陸成功之後顯示成功界面,失敗提示失敗信息
簡單的看一下界面:
activity_user_login.xml:
界面效果如下:
程序運行結果預覽:
界面寫好之後,開始分析該程序的數據和功能:
首先,需要有一個JavaBean對象User,保存username 和password字段
需要String類型的username和password
package com.jishihuitong.mvpdemo.bean; /** * Created by hss on 2016/8/2. */ public class User { private String username; private String password; public String getUsername() { return username; } public String getPassword() { return password; } public void setUsername(String username) { this.username = username; } public void setPassword(String password) { this.password = password; } }
然後根據視圖,肯定要有一個login的方法,在MVP中presenter操作model和view的過程都是使用接口的,所以要有一個IUserModel和UserModelImpl繼續完成
IUserModel類
package com.jishihuitong.mvpdemo.model; /** * Created by hss on 2016/8/2. */ public interface IUserModel { /** * 登錄數據模塊的操作 * @param username 用戶名 * @param password 密碼 * @param onLoginListener 登錄監聽 */ public void login(String username,String password,OnLoginListener onLoginListener); }
IUserModel實現類
package com.jishihuitong.mvpdemo.model; import com.jishihuitong.mvpdemo.bean.User; /** * Created by hss on 2016/8/2. */ public class UserModelImpl implements IUserModel { @Override public void login(final String username, final String password, final OnLoginListener onLoginListener) { new Thread(){ @Override public void run() { try { //模擬從網絡加載數據,需要時間 Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } if("username".equals(username) && "password".equals(password)){ User user = new User(); user.setUsername(username); user.setPassword(password); onLoginListener.loginSuccess(user); }else{ onLoginListener.loginFailed(); } } }.start(); } }
登錄成功或者失敗的監聽
package com.jishihuitong.mvpdemo.model; import com.jishihuitong.mvpdemo.bean.User; /** * Created by hss on 2016/8/2. */ public interface OnLoginListener { /** * 登錄成功 * @param user user對象 */ public void loginSuccess(User user); /** * 登錄失敗 */ public void loginFailed(); }
View層,上面說到,MVP設計模式中,調用View層的方法都是通過接口調用的,
所以我們需要顯示定義一個View的接口ILoginVeiw,在該接口中需要有什麼方法呢?
首先需要
getUsername();
getPassword();
清空輸入框內容的方法
clearUsername();
clearPassword();
登錄成功和登錄失敗的方法
toMainActivity(User user);
showFailedError();
顯示進度和隱藏進度的方法
showLoading();
hideLoading();
所以綜合上述表述,寫出來的ILoginView接口應該是這樣的:
package com.jishihuitong.mvpdemo.view;
import com.jishihuitong.mvpdemo.bean.User;
/**
* Created by hss on 2016/8/2.
*/
public interface IUserLoginView {
/**
* View層接口獲取用戶名的方法
* @return 輸入的用戶名
*/
public String getUserName();
/**
* View層接口獲取密碼的方法
* @return 輸入的密碼
*/
public String getPassword();
/**
* View層清除用戶名
*/
public void clearUserName();
/**
* View層清除密碼的方法
*/
public void clearPassword();
/**
* View層登錄成功的方法
* @param user user對象
*/
public void toMainActivity(User user);
/**
* View層顯示登錄失敗的方法
*/
public void showFailedError();
/**
* View層顯示進度條的方法
*/
public void showLoading();
/**
* View層隱藏進度條的方法
*/
public void hideLoading();
}
而加載布局的一個類顯然就是View層的了,該類要實現ILoginView接口,並且實現裡面的方法:
然後登錄操作,需要使用present來執行,
UserLoginActivity.java
package com.jishihuitong.mvpdemo.view;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.jishihuitong.mvpdemo.R;
import com.jishihuitong.mvpdemo.bean.User;
import com.jishihuitong.mvpdemo.presenter.UserLoginPresenter;
/**
* 登錄界面主activity IView的實現類,
*/
public class UserLoginActivity extends AppCompatActivity implements IUserLoginView {
private EditText id_et_username;
private EditText id_et_password;
private Button id_btn_login;
private Button id_btn_clear;
private UserLoginPresenter mUserLoginPrestener = new UserLoginPresenter(this);
private ProgressBar id_progressbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_login);
initView();
}
/**
* 初始化控件
*/
private void initView() {
id_et_username = (EditText) findViewById(R.id.id_et_username);
id_et_password = (EditText) findViewById(R.id.id_et_password);
id_btn_login = (Button) findViewById(R.id.id_btn_login);
id_btn_clear = (Button) findViewById(R.id.id_btn_clear);
id_progressbar = (ProgressBar) findViewById(R.id.id_progressbar);
id_btn_login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// presenter控制邏輯 登錄操作
mUserLoginPrestener.login();
}
});
id_btn_clear.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mUserLoginPrestener.clear();
}
});
}
@Override
public String getUserName() {
return id_et_username.getText().toString();
}
@Override
public String getPassword() {
return id_et_password.getText().toString();
}
@Override
public void clearUserName() {
id_et_username.setText("");
}
@Override
public void clearPassword() {
id_et_password.setText("");
}
@Override
public void toMainActivity(User user) {
Toast.makeText(getApplicationContext(),getUserName()+"登錄成功",Toast.LENGTH_SHORT).show();
}
@Override
public void showFailedError() {
Toast.makeText(getApplicationContext(),getUserName()+"登錄失敗",Toast.LENGTH_SHORT).show();
}
@Override
public void showLoading() {
id_progressbar.setVisibility(View.VISIBLE);
}
@Override
public void hideLoading() {
id_progressbar.setVisibility(View.INVISIBLE);
}
}
UserLoginPresenter.java
package com.jishihuitong.mvpdemo.presenter;
import android.os.Handler;
import com.jishihuitong.mvpdemo.bean.User;
import com.jishihuitong.mvpdemo.model.IUserModel;
import com.jishihuitong.mvpdemo.model.OnLoginListener;
import com.jishihuitong.mvpdemo.model.UserModelImpl;
import com.jishihuitong.mvpdemo.view.IUserLoginView;
/**
* Created by hss on 2016/8/2.
*/
public class UserLoginPresenter {
private IUserModel userModel;
private IUserLoginView userLoginView;
private Handler mHandler = new Handler() {
};
public UserLoginPresenter(IUserLoginView userLoginView) {
this.userModel = new UserModelImpl();
this.userLoginView = userLoginView;
}
/**
* 登錄操作
*/
public void login() {
// 設置進度條可見
userLoginView.showLoading();
//數據控制器控制model操作登錄
userModel.login(userLoginView.getUserName(), userLoginView.getPassword(), new OnLoginListener() {
@Override
public void loginSuccess(final User user) {
//需要在UI線程執行
mHandler.post(new Runnable() {
@Override
public void run() {
userLoginView.toMainActivity(user);
userLoginView.hideLoading();
}
});
}
@Override
public void loginFailed() {
//需要在UI線程執行
mHandler.post(new Runnable() {
@Override
public void run() {
userLoginView.showFailedError();
userLoginView.hideLoading();
}
});
}
});
}
/**
* 清除所有數據的方法
*/
public void clear() {
userLoginView.clearPassword();
userLoginView.clearUserName();
}
}
總體來說,雖然說代碼的層次增加了,代碼量也增加了,但是仔細看看,是不是代碼感覺特別明朗,層次感特別清晰呢,該模式主要適用於數據和view交互比較多的模塊
點擊下載代碼
通過上一節的分析,我們發現InputDispatcherThread使用InputChannel的sendMessage方法發送了一條消息,但是我們不知道誰在接收這條消息
每一個build.gradle文件代表一個project,一個project會有多個tasks如Android工程:包含Android tasks,build tasks
傳統界面的布局方式總是行列分明、坐落有序的,這種布局已是司空見慣,在不知不覺中大家都已經對它產生了審美疲勞。這個時候瀑布流布局的出現,就給人帶來了耳目一新的感覺,這種布局
本文為大家分享了Android實現拖動選擇按鈕的具體代碼,供大家參考,具體內容如下效果圖View代碼第一步:自定義屬性 <declare-styleable nam