引言
本文承接上篇,在实现了简单登录后,本章更近一步,先实现UI效果,再将架构模式更改为 ==MVP #f44336==
正文
关于MVP模式,我推荐的是谷歌官方的例子android-architecture,这个库基本包含了所有的架构模式,是不错的入门和深入的教程。
需要注意的是,架构模式没有最好,只有最适合,不要盲目的追求架构而忽略了编码。本文所使用的MVP模式是最简单的一种模式,将来会在MVP的基础上,演变成为属于自己的MVP变种。
实现上章遗留的登陆UI
新建输入框背景
输入框的背景色太过于难看了,我们新建一个selector来写样式。
-
-
在xml中进行引用。
新建按钮背景
同上,新建一个selector作为登陆按钮的背景。
-
-
在布局中引用
效果
为了美观,增加了一些样式上的调整。
运行起来看看效果吧。
沉浸式
上面已经完成了页面的调整,但是剩余顶部的图片并没有沉浸到状态栏中,这效果并不是很好,所以引入一个开源库:
StatusBarUtil
相关介绍
依赖开源库
// 沉浸状态栏
implementation 'com.jaeger.statusbarutil:library:1.5.1'
在onCreate中的setContentView之后调用以下代码
StatusBarUtil.setTranslucentForImageView(this, null);
来看看效果吧。
MVP
好了,页面效果我们已经实现了,下一步就是开始更改代码结构为MVP模式了。
新建合约类
新建合约类,确定View层的接口和P层的抽象接口。
/**
* 登陆合约类
*/
public interface LoginContract {
interface View {
/**
* 登陆成功
*
* @param loginDto 成功回调的信息
*/
void loginSuccess(LoginDto loginDto);
/**
* 登陆失败
*
* @param message 失败消息
*/
void loginFailure(String message);
}
abstract class Presenter {
/**
* 持有View层
*/
protected View view;
public Presenter(View view) {
this.view = view;
}
/**
* 登陆
*
* @param userName 用户名
* @param password 密码
*/
public abstract void login(String userName, String password);
}
}
继承实现Presenter
创建LoginPresenter继承LoginContract.Presenter,将Activity中的请求部分代码转移到Presenter。
/**
* 登陆Presenter
*/
public class LoginPresenter extends LoginContract.Presenter {
private String TAG = "LoginPresenter";
/**
* 用户服务
*/
private UserService mUserService;
public LoginPresenter(LoginContract.View view) {
super(view);
// 日志拦截器,可以打印出所有的请求过程中的信息
// 如:请求体、参数、响应体等
HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor();
logInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.addInterceptor(logInterceptor);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://olrt5mymy.bkt.clouddn.com/")//请求url
//增加转换器,这一步能直接Json字符串转换为实体对象
.addConverterFactory(CustGsonConverterFactory.create())
//加入 RxJava转换器
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(builder.build())
.build();
mUserService = retrofit.create(UserService.class);
}
@Override
public void login(String userName, String password) {
// 开始请求
Subscriber subscriber = mUserService.login(userName, password)
.subscribeOn(Schedulers.io())//运行在io线程
.observeOn(AndroidSchedulers.mainThread())//回调在主线程
.subscribeWith(new ResourceSubscriber() {
@Override
public void onNext(LoginDto loginDto) {
//结果回调
Log.e(TAG, "onNext: " + loginDto);
if (loginDto.getCode() == 200) {
view.loginSuccess(loginDto);
} else {
view.loginFailure(loginDto.getMessage());
}
}
@Override
public void onError(Throwable t) {
Log.e(TAG, "onError: ");
view.loginFailure("登陆失败:" + t.getMessage());
}
@Override
public void onComplete() {
Log.e(TAG, "onComplete: ");
}
});
}
}
Activity中使用Presenter
将Activity中的请求代码网络请求代码移除,换成持有LoginPresenter进行登陆。
public class LoginActivity extends AppCompatActivity implements LoginContract.View {
private String TAG = "LoginActivity";
private LoginPresenter mLoginPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
mLoginPresenter = new LoginPresenter(this);
initEvent();
}
private void initEvent() {
//获取帐号输入框
final EditText etAccount = findViewById(R.id.et_account);
//获取密码输入框
final EditText etPassword = findViewById(R.id.et_pass);
//获取登录按钮 设置点击事件
findViewById(R.id.btn_login).setOnClickListener(new View.OnClickListener() {
@SuppressLint("CheckResult")
@Override
public void onClick(View v) {
//获取帐号
String account = etAccount.getText().toString();
//获取密码
String password = etPassword.getText().toString();
//登录
Toast.makeText(LoginActivity.this, "正在登陆", Toast.LENGTH_SHORT).show();
mLoginPresenter.login(account, password);
}
});
}
@Override
public void loginSuccess(LoginDto loginDto) {
Toast.makeText(this, "登陆成功:" + loginDto.toString(), Toast.LENGTH_SHORT).show();
}
@Override
public void loginFailure(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
}
可以看到,现在的代码结构非常的清晰明了,也不是那么臃肿冗余了,接下来运行起来看看效果吧。
登陆效果
最后
本章完成了 MVP 模式的迁移,但是我们挖的坑也越多了,敬请期待下篇:对Retrofit的封装!
本次源码