mvp菜鸟级入门教程
对于入门mvp的话,我觉得越简单越好,不应该是多复杂多高大上的东西,毕竟咱们搞技术的也都实在,mvp对于开发商业项目的开发很有帮助,我以前写的都是mvc的代码,写完之后很臃肿,同事见了痛苦不堪,mvp的好处就是能够实现代码分离,不会一个activity里面写成千上万代码,而且不好维护和扩展。
- 1
用mvc写的登录操作。
- 2
改造成mvp框架形式。
- 3
使用mock单元测试。
mvc样式
只是为了理解mvp,所以布局文件不贴了。
LoginActivity.java
/**
* Created by Gorills on 2017/1/15.
*/
public class LoginActivity extends Activity implements View.OnClickListener {
private final String TAG = LoginActivity.class.getSimpleName();
EditText usernameTextView, passwordTextView;
ProgressBar progressBar;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
initView();
}
private void initView() {
progressBar = (ProgressBar) findViewById(R.id.progress);
usernameTextView = (EditText) findViewById(R.id.username);
passwordTextView = (EditText) findViewById(R.id.password);
findViewById(R.id.button).setOnClickListener(this);
}
@Override
public void onClick(View view) {
String username = usernameTextView.getText().toString();
String password = passwordTextView.getText().toString();
if (username.isEmpty() || password.isEmpty()) {
Toast.makeText(LoginActivity.this, "用户名密码不能为空", Toast.LENGTH_SHORT).show();
} else if (username.length() < 8 || passwordTextView.length() < 9) {
usernameTextView.setError("账号至少8位,密码至少9位");
} else if (username.equals(MainActivity.USERNAME)) {
if (password.equals(MainActivity.PASSWORD)) {
// 登录成功,main拨打loginSuccess()电话通知主人登录成功了
startActivity(new Intent(LoginActivity.this, MainActivity.class));
} else {
// 登录失败,main拨打loginFailed()电话通知主人登录失败了,并告知失败原因
passwordTextView.setError("密码错误");
}
}
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
public static final String USERNAME = "username";
public static final String PASSWORD = "password";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
以上便是最简单的登录模块了,接下来我们改成使用mvp编写。
LoginActivity.java
**
* Created by Gorills on 2017/1/15.
*/
public class LoginActivity extends Activity implements LoginView, View.OnClickListener {
private final String TAG = LoginActivity.class.getSimpleName();
EditText usernameTextView, passwordTextView;
ProgressBar progressBar;
private LoginPresenter loginPresenter;//ctrl+alt+f转换为全局变量
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
initView();
loginPresenter = new LoginPresenter(this, new LoginService());
}
private void initView() {
progressBar = (ProgressBar) findViewById(R.id.progress);
usernameTextView = (EditText) findViewById(R.id.username);
passwordTextView = (EditText) findViewById(R.id.password);
findViewById(R.id.button).setOnClickListener(this);
}
@Override
public void onClick(View view) {
loginPresenter.performLoginClick();
}
@Override
public String getUsername() {
return usernameTextView.getText().toString();
}
@Override
public void showUsernameError(int username_error) {
usernameTextView.setError(getString(username_error));
}
@Override
public String getPassword() {
return passwordTextView.getText().toString();
}
@Override
public void showPasswordError(int password_error) {
passwordTextView.setError(getString(password_error));
}
@Override
public void startMainActivity() {
// 登录成功,main拨打loginSuccess()电话通知主人登录成功了
startActivity(new Intent(LoginActivity.this, MainActivity.class));
}
@Override
public void showProgress() {
progressBar.setVisibility(View.VISIBLE);
}
@Override
public void hideProgress() {
progressBar.setVisibility(View.GONE);
}
@Override
public void showLoginError(int login_failed) {
Toast.makeText(LoginActivity.this, getString(login_failed), Toast.LENGTH_SHORT).show();
}
}
LoginPresenter.java
**
* Created by Gorills on 2017/1/17.
*/
public class LoginPresenter {//ctrl+shift+t to create test
private final LoginView loginView;
private final LoginService loginService;
public LoginPresenter(LoginView loginView, LoginService loginService) {
this.loginView = loginView;
this.loginService = loginService;
}
public void performLoginClick() {
String username = loginView.getUsername();
if (username.isEmpty()) {
loginView.showUsernameError(R.string.username_error);
return;
}
String password = loginView.getPassword();
if (password.isEmpty()) {
loginView.showPasswordError(R.string.error_incorrect_password);
return;
}
loginView.showProgress();
boolean succeed = loginService.login(username, password);
loginView.hideProgress();
if (succeed) {
loginView.startMainActivity();
return;
} else {
loginView.showLoginError(R.string.login_failed);
return;
}
}
}
LoginService.java
/**
* Created by Gorills on 2017/1/17.
*/
public class LoginService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
public boolean login(String username, String password) {
if (username.equals(MainActivity.USERNAME) && password.equals(MainActivity.PASSWORD))
return true;
return false;
}
}
LoginView.java
/**
* Created by Gorills on 2017/1/17.
*/
public interface LoginView {
String getUsername();
void showUsernameError(int username_error);
String getPassword();
void showPasswordError(int password_error);
void startMainActivity();
void showProgress();
void hideProgress();
void showLoginError(int login_failed);
}
这样看起来虽然代码并没有减少,但是在LoginActivity里面看到的代码逻辑明显变清晰了,他只需要处理界面相关的代码,功能代码放在了Presenter里面。
使用Mockito对Demo进行测试
notes:因为以前很少用junit测试,所以在摸索中卡在了一个地方,我是参照youtube上的一个教程做的,检查了好几遍也没找到问题出在哪里。
Process finished with exit code 1
Class not found: “com.zzz.login.LoginPresenterTest”Empty test suite.后面才发现是在清单文件里面没有配置,我们需要在清单文件里面添加
import com.gorills.testmvp.R;
import junit.framework.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
/**
* Created by Administrator on 2017/1/18.
*/
@RunWith(MockitoJUnitRunner.class)
public class LoginPresenterTest {
@Mock
private LoginView loginView;
LoginPresenter loginPresenter;
@Before
public void setUp() throws Exception {
loginPresenter = new LoginPresenter(loginView);
}
@Test
public void showLoginErrorWhenPasswordEmpty() {
when(loginView.getUsername()).thenReturn("username");
when(loginView.getPassword()).thenReturn("");
loginPresenter.doLogin();
verify(loginView).showPasswordError(R.string.password_empty);
}
@Test
public void showLoginErrorWhenUsernameEmpty() {
when(loginView.getUsername()).thenReturn("");
loginPresenter.doLogin();
verify(loginView).showUsernameError(R.string.username_empty);
}
@org.junit.Test
public void testShowErrorWhenLoginError() throws Exception {
when(loginView.getUsername()).thenReturn("USERNAME");
when(loginView.getPassword()).thenReturn("PASSWORK");
loginPresenter.doLogin();
verify(loginView).showLoginError();
}
}
这里就算一个demo入门啦,当然mvp远不止这些后面还有很多,我在学习的途中会陆续贴出我的学习笔记供大家参考。写的不对麻烦指出,有疑问欢迎留言。