博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android--Retrofit+RxJava的简单封装(三)
阅读量:7279 次
发布时间:2019-06-30

本文共 19442 字,大约阅读时间需要 64 分钟。

1,继续接着上一篇的讲讲,话说如果像上一篇这样的话,那么我们每一次请求一个结构都要创建一堆的Retrofit对象,而且代码都是相同的,我们可以试试封装一下

先创建一个HttpMethods类,将Retrofit对象创建封装起来

HttpMethods.java

package com.qianmo.retrofitdemo.http;import com.qianmo.retrofitdemo.entry.MovieEntity;import java.util.concurrent.TimeUnit;import okhttp3.OkHttpClient;import retrofit2.Retrofit;import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;import retrofit2.converter.gson.GsonConverterFactory;import rx.Subscriber;import rx.android.schedulers.AndroidSchedulers;import rx.schedulers.Schedulers;/** * Created by wangjitao on 2016/11/3 0003. * 对Retrofit的的简单封装 */public class HttpMethods {    public static final String BASE_URL = "https://api.douban.com/v2/movie/";    private static final int DEFAULT_TIMEOUT = 5;    private Retrofit retrofit;    private MovieService movieService;    //先构造私有的构造方法    private HttpMethods() {        //手动创建一个OkHttpClient并设置超时时间        OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();        httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);        retrofit = new Retrofit.Builder()                .client(httpClientBuilder.build())                .addConverterFactory(GsonConverterFactory.create())                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())                .baseUrl(BASE_URL)                .build();        movieService = retrofit.create(MovieService.class);    }    //创建单例    public static class SingleonHolder {        private static final HttpMethods instance = new HttpMethods();    }    //获取单例    public static HttpMethods getInstance() {        return SingleonHolder.instance;    }    /**     *     * @param start 起始位置     * @param count 获取长度     * @param subscriber 传递过来的观察者对象     */    public void getTopMovie(int start, int count, Subscriber
subscriber) { movieService.getTopMovie(start, count) .subscribeOn(Schedulers.io()) .unsubscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(subscriber); }}

在直接在Activity中进行调用

package com.qianmo.retrofitdemo;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.widget.Button;import android.widget.TextView;import android.widget.Toast;import com.qianmo.retrofitdemo.entry.MovieEntity;import com.qianmo.retrofitdemo.http.HttpMethods;import com.qianmo.retrofitdemo.http.MovieService;import butterknife.Bind;import butterknife.ButterKnife;import butterknife.OnClick;import retrofit2.Call;import retrofit2.Callback;import retrofit2.Response;import retrofit2.Retrofit;import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;import retrofit2.converter.gson.GsonConverterFactory;import rx.Subscriber;import rx.android.schedulers.AndroidSchedulers;import rx.schedulers.Schedulers;public class MainActivity extends AppCompatActivity {    @Bind(R.id.tv_show)    TextView tvShow;    @Bind(R.id.btn_request)    Button btnRequest;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        ButterKnife.bind(this);    }    @OnClick({R.id.btn_request})    public void onClick(View view) {        switch (view.getId()) {            case R.id.btn_request:                getMovie();                break;        }    }    //请求网络数据    private void getMovie() {//        //https://api.douban.com/v2/movie/top250?start=0&count=10 目标地址//        String baseUrl = "https://api.douban.com/v2/movie/";////        //创建Retrofit对象//        Retrofit retrofit = new Retrofit.Builder()//                .baseUrl(baseUrl)//                .addConverterFactory(GsonConverterFactory.create())//                .build();////        MovieService movieService = retrofit.create(MovieService.class);//        Call
call = movieService.getTopMovie(0, 10);// call.enqueue(new Callback
() {// @Override// public void onResponse(Call
call, Response
response) {// tvShow.setText(response.body().getTitle());// }//// @Override// public void onFailure(Call
call, Throwable t) {// tvShow.setText(t.getMessage());// }// }); //第二种// String baseUrl = "https://api.douban.com/v2/movie/";//// Retrofit retrofit = new Retrofit.Builder()// .baseUrl(baseUrl)// .addConverterFactory(GsonConverterFactory.create())// .addCallAdapterFactory(RxJavaCallAdapterFactory.create())// .build();// MovieService movieService = retrofit.create(MovieService.class);//// movieService.getTopMovie(0, 10)// .subscribeOn(Schedulers.io())// .observeOn(AndroidSchedulers.mainThread())// .subscribe(new Subscriber
() {// @Override// public void onCompleted() {// Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();// }//// @Override// public void onError(Throwable e) {// tvShow.setText(e.getMessage());// }//// @Override// public void onNext(MovieEntity movieEntity) {// tvShow.setText(movieEntity.getTitle());// }// }); HttpMethods.getInstance().getTopMovie(0, 10, new Subscriber
() { @Override public void onCompleted() { Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show(); } @Override public void onError(Throwable e) { tvShow.setText(e.getMessage()); } @Override public void onNext(MovieEntity movieEntity) { tvShow.setText(movieEntity.getTitle()); } }); }}

但是现在存在一个问题,当存在相同格式的数据时候  我们应该怎么封装,一般来说我们后台返给我们的数据是这样的:

{ "resultCode": 0, "resultMessage": "成功", "data": {}}

 主要的数据是data,然后通过code来判断是否请求成功  由于data里面的数据是多变的 可以是一个对象也可以是一个数组 这时候我们需要创建一个HttpResult

package com.qianmo.retrofitdemo.http;/** * Created by Administrator on 2016/11/3 0003. */public class HttpResult
{ private int resultCode ; private String resultMessage ; private T data ;}

用过我们这次借口的同学都知道我们这次接口其实不是这样的,先来看看我们这次的数据结构吧

{    "count": 10,     "start": 0,     "total": 250,     "subjects": [],     "title": "豆瓣电影Top250"}

我们打算通过count的数量来判断请求是否成功,所以吧HttpResult类修改成下面

package com.qianmo.retrofitdemo.http;/** * Created by Administrator on 2016/11/3 0003. */public class HttpResult
{// 常用形式// private int resultCode ;// private String resultMessage ;//// private T data ; //本次接口的数据结构 private int count; private int start; private int total; private String title; //用来模仿Data private T subjects; public int getCount() { return count; } public void setCount(int count) { this.count = count; } public int getStart() { return start; } public void setStart(int start) { this.start = start; } public int getTotal() { return total; } public void setTotal(int total) { this.total = total; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public T getSubjects() { return subjects; } public void setSubjects(T subjects) { this.subjects = subjects; } @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append("title=" + title + " count=" + count + " start=" + start); if (null != subjects) { sb.append(" subjects:" + subjects.toString()); } return sb.toString(); }}

在正常服务器返回的数据下code=200或者code=0的时候是表示成功的,但是由于我们这次的接口没有这一块的内容,所以打算使用count字段来判断,当coun = 0的时候表示没有数据,请求失败,所以这里我们需要在HttpMethod类中添加一个判断的方法

/**     * 用来处理请求的code     * @param 
*/ private class HttpResultFunc
implements Func1
, T> { @Override public T call(HttpResult
tHttpResult) { if (tHttpResult.getCount() == 0) { throw new ApiException(100); } return tHttpResult.getSubjects(); } }

所以getMovie() 方法修改成了

/**     * 用于获取豆瓣电影Top250的数据     * @param subscriber  由调用者传过来的观察者对象     * @param start 起始位置     * @param count 获取长度     */    public void getTopMovie(Subscriber
> subscriber, int start, int count){ movieService.getTopMovie(start, count) .map(new HttpResultFunc
>()) .subscribeOn(Schedulers.io()) .unsubscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(subscriber);}

ok,在修改一下activity中的调用方法

HttpMethods.getInstance().getTopMovie(0, 10, new Subscriber
>() { @Override public void onCompleted() { Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show(); } @Override public void onError(Throwable e) { tvShow.setText(e.getMessage()); } @Override public void onNext(List
subjects) { StringBuffer sb = new StringBuffer(); for (Subject subject : subjects) { sb.append(subject.toString()); } tvShow.setText(sb); } });

让我们看一下效果:(截取的动态图又太大了!!上传不了)

 

 但是这也不是我们想要的最终结果,在请求数据的时候显示加载框,在请求完成的时候或者请求出错的时候影藏掉加载框,这样的话才算一个正常的网络请求框架。由于使用了RxJava,所以要创建一个类,继承与Subscriber,由于Subscriver对象中有四个方法,onStart、onNext、onError、onCompleted方法,我们需要在onStart中显示进度框,在onCompleted和onError中隐藏掉加载框,由于activity只关心最后的数据,所以我们需要写一个接口回调,将onNext方法中的数据传递给activity,让activity去处理逻辑。

SubscriberOnNextListenter.java

package com.qianmo.retrofitdemo.http;/** * Created by Administrator on 2016/11/3 0003. */public interface SubscriberOnNextListenter
{ void next(T t);}

ProgressSubscriber.java

package com.qianmo.retrofitdemo.http;import android.content.Context;import android.widget.Toast;import rx.Subscriber;/** * Created by wangjitao on 2016/11/3 0003. */public class ProgressSubscriber
extends Subscriber
{ private SubscriberOnNextListenter mSubscriberOnNextListenter; private Context context; public ProgressSubscriber(SubscriberOnNextListenter mSubscriberOnNextListenter, Context context) { this.mSubscriberOnNextListenter = mSubscriberOnNextListenter; this.context = context; } @Override public void onStart() { } @Override public void onCompleted() { Toast.makeText(context, "Get Top Movie Completed", Toast.LENGTH_SHORT).show(); } @Override public void onError(Throwable e) { Toast.makeText(context, "error:" + e.getMessage(), Toast.LENGTH_SHORT).show(); } @Override public void onNext(T t) { mSubscriberOnNextListenter.next(t); }}

再来修改一下我们activity调用的代码

package com.qianmo.retrofitdemo;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.widget.Button;import android.widget.TextView;import android.widget.Toast;import com.qianmo.retrofitdemo.entry.Subject;import com.qianmo.retrofitdemo.http.HttpMethods;import com.qianmo.retrofitdemo.http.ProgressSubscriber;import com.qianmo.retrofitdemo.http.SubscriberOnNextListenter;import java.util.List;import butterknife.Bind;import butterknife.ButterKnife;import butterknife.OnClick;import rx.Subscriber;public class MainActivity extends AppCompatActivity {    @Bind(R.id.tv_show)    TextView tvShow;    @Bind(R.id.btn_request)    Button btnRequest;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        ButterKnife.bind(this);    }    @OnClick({R.id.btn_request})    public void onClick(View view) {        switch (view.getId()) {            case R.id.btn_request:                getMovie();                break;        }    }    //请求网络数据    private void getMovie() {//        //https://api.douban.com/v2/movie/top250?start=0&count=10 目标地址//        String baseUrl = "https://api.douban.com/v2/movie/";////        //创建Retrofit对象//        Retrofit retrofit = new Retrofit.Builder()//                .baseUrl(baseUrl)//                .addConverterFactory(GsonConverterFactory.create())//                .build();////        MovieService movieService = retrofit.create(MovieService.class);//        Call
call = movieService.getTopMovie(0, 10);// call.enqueue(new Callback
() {// @Override// public void onResponse(Call
call, Response
response) {// tvShow.setText(response.body().getTitle());// }//// @Override// public void onFailure(Call
call, Throwable t) {// tvShow.setText(t.getMessage());// }// }); //第二种// String baseUrl = "https://api.douban.com/v2/movie/";//// Retrofit retrofit = new Retrofit.Builder()// .baseUrl(baseUrl)// .addConverterFactory(GsonConverterFactory.create())// .addCallAdapterFactory(RxJavaCallAdapterFactory.create())// .build();// MovieService movieService = retrofit.create(MovieService.class);//// movieService.getTopMovie(0, 10)// .subscribeOn(Schedulers.io())// .observeOn(AndroidSchedulers.mainThread())// .subscribe(new Subscriber
() {// @Override// public void onCompleted() {// Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();// }//// @Override// public void onError(Throwable e) {// tvShow.setText(e.getMessage());// }//// @Override// public void onNext(MovieEntity movieEntity) {// tvShow.setText(movieEntity.getTitle());// }// }); //第三种// HttpMethods.getInstance().getTopMovie(0, 10, new Subscriber
>() {// @Override// public void onCompleted() {// Toast.makeText(MainActivity.this, "Get Top Movie Completed", Toast.LENGTH_SHORT).show();// }//// @Override// public void onError(Throwable e) {// tvShow.setText(e.getMessage());// }//// @Override// public void onNext(List
subjects) {// StringBuffer sb = new StringBuffer();// for (Subject subject : subjects) {// sb.append(subject.toString());// }// tvShow.setText(sb);// }// }); SubscriberOnNextListenter subscriberOnNextListenter = new SubscriberOnNextListenter() { @Override public void next(Object o) { } }; //第四种 HttpMethods.getInstance() .getTopMovie(0, 10, new ProgressSubscriber
>( new SubscriberOnNextListenter
>() { @Override public void next(List
subjects) { StringBuffer sb = new StringBuffer(); for (Subject subject : subjects) { sb.append(subject.toString()); } tvShow.setText(sb); } }, MainActivity.this)); }}

再加上取消加载的接口和封装的progress就基本上完成了

package com.qianmo.retrofitdemo.http;public interface ProgressCancelListener {    void onCancelProgress();}

 

package com.qianmo.retrofitdemo.http;import android.app.ProgressDialog;import android.content.Context;import android.content.DialogInterface;import android.os.Handler;import android.os.Message;/** * Created by liukun on 16/3/10. */public class ProgressDialogHandler extends Handler {    public static final int SHOW_PROGRESS_DIALOG = 1;    public static final int DISMISS_PROGRESS_DIALOG = 2;    private ProgressDialog pd;    private Context context;    private boolean cancelable;    private ProgressCancelListener mProgressCancelListener;    public ProgressDialogHandler(Context context, ProgressCancelListener mProgressCancelListener,                                 boolean cancelable) {        super();        this.context = context;        this.mProgressCancelListener = mProgressCancelListener;        this.cancelable = cancelable;    }    private void initProgressDialog(){        if (pd == null) {            pd = new ProgressDialog(context);            pd.setCancelable(cancelable);            if (cancelable) {                pd.setOnCancelListener(new DialogInterface.OnCancelListener() {                    @Override                    public void onCancel(DialogInterface dialogInterface) {                        mProgressCancelListener.onCancelProgress();                    }                });            }            if (!pd.isShowing()) {                pd.show();            }        }    }    private void dismissProgressDialog(){        if (pd != null) {            pd.dismiss();            pd = null;        }    }    @Override    public void handleMessage(Message msg) {        switch (msg.what) {            case SHOW_PROGRESS_DIALOG:                initProgressDialog();                break;            case DISMISS_PROGRESS_DIALOG:                dismissProgressDialog();                break;        }    }}

progressSubscriber.java

package com.qianmo.retrofitdemo.http;import android.content.Context;import android.widget.Toast;import java.net.ConnectException;import java.net.SocketTimeoutException;import rx.Subscriber;/** * Created by wangjitao on 2016/11/3 0003. */public class ProgressSubscriber
extends Subscriber
implements ProgressCancelListener { private SubscriberOnNextListenter mSubscriberOnNextListenter; private ProgressDialogHandler mProgressDialogHandler; private Context context; public ProgressSubscriber(SubscriberOnNextListenter mSubscriberOnNextListenter, Context context) { this.mSubscriberOnNextListenter = mSubscriberOnNextListenter; this.context = context; mProgressDialogHandler = new ProgressDialogHandler(context, this, true); } /** * 在开始订阅的时候显示加载框 */ @Override public void onStart() { if (mProgressDialogHandler != null) { mProgressDialogHandler.obtainMessage(ProgressDialogHandler.SHOW_PROGRESS_DIALOG).sendToTarget(); } } /** * 在完成的时候进行影藏 */ @Override public void onCompleted() { Toast.makeText(context, "Get Top Movie Completed", Toast.LENGTH_SHORT).show(); dismissProgressDialog(); } /** * 在出错的时候也进行影藏 * * @param e */ @Override public void onError(Throwable e) { if (e instanceof SocketTimeoutException) { Toast.makeText(context, "网络中断,请检查您的网络状态", Toast.LENGTH_SHORT).show(); } else if (e instanceof ConnectException) { Toast.makeText(context, "网络中断,请检查您的网络状态", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(context, "error:" + e.getMessage(), Toast.LENGTH_SHORT).show(); } dismissProgressDialog(); } @Override public void onNext(T t) { mSubscriberOnNextListenter.next(t); } @Override public void onCancelProgress() { if (!this.isUnsubscribed()) { this.unsubscribe(); } } private void showProgressDialog() { if (mProgressDialogHandler != null) { mProgressDialogHandler.obtainMessage(ProgressDialogHandler.SHOW_PROGRESS_DIALOG).sendToTarget(); } } private void dismissProgressDialog() { if (mProgressDialogHandler != null) { mProgressDialogHandler.obtainMessage(ProgressDialogHandler.DISMISS_PROGRESS_DIALOG).sendToTarget(); mProgressDialogHandler = null; } }}

最后看一下效果

  

  

 

  

  

  

  

  

转载地址:http://pqhcm.baihongyu.com/

你可能感兴趣的文章
APICloud框架——总结一下最近开发APP遇到的一些问题 (二)
查看>>
python day04
查看>>
JVM的内存区域划分
查看>>
MySQL基础
查看>>
1595:Symmetry
查看>>
你应该知道的大数据领域12大动向
查看>>
R-CNN for Small Object Detection
查看>>
IF函数多个条件判断及嵌套
查看>>
代码搬移
查看>>
ajax请求code:200但是进入error函数
查看>>
软件图标显示不正常的问题
查看>>
Golang websocket
查看>>
关于编码:Unicode/UTF-8/UTF-16/UTF-32
查看>>
C++ OpenSSL 之三:生成CSR文件
查看>>
amaze ui响应式辅助
查看>>
C++getline使用
查看>>
Spinner使用二
查看>>
android 隐藏输入法键盘
查看>>
Android jni 中打印logcat日志
查看>>
SSL和keystore生成、导入等配置
查看>>