MVP 字母的含義
M:modle 提供數(shù)據(jù) 如:bean dao db net(網(wǎng)絡請求接口)</br>
P: presenter 負責邏輯的處理 如:網(wǎng)絡框架,網(wǎng)絡請求數(shù)據(jù)
V:View 界面展示 如:Activity ,Adapter ,Fragment
Retrofit 使用步驟(依賴接口的形式)
使用Retrofit服務器最好返回的是一個code 和一個json串的形式,這樣我們就能提前寫Javabean,也能在Presenter模塊進行抽取。
1.1 添加依賴
compile 'com.squareup.retrofit2:converter-gson:2.2.0'
1.2 創(chuàng)建Retrofit對象進行解析,代碼如下
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constant.BASEURL)
.addConverterFactory(GsonConverterFactory.create())
.build();
MVP+Retrofit實戰(zhàn)總結
外賣項目的梳理
登錄模塊
1 首先要創(chuàng)建一個basePresenter 在這個類中我們創(chuàng)建了Retrofit 對象和
CallBack 回調接口,代碼如下:
public abstract class BasePresenter {
protected ResponseInfoApi responseInfoApi;
private HashMap<String, String> errorMap;
public BasePresenter() {
errorMap = new HashMap<>();
errorMap.put("1","此頁數(shù)據(jù)沒有更新");
errorMap.put("2","服務器忙");
errorMap.put("3","請求參數(shù)異常");
//創(chuàng)建Retrofit對象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constant.BASEURL)
.addConverterFactory(GsonConverterFactory.create())
.build();
//指定Retrofit如何發(fā)送具體的請求
//請求方式 get post
//請求路徑 url
//請求參數(shù)
//請求結果
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中的數(shù)據(jù)可用
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的短信
我們創(chuàng)建登錄 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;//保持時間遞減的狀態(tài)碼
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();
//必須獲取校驗成功,才可以繼續(xù)下一個發(fā)送請求做登錄過程
login();
break;
case SUBMIT_CODE_FAIL:
Toast.makeText(LoginActivity.this,"校驗驗證碼失敗",Toast.LENGTH_SHORT).show();
break;
case KEEP_TIME_MINS:
tvUserCode.setText("稍后再發(fā)("+(time--)+")");
break;
case RESET_TIME:
tvUserCode.setText("重新發(fā)送");
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){
//下發(fā)驗證碼短信成功后,才可以做驗證碼短信+手機號碼校驗過程
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){
//下發(fā)驗證碼短信成功后,才可以做驗證碼短信+手機號碼校驗過程
handler.sendEmptyMessage(GET_CODE_FAIL);
}
if (event == SMSSDK.EVENT_SUBMIT_VERIFICATION_CODE){
//校驗驗證碼失敗
handler.sendEmptyMessage(SUBMIT_CODE_FAIL);
}
}
//做某一個事件結果的監(jiān)聽
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);
//對下發(fā)驗證碼短信的事件結果進行監(jiān)聽
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:
//判斷手機號是否為空,是否合法,如果滿足以上條件,就需要發(fā)送驗證碼短信
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)){
//下發(fā)驗證碼短信(發(fā)送成功,失敗 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,則說明還有計數(shù)的時間
while(time>0){
try {
Thread.sleep(999);
} catch (InterruptedException e) {
e.printStackTrace();
}
//發(fā)送一條消息,用于減少time的時間
handler.sendEmptyMessage(KEEP_TIME_MINS);
}
//重新下發(fā)驗證碼短信
handler.sendEmptyMessage(RESET_TIME);
}
}.start();
}
}
}
3 Retrofit 在請求網(wǎng)絡數(shù)據(jù)需要我們進行網(wǎng)絡接口的編寫
public interface ResponseInfoApi {
//請求方式 get post
//請求路徑 url
//請求參數(shù) key = value
//請求結果
//http://10.0.2.2:8080/TakeoutServiceVersion2/home?latitude=value&longitude=value發(fā)送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 網(wǎng)絡請求框架,我們需要創(chuàng)建一個拼接url的接口
2. 如果多個界面復雜邏輯,我們要創(chuàng)建basepresenter,在里面創(chuàng)建Retrofit對
象,CallBack 回調,和數(shù)據(jù)解析的接口,錯誤信息接口(可選),讓子類重寫
后兩個接口,進行數(shù)據(jù)的解析和異常時進行錯誤信息說明
3.在我們UI界面,只是做了初始化控件,點擊事件,獲取Editext的內容,
shareSDK短信驗證碼,和presenter鏈接是通過創(chuàng)建presenter對象的方式,通
過 對象調用方法,把我們獲取的參數(shù)傳遞過去,在presenter的父類
basepresenter中我們已經通過retrofit.create()方法,創(chuàng)建了網(wǎng)絡請求url接口對
象,通過這個對象,把我們UI界面?zhèn)鬟f過來的參數(shù)進行拼接生成的對象為A(A是
舉例子),在通過其異步請求數(shù)據(jù),A..enqueue(new CallBackAdapter()); 這樣我
們就完成了短信驗證+登錄的雙重操作