zoukankan      html  css  js  c++  java
  • Android 基于Retrofit+Rxjava搭建的简单易用的网络架构

    装逼開始之前,为大家推荐两篇文章,用来更好的学习Retrofit和Rxjava。

    在这里我们要感谢互联网装逼行业勇于献身,甘于奉献的的大婶们。

    我仅代表个人,给您们跪舔了。

    Retrofit:Retrofit官网

    Rxjava:给 Android 开发人员的 RxJava 具体解释

    ---------------这是切割线---------------

    首先配置支持的gradle文件:

        compile 'io.reactivex:rxjava:1.1.3'
        compile 'io.reactivex:rxandroid:1.1.0'
        compile 'com.squareup.retrofit2:retrofit:2.0.1'
        compile 'com.squareup.retrofit2:converter-gson:2.0.1'
        compile 'com.squareup.retrofit2:adapter-rxjava:2.0.1'

    截止至本文发表前。上述支持库都是最新版本号。

    贴出Retrofit官网的GET请求演示样例:GitHubService接口

    public interface GitHubService {
      @GET("users/{user}/repos")
      Call<List<Repo>> listRepos(@Path("user") String user);
    }

    网络请求部分代码为:

            String baseUrl = "https://*******";
    
            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
    
            GitHubService service = retrofit.create(GitHubService.class);
            Call<List<XXXEntity>> repos = service.listRepos("octocat");
            repos.enqueue(new Callback<XXXEntity>() {
                @Override
                public void onResponse(Call<XXXEntity> call, Response<XXXEntity> response) {
                    Log.i("onResponse",response.body().toString());
                }
    
                @Override
                public void onFailure(Call<XXXEntity> call, Throwable t) {
                    Log.i("onResponse",t.getMessage());
                }
            });


    baseUrl 为网络请求地址

    addConverterFactory(GsonConverterFactory.create())为设置json解析方式为Gson。

    retrofit.create採用动态代理的方式获取GitHubService对象,并通过Callback获取返回的数据。

    ---------------当Retrofit与Rxjava相遇----------------


    Retrofit.Builder须要调用

    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
    方法,表示用Rxjava做回调。即Rxjava所讲的观察者模式。那么网络请求接口就须要改成例如以下方式:
    Observable<List<Repo>> listRepos(@Path("user") String user);
    网络请求部分的代码则更改为:

            String baseUrl = "https://*******";
    
            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
    
            service.listRepos("octocat")
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Subscriber<XXXEntity>() {
                        @Override
                        public void onCompleted() {
                            Log.i("onCompleted","onCompleted");
                        }
    
                        @Override
                        public void onError(Throwable e) {
                            Log.i("onError",e.toString());
                        }
    
                        @Override
                        public void onNext(XXXEntity movieEntity) {
                            Log.i("onCompleted",movieEntity.toString());
                        }
                    });
    假设细致阅读过上述两篇文章,不难理解这部分代码的含义。因为篇幅原因。这里就不在反复了。

    当然如此这般的结合,无法满足对代码有深度洁癖的骚年们。接下来。在此基础上,对代码做总体的封装。

    项目文件夹结构例如以下:


    首先封装网络请求类HTTPHelper.java

        /**
         * 这一部分配置常量,能够抽取出常量类
         */
        private static final String BASE_PATH = "http://www.weather.com.cn/";//訪问的地址
        private static final long DEFAULT_TIMEOUT = 5000;//默认超时时间(毫秒)
    
    
        private Retrofit mRetrofit;
        private INetService mNetService;
    
        private HTTPHelper(){
            OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder();
            okHttpClient.addInterceptor(new HTTPInterceptor());
            okHttpClient.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
            mRetrofit = new Retrofit.Builder()
                    .client(okHttpClient.build())
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .baseUrl(BASE_PATH)
                    .build();
    
            mNetService = mRetrofit.create(INetService.class);
    
        }
    
        /**
         * 单例控制器
         */
        private static class SingletonHolder{
            private static final HTTPHelper INSTANCE = new HTTPHelper();
        }
    
        /**
         * 获取单例对象
         * @return
         */
        public static HTTPHelper getInstance(){
            return SingletonHolder.INSTANCE;
        }
    我们须要将网络请求回来的字符串转换成javaBean对象,所以引入Rxjava的map转换机制。

    代码例如以下:

        private class HttpResultFunc<T> implements Func1<IModel, T> {
            @Override
            public T call(IModel iModel) {
                if (iModel == null){
                    try {
                        throw new Exception("result model is null");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                return (T)iModel;
            }
        }
    到此。配置阶段结束,以下将是Rxjava的异步订阅请求网络并返回操作。

    为了方便Activity、Fragment等界面处理数据。封装Subscriber接口:

    package demo.myframework.common;
    
    import rx.Subscriber;
    
    /**
     * @Author: lizhipeng
     * @Data: 16/4/12 下午4:17
     * @Description: 自己定义调阅者以及结果监听接口
     */
    public class ResultSubscriber<T> extends Subscriber<T> {
        private int mRequestType;
        private OnResultListener<T> mListener = null;
    
        /**
         * 自己定义订阅。參数用来区分网络接口。以用来在不同接口操作过程中。处理不同的逻辑
         * @param requestType
         */
        public ResultSubscriber(int requestType) {
            this.mRequestType = requestType;
            mListener = new OnResultListener<T>() {
                @Override
                public void onStart(int requestType) {
                }
                @Override
                public void onCompleted(int requestType) {
                }
                @Override
                public void onError(Throwable e, int requestType) {
                }
                @Override
                public void onNext(T t, int requestType) {
                }
            };
        }
    
        @Override
        public void onStart() {
            mListener.onStart(mRequestType);
        }
    
        @Override
        public void onCompleted() {
            mListener.onCompleted(mRequestType);
        }
    
        @Override
        public void onError(Throwable e) {
            if (e != null){
                mListener.onError(e,mRequestType);
            }
        }
    
        @Override
        public void onNext(T t) {
            mListener.onNext(t,mRequestType);
        }
    
        /**
         * 设置订阅监听器
         * @param listener
         */
        public void setOnResultListener(OnResultListener listener){
            if (listener != null){
                mListener = listener;
            }
        }
    
        /**
         * 订阅的监听器
         * @param <T>
         */
        public interface OnResultListener<T> {
            /**
             * 网络请求订阅開始
             */
            void onStart(int requestType);
            /**
             * 网络请求完毕
             */
            void onCompleted(int requestType);
            /**
             * 网络请求错误
             */
            void onError(Throwable e,int requestType);
            /**
             * 处理请求结果
             */
            void onNext(T t,int requestType);
        }
    }
    
    已天气訪问为例网络请求接口为:

    package demo.myframework.interfaces;
    
    import demo.myframework.model.WeatherModel;
    import retrofit2.http.GET;
    import retrofit2.http.Path;
    import rx.Observable;
    
    /**
     * @Author: lizhipeng
     * @Data: 16/4/12 下午2:57
     * @Description:  网络请求接口
     */
    public interface INetService {
        @GET("data/cityinfo/{city_id}.html")
        Observable<WeatherModel> getWeather(@Path("city_id") String city);
    }

    HTTPHelper.java 中 网络请求数据方法的实现为:

        /**
         * 获取网络数据的方法
         * @param cityId
         */
        public void getWeather(String cityId, int resultType, ResultSubscriber.OnResultListener listener){
            ResultSubscriber<IModel> subscriber = new ResultSubscriber<>(resultType);
            subscriber.setOnResultListener(listener);
            mNetService.getWeather(cityId)
                    .map(new HttpResultFunc<WeatherModel>())
                    .subscribeOn(Schedulers.io())
                    .unsubscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(subscriber);
        }
    MainActivity实现OnResultListener接口。点击button调用方法为

           HTTPHelper.getInstance().getWeather("101010300",CODE,MainActivity.this);
    一下是activity的所有代码:

    package demo.myframework.activity;
    
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;
    
    import demo.myframework.R;
    import demo.myframework.common.ResultSubscriber;
    import demo.myframework.http.HTTPHelper;
    import demo.myframework.model.IModel;
    import demo.myframework.model.WeatherModel;
    
    public class MainActivity extends AppCompatActivity implements ResultSubscriber.OnResultListener<IModel>{
        private static final String TAG = "MainActivity";
        private static final int CODE = 1;
    
        private Button mButton;
        private TextView mTextView;
    
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            initView();
            initData();
        }
    
        private void initData() {
            mButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Log.i(TAG,"onClick");
                    HTTPHelper.getInstance().getWeather("101010300",CODE,MainActivity.this);
                }
            });
        }
    
        private void initView() {
            mButton = (Button) findViewById(R.id.button);
            mTextView = (TextView) findViewById(R.id.textview);
        }
    
        private void setResultSubscriber(){
    
        }
    
        /**
         * 网络请求前调用,通常显示Progressialog
         * @param requestType
         */
        @Override
        public void onStart(int requestType) {
            Log.i(TAG,"onStart");
        }
    
        /**
         * 网络请求完毕调用,通常销毁Progressialog
         * @param requestType
         */
        @Override
        public void onCompleted(int requestType) {
            Log.i(TAG,"onCompleted");
        }
    
        /**
         * 网络请求错误后调用
         * @param e
         * @param requestType
         */
        @Override
        public void onError(Throwable e, int requestType) {
            Log.i(TAG,"onError");
        }
    
        /**
         * onNext 方法中处理请求下来的数据
         * @param iModel
         * @param requestType
         */
        @Override
        public void onNext(IModel iModel, int requestType) {
            Log.i(TAG,"onNext");
            if (requestType == CODE){
                mTextView.setText(((WeatherModel)iModel).getWeatherinfo().toString());
            }
        }
    }
    


    另为了方便測试联调,实现OKhttp的过滤接口。一下代码分别为过滤器和javaBean的实现:

    HTTPInterceptor.java

    package demo.myframework.http;
    
    import android.util.Log;
    
    import java.io.IOException;
    
    import okhttp3.Interceptor;
    import okhttp3.Request;
    import okhttp3.RequestBody;
    import okhttp3.Response;
    
    /**
     * @Author: lizhipeng
     * @Data: 16/4/12 下午5:19
     * @Description: 定义http拦截器,用于设置http协议和日志调试
     */
    public class HTTPInterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
            //封装headers
            Request request = chain.request().newBuilder()
                    .addHeader("Content-Type", "application/json") //加入请求头信息
                    .build();
    //        Headers headers = request.headers();
            String requestUrl = request.url().toString(); //获取请求url地址
            String methodStr = request.method(); //获取请求方式
            RequestBody body = request.body(); //获取请求body
            String bodyStr = (body==null?"":body.toString());
            //打印Request数据
            Log.i("HTTP-Interceptor","requestUrl=====>"+requestUrl);
            Log.i("HTTP-Interceptor","requestMethod=====>"+methodStr);
            Log.i("HTTP-Interceptor","requestBody=====>"+body);
    
            Response response = chain.proceed(request);
            return response;
        }
    }
    

    WeatherModel.java

    package demo.myframework.model;
    
    /**
     * @Author: lizhipeng
     * @Data: 16/4/12 下午3:16
     * @Description:  天气信息模板
     */
    public class WeatherModel implements IModel{
    
        /**
         * city : 朝阳
         * cityid : 101010300
         * temp1 : -2℃
         * temp2 : 16℃
         * weather : 晴
         * img1 : d0.gif
         * img2 : n0.gif
         * ptime : 18:00
         */
    
        private WeatherinfoBean weatherinfo;
    
        public WeatherinfoBean getWeatherinfo() {
            return weatherinfo;
        }
    
        public void setWeatherinfo(WeatherinfoBean weatherinfo) {
            this.weatherinfo = weatherinfo;
        }
    
        public static class WeatherinfoBean {
            private String city;
            private String cityid;
            private String temp1;
            private String temp2;
            private String weather;
            private String img1;
            private String img2;
            private String ptime;
    
            public String getCity() {
                return city;
            }
    
            public void setCity(String city) {
                this.city = city;
            }
    
            public String getCityid() {
                return cityid;
            }
    
            public void setCityid(String cityid) {
                this.cityid = cityid;
            }
    
            public String getTemp1() {
                return temp1;
            }
    
            public void setTemp1(String temp1) {
                this.temp1 = temp1;
            }
    
            public String getTemp2() {
                return temp2;
            }
    
            public void setTemp2(String temp2) {
                this.temp2 = temp2;
            }
    
            public String getWeather() {
                return weather;
            }
    
            public void setWeather(String weather) {
                this.weather = weather;
            }
    
            public String getImg1() {
                return img1;
            }
    
            public void setImg1(String img1) {
                this.img1 = img1;
            }
    
            public String getImg2() {
                return img2;
            }
    
            public void setImg2(String img2) {
                this.img2 = img2;
            }
    
            public String getPtime() {
                return ptime;
            }
    
            public void setPtime(String ptime) {
                this.ptime = ptime;
            }
    
            @Override
            public String toString() {
                return "WeatherinfoBean{" +
                        "city='" + city + ''' +
                        ", cityid='" + cityid + ''' +
                        ", temp1='" + temp1 + ''' +
                        ", temp2='" + temp2 + ''' +
                        ", weather='" + weather + ''' +
                        ", img1='" + img1 + ''' +
                        ", img2='" + img2 + ''' +
                        ", ptime='" + ptime + ''' +
                        '}';
            }
        }
    
    }
    
    凝视已经在代码中具体说明,就不做太多解释了。着重说一点。ResultSubscriber.java中的mRequestType是用来在连续多次请求网络接口时。须要在界面中做不同的处理而区分的属性。使用时,最好也为每一个接口配置为相应的唯一值。


    附上GitHub地址,https://github.com/QiYuan007/EasyFrame 假设本文对你有帮助,多多start。


    假设你有更好的实现方式,请与我联系。















  • 相关阅读:
    透明度问题解决方案
    不得不去奋斗的原因
    未来的你肯定会感谢现在努力的你
    前端学习参考
    js仿京东轮播图效果
    hyper容器网络相关源码分析
    利用setns()将进程加入一个新的network namespace
    frakti && RunPodSandbox 源码分析
    Makefile 编写 tips
    《In Search of an Understandable Consensus Algorithm》翻译
  • 原文地址:https://www.cnblogs.com/clnchanpin/p/7235304.html
Copyright © 2011-2022 走看看