• Android--Retrofit+RxJava的简单封装(三)


    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<MovieEntity> 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<MovieEntity> call = movieService.getTopMovie(0, 10);
    //        call.enqueue(new Callback<MovieEntity>() {
    //            @Override
    //            public void onResponse(Call<MovieEntity> call, Response<MovieEntity> response) {
    //                tvShow.setText(response.body().getTitle());
    //            }
    //
    //            @Override
    //            public void onFailure(Call<MovieEntity> 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<MovieEntity>() {
    //                    @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<MovieEntity>() {
                @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<T> {
        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<T> {
    //    常用形式
    //    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 <T>
         */
        private class HttpResultFunc<T> implements Func1<HttpResult<T>, T> {
            @Override
            public T call(HttpResult<T> tHttpResult) {
                if (tHttpResult.getCount() == 0) {
                    throw new ApiException(100);
                }
                return tHttpResult.getSubjects();
            }
        }
    

    所以getMovie() 方法修改成了

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

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

    HttpMethods.getInstance().getTopMovie(0, 10, new Subscriber<List<Subject>>() {
                @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<Subject> 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<T> {
        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<T> extends Subscriber<T> {
    
        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<MovieEntity> call = movieService.getTopMovie(0, 10);
    //        call.enqueue(new Callback<MovieEntity>() {
    //            @Override
    //            public void onResponse(Call<MovieEntity> call, Response<MovieEntity> response) {
    //                tvShow.setText(response.body().getTitle());
    //            }
    //
    //            @Override
    //            public void onFailure(Call<MovieEntity> 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<MovieEntity>() {
    //                    @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<List<Subject>>() {
    //            @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<Subject> 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<List<Subject>>(
                            new SubscriberOnNextListenter<List<Subject>>() {
                                @Override
                                public void next(List<Subject> 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<T> extends Subscriber<T> 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;
            }
        }
    }
    

    最后看一下效果

      

      

     

      

      

      

      

      

  • 相关阅读:
    Web前端开发——HTML概述
    Web前端开发——概述
    [nowCoder] 两个不等长数组求第K大数
    [nowCoder] 两个长度相同有序数组的中位数
    [nowCoder] 完全二叉树结点数
    [nowCoder] 子数组最大乘积
    [nowCoder] 局部最小值位置
    [LeetCode] Binary Tree Right Side View
    [C/CPP系列知识] Type difference of character literals 和 bool in C and C++
    [C/CPP系列知识] C++中extern “C” name mangling -- Name Mangling and extern “C” in C++
  • 原文地址:https://www.cnblogs.com/wjtaigwh/p/6027301.html
Copyright © 2020-2023  润新知