MVP 字母的含义
M:modle 提供数据 如:bean dao db net(网络请求接口)</br>
P: presenter 负责逻辑的处理 如:网络框架,网络请求数据
V:View 界面展示 如:Activity ,Adapter ,Fragment
Retrofit 使用步骤(依赖接口的形式)
使用Retrofit服务器最好返回的是一个code 和一个json串的形式,这样我们就能提前写Javabean,也能在Presenter模块进行抽取。
1.1 添加依赖
compile 'com.squareup.retrofit2:converter-gson:2.2.0'
1.2 创建Retrofit对象进行解析,代码如下
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constant.BASEURL)
.addConverterFactory(GsonConverterFactory.create())
.build();
MVP+Retrofit实战总结
外卖项目的梳理
登录模块
1 首先要创建一个basePresenter 在这个类中我们创建了Retrofit 对象和
CallBack 回调接口,代码如下:
public abstract class BasePresenter {
protected ResponseInfoApi responseInfoApi;
private HashMap<String, String> errorMap;
public BasePresenter() {
errorMap = new HashMap<>();
errorMap.put("1","此页数据没有更新");
errorMap.put("2","服务器忙");
errorMap.put("3","请求参数异常");
//创建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constant.BASEURL)
.addConverterFactory(GsonConverterFactory.create())
.build();
//指定Retrofit如何发送具体的请求
//请求方式 get post
//请求路径 url
//请求参数
//请求结果
responseInfoApi = retrofit.create(ResponseInfoApi.class);
}
//如何处理结果(2个方法回调方法)
//同步?httpUrlConnection
//异步?回调方法(成功,失败)
class CallBackAdapter implements Callback<ResponseInfo>{
@Override
public void onResponse(Call<ResponseInfo> call, Response<ResponseInfo> response) {
//获取服务器返回的结果
ResponseInfo body = response.body();
if (body.getCode().equals("0")){
//请求成功,data中的数据可用
String json = body.getData();
//json解析
parseJson(json);
}else{
//本次请求有异常,具体的异常类型获取出来
String errorMessage = errorMap.get(body.getCode());
//自定义一个运行时异常,让onFailure方法接收
onFailure(call,new RuntimeException(errorMessage));
}
}
@Override
public void onFailure(Call<ResponseInfo> call, Throwable t) {
if (t instanceof RuntimeException){
//onFailure方法自己调用
String message = t.getMessage();
//自定义一个如何显示异常方法
showErrorMessage(message);
}
//retrofit框架调用
showErrorMessage("服务器忙,请稍后重试");
}
}
//因为json串对于每一个页面的请求而言,结果都是有差异的,所以无法做具体的解析,抽象
protected abstract void parseJson(String json);
protected abstract void showErrorMessage(String message);
}
2 M模块我们 只进行了控件的初始化,按钮的点击事件,shareSDK的短信
我们创建登录 Presenter 对象,通过这个类对象中的方法,把我们的
username password phone 等传递到Presenter中,逻辑在Presenter 中进
行处理。代码如下:
public class LoginActivity extends BaseActivity {
private static final int GET_CODE_SUCCES = 100;//获取验证码成功
private static final int GET_CODE_FAIL = 101;//获取验证码失败
private static final int KEEP_TIME_MINS = 102;//保持时间递减的状态码
private static final int RESET_TIME = 103;//重置时间为60秒
private static final int SUBMIT_CODE_SUCCES = 104;//校验验证码成功
private static final int SUBMIT_CODE_FAIL = 105;//校验验证码失败
@InjectView(R.id.iv_user_back)
ImageView ivUserBack;
@InjectView(R.id.iv_user_password_login)
TextView ivUserPasswordLogin;
@InjectView(R.id.et_user_phone)
EditText etUserPhone;
@InjectView(R.id.tv_user_code)
TextView tvUserCode;
@InjectView(R.id.et_user_psd)
EditText etUserPsd;
@InjectView(R.id.et_user_code)
EditText etUserCode;
@InjectView(R.id.login)
TextView login;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case GET_CODE_SUCCES:
Toast.makeText(LoginActivity.this,"获取验证码成功",Toast.LENGTH_SHORT).show();
break;
case GET_CODE_FAIL:
Toast.makeText(LoginActivity.this,"获取验证码失败",Toast.LENGTH_SHORT).show();
break;
case SUBMIT_CODE_SUCCES:
Toast.makeText(LoginActivity.this,"校验验证码成功",Toast.LENGTH_SHORT).show();
//必须获取校验成功,才可以继续下一个发送请求做登录过程
login();
break;
case SUBMIT_CODE_FAIL:
Toast.makeText(LoginActivity.this,"校验验证码失败",Toast.LENGTH_SHORT).show();
break;
case KEEP_TIME_MINS:
tvUserCode.setText("稍后再发("+(time--)+")");
break;
case RESET_TIME:
tvUserCode.setText("重新发送");
time = 60;
break;
}
}
};
private void login() {
//电话
String phone = etUserPhone.getText().toString().trim();
//密码
String psd = etUserPsd.getText().toString().trim();
//验证码
String code = etUserCode.getText().toString().trim();
if(SMSUtil.isMobileNO(phone) && !TextUtils.isEmpty(psd) && !TextUtils.isEmpty(code)){
LoginPresenter loginPresenter = new LoginPresenter(this);
loginPresenter.getLoginData(phone,psd,phone,2);
}
}
// EVENT_SUBMIT_VERIFICATION_CODE
private EventHandler eventHandler = new EventHandler(){
@Override
public void afterEvent(int event, int result, Object o) {
//此方法是运行在子线程中的,所以不可以
if (result == SMSSDK.RESULT_COMPLETE){
//成功
if (event == SMSSDK.EVENT_GET_VERIFICATION_CODE){
//下发验证码短信成功后,才可以做验证码短信+手机号码校验过程
handler.sendEmptyMessage(GET_CODE_SUCCES);
}
if (event == SMSSDK.EVENT_SUBMIT_VERIFICATION_CODE){
//校验验证码成功
handler.sendEmptyMessage(SUBMIT_CODE_SUCCES);
}
}else{
//失败
if (event == SMSSDK.EVENT_GET_VERIFICATION_CODE){
//下发验证码短信成功后,才可以做验证码短信+手机号码校验过程
handler.sendEmptyMessage(GET_CODE_FAIL);
}
if (event == SMSSDK.EVENT_SUBMIT_VERIFICATION_CODE){
//校验验证码失败
handler.sendEmptyMessage(SUBMIT_CODE_FAIL);
}
}
//做某一个事件结果的监听
super.afterEvent(event, result, o);
}
};
private int time = 60;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
ButterKnife.inject(this);
//对下发验证码短信的事件结果进行监听
SMSSDK.registerEventHandler(eventHandler);
}
@OnClick({R.id.tv_user_code,R.id.login})
public void onClick(View view){
switch (view.getId()){
case R.id.tv_user_code:
//判断手机号是否为空,是否合法,如果满足以上条件,就需要发送验证码短信
sendCode();
break;
case R.id.login:
checkLogin();
break;
}
}
private void checkLogin() {
//电话
String phone = etUserPhone.getText().toString().trim();
//密码
String psd = etUserPsd.getText().toString().trim();
//验证码
String code = etUserCode.getText().toString().trim();
if(SMSUtil.isMobileNO(phone) && !TextUtils.isEmpty(psd) && !TextUtils.isEmpty(code)){
//手机号码和验证码,放再sharesdk平台校验过程
// SMSSDK.submitVerificationCode("86",phone,code);
login();
}
}
private void sendCode() {
String phone = etUserPhone.getText().toString().trim();
if(SMSUtil.isMobileNO(phone)){
//下发验证码短信(发送成功,失败 EventHandler --->afterEvent())
SMSSDK.getVerificationCode("86",phone, new
OnSendMessageHandler() {
@Override
public boolean onSendMessage(String country, String phone) {
return false;
}
});
//子线程进行倒计时
new Thread(){
@Override
public void run() {
//如果time的值大于0,则说明还有计数的时间
while(time>0){
try {
Thread.sleep(999);
} catch (InterruptedException e) {
e.printStackTrace();
}
//发送一条消息,用于减少time的时间
handler.sendEmptyMessage(KEEP_TIME_MINS);
}
//重新下发验证码短信
handler.sendEmptyMessage(RESET_TIME);
}
}.start();
}
}
}
3 Retrofit 在请求网络数据需要我们进行网络接口的编写
public interface ResponseInfoApi {
//请求方式 get post
//请求路径 url
//请求参数 key = value
//请求结果
//http://10.0.2.2:8080/TakeoutServiceVersion2/home?latitude=value&longitude=value发送get请求
@GET(Constant.LOGIN)
Call<ResponseInfo> getLoginInfo(@Query("username") String username,@Query("password")String password,
@Query("phone")String phone, @Query("type")int type);
}
总结:
1. 我们用Retrofit 网络请求框架,我们需要创建一个拼接url的接口
2. 如果多个界面复杂逻辑,我们要创建basepresenter,在里面创建Retrofit对
象,CallBack 回调,和数据解析的接口,错误信息接口(可选),让子类重写
后两个接口,进行数据的解析和异常时进行错误信息说明
3.在我们UI界面,只是做了初始化控件,点击事件,获取Editext的内容,
shareSDK短信验证码,和presenter链接是通过创建presenter对象的方式,通
过 对象调用方法,把我们获取的参数传递过去,在presenter的父类
basepresenter中我们已经通过retrofit.create()方法,创建了网络请求url接口对
象,通过这个对象,把我们UI界面传递过来的参数进行拼接生成的对象为A(A是
举例子),在通过其异步请求数据,A..enqueue(new CallBackAdapter()); 这样我
们就完成了短信验证+登录的双重操作
网友评论