RxJava配合Retrofit實現網絡封裝

cnbond 8年前發布 | 12K 次閱讀 Retrofit RxJava

那么呢,首先呢,我們呢,來記錄一下Android中比較火的兩種技術,火了大半壁江山的RxJava和壟斷了大部分的網絡請求Retrofit。這兩者的結合其實不需要太多的封裝,只要簡簡單單的搞兩下子基本就實現了常用的網絡框架了。

廢話不多說,代碼說明一切:

1、創建一個Android項目;

2、導入下面的依賴;

compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'
compile 'io.reactivex:rxjava:1.1.0'
compile 'io.reactivex:rxandroid:1.1.0'
compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'
compile 'com.google.code.gson:gson:2.6.2'

3、新建一個接口 NetService

public interface NetService  {    }

4、新建一個類 NetUtils

構造函數

private static final long DEFAULT_TIMEOUT = 8; //超時時間設置為8秒
private final String BASE_URL ="http://op.juhe.cn/onebox/";  //固定的網址 必須以‘/’結尾
private static NetUtils INSTANCE;
private final Retrofit retrofit;
public static NetService netService = null;

private NetUtils() {   
 OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();//創建一個OkHttp,如果不指定默認就是OkHttp
 httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);   
 retrofit = new Retrofit.Builder()
.client(httpClientBuilder.build())
.addConverterFactory(GsonConverterFactory.create()) //GSON數據解析器
.addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 
.baseUrl(BASE_URL) 
.build();    
netService = retrofit.create(NetService.class); 
}

我們可以看到這個構造函數是私有的,這里主要是想讓這個工具類是一個單例模式:接下來我們實現單例模式:

public static NetService getInstance() 
{    if (null == INSTANCE) { 
       INSTANCE = new NetUtils();    
}   
       return netService;
}

工具已經封裝好了,

接下來:看看NetService中的請求方法怎么寫:

一般的現在后臺返回的數據都是下面這個種格式的:

{

"error_code":"200",

"reason":"請求成功",

"result":"{ }"

}

JSON在線視圖查看器.png

前面是狀態和提示,通常我們只關心result里面的真實數據,所以這里寫個通用數據類BaseData

public class BaseData<T> {
    public T result;   
 public int status;   
 public String reason;   
 public T getResult() {  
      return result;  
  }   
 public void setResult(T result) { 
       this.result = result;  
  }   
 public int getStatus() {  
      return status;   
 }   
 public void setStatus(int status) { 
       this.status = status;   
 }    
public String getReason() { 
       return reason;   
 }    
public void setReason(String reason) { 
       this.reason = reason;   
 }
}

5、NetServer中的請求方法

@GET("news/query") //get請求 括號內為請求地址后綴
//@Query("key") @Query("q")  key 和q 查詢字段
Observable<BaseData<NewsData>> getNewsData(@Query("key") String key, @Query("q")String name);

為什么要用BaseData 主要是每次返回的error_code 和reason和result字段名永遠都是不變的,我們不需要再每個接受數據的實體中都寫重復的字段,這里以聚合數據中的新聞接口為例,簡單寫幾個接收字段;

public class NewsData {   
 private String title;    
private String content;  
 private String url;
}

當然set get方法你需要實現,我就不貼代碼了;

6、如何請求網絡

public void startRequest(View v){
    String key="";    //key我就不給你了,少年自己請求賬號吧
    String q="雙十一";   //雙十一關鍵字
 getNetService().getNewsData(key,q).
  subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(new Subscriber<BaseData<List<NewsData>>>() {
   @Override        
  public void onCompleted()
   {
   }       
   @Override       
   public void onError(Throwable e) { 
           Toast.makeText(NetUtilsActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();        
  }        
  @Override       
   public void onNext(BaseData<List<NewsData>> listBaseData) {
    result = listBaseData.getResult();           
   newsAdapter.notifyDataSetChanged();            
  Toast.makeText(NetUtilsActivity.this, result.get(0).getTitle(), Toast.LENGTH_SHORT).show();        
  }  
 });
}

手指輕輕那么一點,網絡請求立馬實現

那么是不是就結束了呢,不要著急,連進度框都沒有算什么網絡請求?所以呢,還需要進一步的優化!

7、建一個BaseSubscriber

public  abstract class BaseSubscriber<T> extends Subscriber<T> { 
   private Context mContext;  
  private ProgressDialog progressDialog;  
  public  BaseSubscriber(Context context)    {   
  mContext=context;      
  progressDialog = new ProgressDialog(mContext);   
     progressDialog.setMessage("正在加載數據,請稍后...");   
 }  
  @Override  
  public void onStart() {      
    super.onStart();       
  Log.d("BaseSubscriber", "onStart");       
   progressDialog.show();   
}  
  @Override    public  void onCompleted(){      
    progressDialog.dismiss();   
 }   
 @Override    
public void onError(Throwable e){  
     progressDialog.dismiss();       
     final AlertDialog.Builder builder=new AlertDialog.Builder(mContext);
     builder.setMessage(e.getMessage()).setPositiveButton("確定", 
     new DialogInterface.OnClickListener() {
            @Override            
            public void onClick(DialogInterface dialogInterface, int i) {
                builder.create().dismiss();           
       }      
   });      
    builder.show();    }   
 @Override    public abstract void onNext(T t);
}

onNext為抽象方法,主要是因為大部分時間我們并不需要關心onError()和onCompleted(),這樣保證了調用的Fragent和Acitivity的簡潔,如果真要處理錯誤只需要將onError重寫。

請求變成這樣了

getNetService().getNewsData(key, q).
 subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BaseSubscriber<BaseData<List<NewsData>>>(NetUtilsActivity.this) { 
           @Override            
      public void onNext(BaseData<List<NewsData>> newsDatas) { 
               result=newsDatas.getResult();               
               newsAdapter.notifyDataSetChanged();           
 }        
});

getNetService()是從BaseActivity來的:

public class BaseActivity extends AppCompatActivity {
   public NetService getNetService(){
        return NetUtils.getInstance();   
 }
}

但還是不完美,比如BaseSubscriber<BaseData<List<NewsData>>> 泛型太累贅,比如每次都要寫

subscribeOn(Schedulers.io())

.observeOn(AndroidSchedulers.mainThread())

.subscribe()這一串進行線程切換,這種固定的我們能不能寫成方法直接調用?

那么:

8、新建HttpResultFunc

public class HttpResultFunc<T> implements Func1<BaseData<T>, T> {
    @Override    
  public T call(BaseData<T> baseData) {
        if (baseData.geError_Code!=200) {           
   try {               
 throw new Exception(baseData.getReason());            
  } catch (Exception e) { 
               e.printStackTrace();            } 
       }      
return baseData.getResult();    }

該類的主要功能就是將不關心的數據過濾掉,如果error_code!=200,說明請求數據出錯了,此時通常result這樣的數據為null,只需要在activity或者Fragment中判斷數據是否為null;

修改后 map變形

getNetService().getNewsData(key, q)
.map(new HttpResultFunc<List<NewsData>>())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new BaseSubscriber<List<NewsData>>(NetUtilsActivity.this) {
            @Override            
    public void onNext(List<NewsData> newsDatas) {
                if(null!=newsDatas) {                    
                    result = newsDatas;                    
                    newsAdapter.notifyDataSetChanged();                
        }            
      }        
});

9、在NetUtils中加入:

public static  void toSubscribe(Observable o, Subscriber s) {
             o.subscribeOn(Schedulers.io()
            .unsubscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(s);}

這一樣我們就將固定的東西封裝起來了:

請求變成這樣了

NetUtils.toSubscribe(getNetService().getNewsData(key, q)
.map(new HttpResultFunc<List<NewsData>>()), 
new BaseSubscriber<List<NewsData>>(NetUtilsActivity.this) {
    @Override    public void onNext(List<NewsData> o) {
   if(null!=0){       
        result=o;        
        newsAdapter.notifyDataSetChanged(); 
        }   
    }  
});

但筆者沒有找到有個很好的方法把.map(new HttpResultFunc<List<NewsData>>()),用泛型封裝起來,主要是對泛型的知識還很欠缺。

來自:http://www.jianshu.com/p/d96be4123308

 

 本文由用戶 cnbond 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!