一步步搭建Retrofit+RxJava+MVP网络请求框架(一)
首先,展示一下封裝好之后的項目的層級結構。?
1、先創建一個RetrofitApiService.java
?
package com.xdw.retrofitrxmvpdemo.http;import com.xdw.retrofitrxmvpdemo.model.UserInfo;import retrofit2.http.GET; import retrofit2.http.Query; import rx.Observable;/*** Created by 夏德旺 on 2017/12/8.*/public interface RetrofitApiService {@GET("userinfo")Observable<UserInfo> getUserInfo(@Query("uid") int uid);}?
這里就是把原生的retrofit中的Call換成了RxJava中的Observable。
2、封裝RetrofitUtil
package com.xdw.retrofitrxmvpdemo.http;import android.content.Context;import com.google.gson.GsonBuilder; import com.xdw.retrofitrxmvpdemo.constant.UrlConstant;import okhttp3.OkHttpClient; import retrofit2.Retrofit; import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; import retrofit2.converter.gson.GsonConverterFactory;/*** Created by 夏德旺 on 2017/12/8.*/public class RetrofitUtil {private Context mCntext;//聲明Retrofit對象private Retrofit mRetrofit;//聲明RetrofitApiService對象private RetrofitApiService retrofitApiService;OkHttpClient client = new OkHttpClient();GsonConverterFactory factory = GsonConverterFactory.create(new GsonBuilder().create());//由于該對象會被頻繁調用,采用單例模式,下面是一種線程安全模式的單例寫法private volatile static RetrofitUtil instance;public static RetrofitUtil getInstance(Context context){if (instance == null) {synchronized (RetrofitUtil.class) {if (instance == null) {instance = new RetrofitUtil(context);}}}return instance;}private RetrofitUtil(Context mContext){mCntext = mContext;init();}//初始化Retrofitprivate void init() {mRetrofit = new Retrofit.Builder().baseUrl(UrlConstant.BASE_URL).client(client).addConverterFactory(factory).addCallAdapterFactory(RxJavaCallAdapterFactory.create()).build();retrofitApiService = mRetrofit.create(RetrofitApiService.class);}public RetrofitApiService getRetrofitApiService(){return retrofitApiService;} }?
3、封裝DataManager,這里和原生的retrofit的封裝一樣該類用來管理RetrofitApiService中對應的各種API接口,當做Retrofit和presenter中的橋梁,Activity就不用直接和retrofit打交道了
?
package com.xdw.retrofitrxmvpdemo.manager;import android.content.Context;import com.xdw.retrofitrxmvpdemo.http.RetrofitApiService; import com.xdw.retrofitrxmvpdemo.http.RetrofitUtil; import com.xdw.retrofitrxmvpdemo.model.UserInfo;import rx.Observable;/*** Created by 夏德旺 on 2017/12/8.*///該類用來管理RetrofitApiService中對應的各種API接口, // 當做Retrofit和presenter中的橋梁,Activity就不用直接和retrofit打交道了 public class DataManager {private RetrofitApiService mRetrofitService;private volatile static DataManager instance;private DataManager(Context context){this.mRetrofitService = RetrofitUtil.getInstance(context).getRetrofitApiService();}//由于該對象會被頻繁調用,采用單例模式,下面是一種線程安全模式的單例寫法public static DataManager getInstance(Context context) {if (instance == null) {synchronized (DataManager.class) {if (instance == null) {instance = new DataManager(context);}}}return instance;}//將retrofit的業務方法映射到DataManager中,以后統一用該類來調用業務方法//以后再retrofit中增加業務方法的時候,相應的這里也要添加,比如添加一個getOrderpublic Observable<UserInfo> getUserInfo(int uid){return mRetrofitService.getUserInfo(uid);} }?
4、創建一個Presenter接口,這里就引入了Presenter這個東西了,后面我們根據具體的業務創建對應的實例去實現該接口。該接口主要面向數據,后面還會創建一個PresentView接口(面向View的),然后通過
BindPresentView方法將這2個接口關聯起來,從而實現對數據和Activity的管理。
package com.xdw.retrofitrxmvpdemo.presenter;import com.xdw.retrofitrxmvpdemo.pv.PresentView;/*** Created by 夏德旺 on 2017/12/8.*/public interface Presenter {//Presenter初始化void onCreate();//銷毀void onDestroy();//綁定視圖void BindPresentView(PresentView presentView); }?
5、定義一個實現Presenter的基礎類BasePresenter,后續具體功能類繼承于它,主要是為了在該類中寫一些共用方法,比如
CompositeSubscription的創建與銷毀。(CompositeSubscription干嘛用的可以查閱RxJava的資料)
?
package com.xdw.retrofitrxmvpdemo.presenter;import com.xdw.retrofitrxmvpdemo.pv.PresentView;import rx.subscriptions.CompositeSubscription;/*** Created by 夏德旺 on 2017/12/8.*/ //定義一個Presenter的基礎類,后續具體功能類繼承于它 public class BasePresenter implements Presenter {//聲明一個CompositeSubscription對象,注意是protected修飾符,便于子類進行調用protected CompositeSubscription mCompositeSubscription;@Overridepublic void onCreate() {//在基礎類中對CompositeSubscription進行初始化,子類中就不用再寫一次//子類如果需要對onCreate進行重寫,記得先調用super.onCreate();mCompositeSubscription = new CompositeSubscription();}@Overridepublic void onDestroy() {//釋放CompositeSubscription,否則會造成內存泄漏if (mCompositeSubscription.hasSubscriptions()){mCompositeSubscription.unsubscribe();}}@Overridepublic void BindPresentView(PresentView presentView) {//與具體視圖進行綁定,留個子類進行擴展} }?
6、創建一個接口PresentView,面向視圖View的接口,和前面的Prenseter配合使用
?
package com.xdw.retrofitrxmvpdemo.pv;/*** Created by 夏德旺 on 2017/12/8.*///面向視圖View的接口,和前面的Prenseter配合使用 public interface PresentView {//定義一個最基礎的接口,里面就包含一個出錯信息的回調//因為大多數時候報錯的時候都是采用一條信息提示//如果需要負責的報錯接口,請重載onError,是重載不是重寫void onError(String result); }?
7、之前還已經創建了2個類,這里補充下,一個是UrlConstant(用來存放常量的,這里用來存放Base Url),另外一個是數據模型類UserInfo
?
UrlConstant.java:
?
package com.xdw.retrofitrxmvpdemo.constant;/*** Created by 夏德旺 on 2017/12/8.*/public class UrlConstant {/*** 域名:* 調試:http://10.1.1.192*/public static final String BASE_URL="http://10.1.1.192"; }?
UserInfo.java:
package com.xdw.retrofitrxmvpdemo.model;/*** Created by 夏德旺 on 2017/12/8.*/public class UserInfo {private String username;private int age;public UserInfo(String username, int age) {this.username = username;this.age = age;}public String getUsername() {return username;}public int getAge() {return age;}@Overridepublic String toString() {return "UserInfo{" +"username='" + username + '\'' +", age=" + age +'}';} }?
8、下面就需要將具體的業務加入到Presenter中了,先寫一個UserInfoPv繼承自PresentView接口,這個是根據具體業務添加。
?
package com.xdw.retrofitrxmvpdemo.pv;import com.xdw.retrofitrxmvpdemo.model.UserInfo;/*** Created by 夏德旺 on 2017/12/8.*/public interface UserInfoPv extends PresentView {//對基礎接口PresentView進行擴展,添加onSuccess回調//因為該回調與具體的業務對應,所以不能寫到基礎接口里面//比如UserInfo的回調就創建一個UserInfoPv的接口,如果新增一個Order的業務,//則新增一個OrderPv的接口void onSuccess(UserInfo userInfo); }?
9、寫一個UserInfoPresenter繼承BasePresenter類,在該類中實現數據的請求,并且將該類與業務對應的PresentView進行綁定,這里是和UserInfoPv綁定
?
package com.xdw.retrofitrxmvpdemo.presenter;import android.content.Context;import com.xdw.retrofitrxmvpdemo.manager.DataManager; import com.xdw.retrofitrxmvpdemo.model.UserInfo; import com.xdw.retrofitrxmvpdemo.pv.PresentView; import com.xdw.retrofitrxmvpdemo.pv.UserInfoPv;import rx.Observer; import rx.android.schedulers.AndroidSchedulers; import rx.schedulers.Schedulers;/*** Created by 夏德旺 on 2017/12/8.*///該類是具體業務presenter,如需增加另一個業務,比如Order //則可以再創建一個OrderPresenter public class UserInfoPresenter extends BasePresenter {private Context mContext;private UserInfoPv mUserInfoPv;private UserInfo mUserInfo;public UserInfoPresenter (Context context){this.mContext = context;}@Overridepublic void BindPresentView(PresentView presentView) {mUserInfoPv = (UserInfoPv)presentView;}//在presenter中實現業務邏輯,此處會調用前面封裝好的retrofit的東西//將處理結果綁定到對應的PresentView實例,這樣Activity和PresentView實例綁定好之后,//Activity->PresentView->Presenter->retrofit的關系就打通了public void getUserInfo(int uid){super.mCompositeSubscription.add(DataManager.getInstance(mContext).getUserInfo(uid).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<UserInfo>() {@Overridepublic void onCompleted() {if (mUserInfo != null){mUserInfoPv.onSuccess(mUserInfo);}}@Overridepublic void onError(Throwable e) {e.printStackTrace();mUserInfoPv.onError("請求失敗!!");}@Overridepublic void onNext(UserInfo userInfo) {mUserInfo = userInfo;}}));} }?
10、好了,retrofit與rxjava,presenter相關的東西都封裝好了,接下來輪到之前苦逼的Activity出場了,在Activity中展示presenter傳遞過來的數據。
?
package com.xdw.retrofitrxmvpdemo.activity;import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast;import com.xdw.retrofitrxmvpdemo.R; import com.xdw.retrofitrxmvpdemo.model.UserInfo; import com.xdw.retrofitrxmvpdemo.presenter.UserInfoPresenter; import com.xdw.retrofitrxmvpdemo.pv.UserInfoPv;public class MainActivity extends AppCompatActivity {private TextView text;private Button button;//定義需要調用的presenter對象private UserInfoPresenter mUserInfoPresenter =new UserInfoPresenter(this);@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);text = (TextView)findViewById(R.id.text);button = (Button)findViewById(R.id.button);//在Activity創建的時候同時初始化presenter,這里onCreater不是指的創建presenter對象,// 而是做一些presenter的初始化操作,名字應該取名init更好理解點,我這里就不重命名了mUserInfoPresenter.onCreate();//將presenter和PresentView進行綁定,實際上就是將presenter和Activity視圖綁定,//這個是MVP模式中V與P交互的關鍵mUserInfoPresenter.BindPresentView(mUserInfoPv);button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//點擊按鈕觸發presenter里面的方法mUserInfoPresenter.getUserInfo(1);}});}//采用內部類方法定義presentView對象,該對象用來將Activity和presenter進行綁定//綁定了以后主線程中就可以通過回調來獲取網絡請求的數據private UserInfoPv mUserInfoPv = new UserInfoPv(){@Overridepublic void onSuccess(UserInfo userInfo) {text.setText(userInfo.toString());}@Overridepublic void onError(String result) {Toast.makeText(MainActivity.this,result, Toast.LENGTH_SHORT).show();}};//在Activity銷毀的時候,一定要對CompositeSubscription進行釋放,否則會造成內存泄漏//釋放操作封裝到了presenter的ondestroy方法中@Overrideprotected void onDestroy(){super.onDestroy();mUserInfoPresenter.onDestroy();} }?
補充下:截圖中的Result這個類是我實際項目中用到的,這里簡化了下業務邏輯,就沒用到它。
Result.java:
?
package com.xdw.retrofitrxmvpdemo.model;/*** Created by 夏德旺 on 2017/12/8.*/public class Result<T> {private int code;private String msg;private T data;public Result(int code, String msg, T data) {this.code = code;this.msg = msg;this.data = data;}public int getCode() {return code;}public String getMsg() {return msg;}public T getData() {return data;}@Overridepublic String toString() {return "Result{" +"code=" + code +", msg='" + msg + '\'' +", data=" + data +'}';} }?
最后說明下,可能有的人覺得本來之前直接在Activity中寫retrofit很方便,現在卻加了這么多代碼,視乎變得更麻煩了。但是自己仔細想想設計模式,當業務變得越來越復雜的時候,這種封裝就會變得越來越有意義。
?
列舉下之后像該項目中擴展業務的步驟,比如加一個訂單功能。
操作步驟:
1、添加對應的model類Order
2、RetrofitApiService中添加對應的網絡請求api
3、將新添加的api映射到DataManager中
4、添加業務對應的PrensentView實例OrderPv
5、添加業務對應的Presenter實例OrderPresenter
6、在需要該業務的UI線程(Activity或Fragment)中調用具體業務對應的Presenter
看著新添加一個業務的過程是不是很多?但是邏輯很清晰,擴展很容易,寫代碼不是說代碼量越少,代表代碼寫的越好越有效率。
之后還會對該框架進一步封裝,加入攔截器,網絡請求等待框等功能的封裝。
?
補充下我這里測試用的服務端源碼,就一個index.php文件:
<?php header("Content-Type: application/json; charset=utf-8");$uid=$_GET['uid'];if($uid==1){$arr['code']=200;$arr['msg']='ok';$data['username']='xiadewang';$data['age']=30;$arr['userinfo']=$data;echo json_encode($data,JSON_UNESCAPED_UNICODE); }?
android代碼鏈接:http://download.csdn.net/download/aaaabbbb1019/10151399
總結
以上是生活随笔為你收集整理的一步步搭建Retrofit+RxJava+MVP网络请求框架(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PAT甲级 1031
- 下一篇: 排序算法之插入排序--Java语言