RxJAva OKHttp RetrofitAndroid开源框架Android知识

RxJava配合Retrofit实现网络封装

2016-11-24  本文已影响833人  情天孽海

那么呢,首先呢,我们呢,来记录一下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>>()),用泛型封装起来,主要是对泛型的知识还很欠缺,有更好的方法烦请告知

源码下载请点击这里

上一篇下一篇

猜你喜欢

热点阅读