Rxjava +Retrofit2

Rxjava分发使用

   Observable.create(

            // 自定义source
            new ObservableOnSubscribe<String>() {
                @Override
                public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                    // 发射器.onNext
                    emitter.onNext("A");
                }
    })

    // 3:subscribe订阅过程 源码分析
    // ObservableCreate. subscribe
    .subscribe(

            // 自定义观察者
            // 1:Observer 
            new Observer<String>() {
                @Override
                public void onSubscribe(Disposable d) {

                }

                @Override
                public void onNext(String s) {

                }

                @Override
                public void onError(Throwable e) {

                }

                @Override
                public void onComplete() {

                }
            });
}

 

Rxjava 不加 Retrofit框架的话使用为

 

public void rxJavaDownloadImageAction(View view) {
    // 起点
    Observable.just(PATH)  // 内部会分发  PATH Stirng  // TODO 第二步

     // TODO 第三步
    .map(new Function<String, Bitmap>() {
        @Override
        public Bitmap apply(String s) throws Exception {
            URL url = new URL(PATH);
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            httpURLConnection.setConnectTimeout(5000);
            int responseCode = httpURLConnection.getResponseCode(); // 才开始 request
            if (responseCode == HttpURLConnection.HTTP_OK) {
                InputStream inputStream = httpURLConnection.getInputStream();
                Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                return bitmap;
            }
            return null;
        }
    })
    /*.map(new Function<Bitmap, Bitmap>() {//中间可以使用加画笔水印的功能
        @Override
        public Bitmap apply(Bitmap bitmap) throws Exception {
            Paint paint = new Paint();
            paint.setTextSize(88);
            paint.setColor(Color.RED);
            return drawTextToBitmap(bitmap, "大家好",paint, 88 , 88);
        }
    })*/
    
    // 日志记录
    .map(new Function<Bitmap, Bitmap>() {
        @Override
        public Bitmap apply(Bitmap bitmap) throws Exception {
            Log.d(TAG, "apply: 是这个时候下载了图片啊:" + System.currentTimeMillis());
            return bitmap;
        }
    })

    .compose(rxud())

    // 订阅 起点 和 终点 订阅起来
    .subscribe(

            // 终点
            new Observer<Bitmap>() {

                // 订阅开始
                @Override
                public void onSubscribe(Disposable d) {
                    // 预备 开始 要分发
                    // TODO 第一步
                    progressDialog = new ProgressDialog(DownloadActivity.this);
                    progressDialog.setTitle("download run");
                    progressDialog.show();
                }

                // TODO 第四步
                // 拿到事件
                @Override
                public void onNext(Bitmap bitmap) {
                    image.setImageBitmap(bitmap);
                }

                // 错误事件
                @Override
                public void onError(Throwable e) {

                }

                // TODO 第五步
                // 完成事件
                @Override
                public void onComplete() {
                    if (progressDialog != null)
                        progressDialog.dismiss();
                }
    });

}

 

// 图片上绘制文字 加水印
private final Bitmap drawTextToBitmap(Bitmap bitmap, String text, Paint paint, int paddingLeft, int paddingTop) {
    Bitmap.Config bitmapConfig = bitmap.getConfig();

    paint.setDither(true); // 获取跟清晰的图像采样
    paint.setFilterBitmap(true);// 过滤一些
    if (bitmapConfig == null) {
        bitmapConfig = Bitmap.Config.ARGB_8888;
    }
    bitmap = bitmap.copy(bitmapConfig, true);
    Canvas canvas = new Canvas(bitmap);

    canvas.drawText(text, paddingLeft, paddingTop, paint);
    return bitmap;
}

Retrofit2基本使用

 

一、Get请求
Retrofit在使用的过程中需要定义接口层,接口层中的每个方法标识一个独立的请求,如下定义接口层ApiService

public interface ApiService {

    @GET("users/list")
    Call<List<User>> getUsers();
}

@Get注解作用于方法之上,表明这是一个Get请求,@Get注解的value值与Retrofit中配置的baseUrl组成完整的请求url,List<User>代表响应结果类型,下面通过Retrofit请求完成上述请求

        // builder模式构建Retrofit对象
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.example.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        // 创建接口层的代理对象,内部通过动态代理创建了ApiService的代理对象  
        ApiService api = retrofit.create(ApiService.class);
        // 执行异步请求
        api.getUsers().enqueue(new Callback<List<User>>() {
            @Override
            public void onResponse(Call<List<User>> call, Response<List<User>> response) {
                // 处理结果
            }

            @Override
            public void onFailure(Call<List<User>> call, Throwable t) {
                // 处理异常
            }
        });

 

 

二、动态url访问@PATH

public interface ApiService {

    @GET("user/{id}")
    Call<User> getUser(@Path("id") String id);
}
@Get注解中使用了{id}作为占位符,实际运行会通过方法中@Path(“id”)注解标注的参数进行替换,访问案例如下:

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.example.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        ApiService api = retrofit.create(ApiService.class);
        api.getUser("1").enqueue(new Callback<User>() {
            @Override
            public void onResponse(Call<User> call, Response<User> response) {
              
            }

            @Override
            public void onFailure(Call<User> call, Throwable t) {
             
            }
        });
三、带有查询参数设置@Query的Get请求

例如我们要访问这样的url https://api.example.com/users?username=zhangsan 接口层定义如下:

public interface ApiService {

    @GET("users")
    Call<User> getUserByUserName(@Query("username") String username);
}
通过@Get表明了请求方式,通过@Query标注了请求的参数名,同样的也适用与Post请求,只需要将@Get注解替换为@Post即可

 

四、POST请求体的方式向服务器传入json字符串@Body

public interface ApiService {

    @POST("users/add")
    Call<List<User>> addUser(@Body User user);
}
可以看到我们通过@Body注解标注参数对象即可,而后Retrofit内部将User对象转换了json字符串传递给服务端

 

其他用法参照博文https://blog.csdn.net/lilinjie_blog/article/details/108569042  下面直接讲Rxjava +Retrofit2

(1)首先定义了一个接口  这里使用的是玩android的通用接口 

public interface WangAndroidApi {

    // 总数据
    @GET("project/tree/json")
    Observable<ProjectBean> getProject();  // 异步线程 耗时操作

    // ITem数据
    @GET("project/list/{pageIndex}/json") // ?cid=294
    Observable<ProjectItem> getProjectItem(@Path("pageIndex") int pageIndex, @Query("cid") int cid);  // 异步线程 耗时操作
}

 

(2)定义一个http工具接口类

public class HttpUtil {

    private static final String TAG = "HttpUtils";

    /**
     * 默认 test-a环境
     */
    public static String BASE_URL = "https://www.wanandroid.com/";

    public static void setBaseUrl(String baseUrl) {
        BASE_URL = baseUrl;
    }

    /**
     * 根据各种配置创建出Retrofit
     *
     * @return 返回创建好的Retrofit
     */
    public static Retrofit getOnlineCookieRetrofit() {
        // OKHttp客户端
        OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder();
        // 各种参数配置
        OkHttpClient okHttpClient = httpBuilder
                .addNetworkInterceptor(new StethoInterceptor())
                .readTimeout(10000, TimeUnit.SECONDS)
                .connectTimeout(10000, TimeUnit.SECONDS)
                .writeTimeout(10000, TimeUnit.SECONDS)
                .build();


        return new Retrofit.Builder().baseUrl(BASE_URL)
                // TODO 请求用 OKhttp
                .client(okHttpClient)

                // TODO 响应RxJava
                // 添加一个json解析的工具
                .addConverterFactory(GsonConverterFactory.create(new Gson()))
                // 添加rxjava处理工具
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())    //这个一定要

                .build();
    }
}

 

(3)  在Activity中获取接口实例

 ApiService api = retrofit.create(ApiService.class);//对比这个


private WangAndroidApi api;
        api = HttpUtil.getOnlineCookieRetrofit().create(WangAndroidApi.class);

然后获取网络数据api

/**
 * TODO Retrofit+RxJava 查询 项目分类  (总数据查询)
 *
 * @param view
 */
public void getProjectAction(View view) {
    // 获取网络API
    api.getProject()
            .subscribeOn(Schedulers.io()) // 上面 异步
            .observeOn(AndroidSchedulers.mainThread()) // 下面 主线程
            .subscribe(new Consumer<ProjectBean>() {                      //简便版可以new Consumer  需要回调可以new Observer
                @Override
                public void accept(ProjectBean projectBean) throws Exception {
                    Log.d(TAG, "accept: " + projectBean); // UI 可以做事情
                }
            });
}

 

/**
 * TODO Retrofit+RxJava 查询  项目分类的49 去 获取项目列表数据  (Item)
 *
 * @param view
 */
public void getProjectListAction(View view) {
    // 注意:这里的 294 是项目分类 所查询出来的数据
    // 上面的项目分类会查询出:"id": 294,"id": 402,"id": 367,"id": 323,"id": 314, ...

    // id 写死的
    api.getProjectItem(1, 294)
            // .....
            .subscribeOn(Schedulers.io()) // 上面 异步
            .observeOn(AndroidSchedulers.mainThread()) // 下面 主线程
            .subscribe(data->{
                Log.d(TAG, "getProjectListAction: " + data);
            });

}

可以实际上这个id应该是先查询总数据再根据上面的id传下来的如果是这个的话写法就是以下

插入一个利用 

implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1' // 操作功能防抖

使用防抖功能,适用于所有View

 

/**
 * RxJava
 * RxJs
 * Rxxxxx
 * RxBinding  防抖
 *
 * TODO 功能防抖 + 网络嵌套(这种是负面教程,嵌套的太厉害了)
 * 2层嵌套
 * 6层
 */
@SuppressLint("CheckResult")
private void antiShakeActon() {
    // 注意:(项目分类)查询的id,通过此id再去查询(项目列表数据)

    // 对那个控件防抖动?
    Button bt_anti_shake = findViewById(R.id.bt_anti_shake);

    RxView.clicks(bt_anti_shake)
            .throttleFirst(2000, TimeUnit.MILLISECONDS) // 2秒钟之内 响应你一次
            .subscribe(new Consumer<Object>() {
                @Override
                public void accept(Object o) throws Exception {
                    api.getProject() // 查询主数据
                    .compose(DownloadActivity.rxud())
                    .subscribe(new Consumer<ProjectBean>() {
                        @Override
                        public void accept(ProjectBean projectBean) throws Exception {
                            for (ProjectBean.DataBean dataBean : projectBean.getData()) { // 10
                                // 查询item数据
                                api.getProjectItem(1, dataBean.getId())
                                .compose(DownloadActivity.rxud())
                                .subscribe(new Consumer<ProjectItem>() {
                                    @Override
                                    public void accept(ProjectItem projectItem) throws Exception {
                                        Log.d(TAG, "accept: " + projectItem); // 可以UI操作
                                    }
                                });
                            }
                        }
                    });
                }
            });
}

 

 

下面使用javamap操作符可以分发多次解决这种嵌套问题

 

/**
 * TODO 功能防抖 + 网络嵌套 (解决嵌套的问题) flatMap
 */
@SuppressLint("CheckResult")
private void antiShakeActonUpdate() {
    // 注意:项目分类查询的id,通过此id再去查询(项目列表数据)

    // 对那个控件防抖动?
    Button bt_anti_shake = findViewById(R.id.bt_anti_shake);

    RxView.clicks(bt_anti_shake)
            .throttleFirst(2000, TimeUnit.MILLISECONDS) // 2秒钟之内 响应你一次

            // 我只给下面 切换 异步
            .observeOn(Schedulers.io())
                                    //上面下来的 //传给下面的
            .flatMap(new Function<Object, ObservableSource<ProjectBean>>() {
                @Override
                public ObservableSource<ProjectBean> apply(Object o) throws Exception {
                    return api.getProject(); // 主数据
                }
            })

            // 第一步不能map 因为  api Observbale<Bean>  TODO 
            /*.map(new Function<Object, ObservableSource<ProjectBean>>() {
                @Override
                public ObservableSource<ProjectBean> apply(Object o) throws Exception {
                    return api.getProject(); // 主数据;
                }
            })*/
                                   //上面下来的                    //传给下面的
            .flatMap(new Function<ProjectBean, ObservableSource<ProjectBean.DataBean>>() {     
                @Override
                public ObservableSource<ProjectBean.DataBean> apply(ProjectBean projectBean) throws Exception {
                    return Observable.fromIterable(projectBean.getData()); // 我自己搞一个发射器 发多次 10 实际上里面有多少次会循环发送几次
                }
            })
            .flatMap(new Function<ProjectBean.DataBean, ObservableSource<ProjectItem>>() {
                @Override
                public ObservableSource<ProjectItem> apply(ProjectBean.DataBean dataBean) throws Exception {
                    return api.getProjectItem(1, dataBean.getId());
                }
            })

            .observeOn(AndroidSchedulers.mainThread()) // 给下面切换 主线程
            .subscribe(new Consumer<ProjectItem>() {
                @Override
                public void accept(ProjectItem projectItem) throws Exception {
                    // 如果我要更新UI  会报错2  不会报错1
                    Log.d(TAG, "accept: " + projectItem);
                }
            });
}

 

Rx思维: 响应式编程

生活中的例子:
起点(分发事件(PATH):我饿了)----------下楼-------去餐厅--------点餐----------> 终点(吃饭 消费事件)

程序中的例子:
起点(分发事件:点击登录)----------登录API-------请求服务器--------获取响应码----------> 终点(更新UI登录成功 消费事件)


起点可以分发一个数据
onNext(1);
    |
    |
    |
flatMap  自己分发 10个数据 给下面
 1 --> 多发送 10次 1+"DDD"  //javaEE
    |
    |
    |
subscribe{
    1+"DDD"
    1+"DDD"
    1+"DDD"
    1+"DDD"
    1+"DDD"
    1+"DDD"
    1+"DDD"
    1+"DDD"
    1+"DDD"
    1+"DDD"

 

 

下面使用

doOnNext这个操作符完成下面的实现 

 

  • do系列的作用是side effect,当onNext发生时,它被调用,不改变数据流。
  • doOnNext()允许我们在每次输出一个元素之前做一些额外的事情。
* 4.一行代码写完需求流程: 从上往下
*    1.请求服务器,执行注册操作(耗时)切换异步线程
*    2.更新注册后的所有 注册相关UI - main  切换主线程
*    3.请求服务器,执行登录操作(耗时)切换异步线程
*    4.更新登录后的所有 登录相关UI - main  切换主线程
public static Retrofit createRetrofit() {

    OkHttpClient.Builder builder = new OkHttpClient.Builder();

    builder.readTimeout(10, TimeUnit.SECONDS);
    builder.connectTimeout(9, TimeUnit.SECONDS);

    if (BuildConfig.DEBUG) {
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        builder.addInterceptor(interceptor);
    }

    return new Retrofit.Builder().baseUrl("http://xxxxxxx")
            .client(builder.build())
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .build();
}
MyRetrofit.createRetrofit().create(IReqeustNetwor.class)
        .registerAction(new RegisterRequest()) // todo 1.请求服务器注册操作   // todo 2
        .subscribeOn(Schedulers.io()) // 给上面 异步
        .observeOn(AndroidSchedulers.mainThread()) // 给下面分配主线程
        .doOnNext(new Consumer<RegisterResponse>() { // todo 3
            @Override
            public void accept(RegisterResponse registerResponse) throws Exception {
                // todo 2.注册完成之后,更新注册UI
            }
        })
        // todo 3.马上去登录服务器操作
        .observeOn(Schedulers.io()) // 给下面分配了异步线程
        .flatMap(new Function<RegisterResponse, ObservableSource<LoginResponse>>() { // todo 4
            @Override
            public ObservableSource<LoginResponse> apply(RegisterResponse registerResponse) throws Exception {
                Observable<LoginResponse> loginResponseObservable = MyRetrofit.createRetrofit().create(IReqeustNetwor.class)
                        .loginAction(new LoginReqeust());
                return loginResponseObservable;
            }
        })
        .observeOn(AndroidSchedulers.mainThread()) // 给下面 执行主线程
        .subscribe(new Observer<LoginResponse>() {

            // 一定是主线程,为什么,因为 subscribe 马上调用onSubscribe
            @Override
            public void onSubscribe(Disposable d) {
                // TODO 1
                progressDialog = new ProgressDialog(RequestActivity.this);
                progressDialog.show();

                // UI 操作

                disposable = d;
            }

            @Override
            public void onNext(LoginResponse loginResponse) { // todo 5
                // TODO 4.登录完成之后,更新登录的UI
            }

            @Override
            public void onError(Throwable e) {

            }

            // todo 6
            @Override
            public void onComplete() {
                //结束
                if (progressDialog != null) {
                    progressDialog.dismiss();
                }
            }
        });

 

注意一定要关掉 Disposable

 

Disposable disposable;
.subscribe(





        // 自定义观察者
        // 1:Observer 源码看看
        new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                disposable  = d;
            }

            @Override
            public void onNext(String s) {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onComplete() {

            }
        });

 

@Override
protected void onDestroy() {  //一定要写,不然会发现内存泄漏
    super.onDestroy();
    if(disposable != null){
      if(!disposable.isDisposed()){
          disposable.dispose();
      }

    }
}

 

 

 

源代码已经上传资源

https://download.csdn.net/download/u013286571/16670315