Rxjava2和Retrofit2多个/并行/同时api(post)调用不同的线程

时间:2017-04-03 08:35:15

标签: android multithreading parallel-processing retrofit2 rx-java2

我有以下代码,我尝试使用Retrofit2 + RxJava2实现多个连续的api调用

@Override
        public void onClick(View v) {

            count++;
            request.setName("rober");
            request.setVarryingValue(count);

            mApiService.apiService()
                    .getAccessToken(<params>)
                    .subscribeOn(Schedulers.newThread())
                    .flatMap(new Function<Auth, ObservableSource<?>>() {
                        @Override
                        public ObservableSource<?> apply(Auth authentication) throws Exception {

                            Observable<Void> postObservable = mApiService.apiService().postCall(request, authentication.getAuth())
                                    .subscribeOn(Schedulers.io());
                            postObservable.subscribe(new Observer<Void>() {

                                @Override
                                public void onSubscribe(Disposable d) {}

                                @Override
                                public void onNext(Void value) {
                                    Log.e("Thread", " Thread : " + Thread.currentThread());
                                }

                                @Override
                                public void onError(Throwable e) {
                                    e.printStackTrace();
                                }

                                @Override
                                public void onComplete() {}
                            });

                            return postObservable;
                        }
                    }).subscribe(new Observer<Object>() {
                @Override
                public void onSubscribe(Disposable d) {}

                @Override
                public void onNext(Object value) {}

                @Override
                public void onError(Throwable e) {}

                @Override
                public void onComplete() {}
            });
        }
    });

我的期望是,每次点击,都会调用一个新的/不同的线程来执行特定的api POST调用,但我从内部api调用中获取这些post值

{"name ":"rober"," some_varrying_number ":"4"}
04-03 07:23:08.319 27225-27378/edu.rx.test D/OkHttp: --> END POST (1679-byte 
body)
04-03 07:23:08.322 27225-27380/edu.rx.test D/OkHttp: --> POST 
http://mydomain.test.post.server http/1.1

{"name ":"rober"," some_varrying_number ":"4"}
04-03 07:23:08.319 27225-27378/edu.rx.test D/OkHttp: --> END POST (1679-byte 
body)
04-03 07:23:08.322 27225-27380/edu.rx.test D/OkHttp: --> POST 
http://mydomain.test.post.server http/1.1


{"name ":"rober"," some_varrying_number ":"4"}
04-03 07:23:08.319 27225-27378/edu.rx.test D/OkHttp: --> END POST (1679-byte 
body)
04-03 07:23:08.322 27225-27380/edu.rx.test D/OkHttp: --> POST 
http://mydomain.test.post.server http/1.1


{"name ":"rober"," some_varrying_number ":"4"}
04-03 07:23:08.319 27225-27378/edu.rx.test D/OkHttp: --> END POST (1679-byte 
body)
04-03 07:23:08.322 27225-27380/edu.rx.test D/OkHttp: --> POST 
http://mydomain.test.post.server http/1.1
似乎它只执行最后一次通话,我已经知道没有确切的&#34;并行&#34;在Rx中打电话,因为如果确实如此,它将违反所有被动原则,但是他们说的很多解决方法,现在我试图实现那个&#34;并行&#34;用我发布的代码打电话,但没有运气:(,我需要一些帮助,

非常感谢任何帮助。谢谢!

编辑:过程就像这样 1.首先获取身份验证令牌 2.成功的身份验证令牌后,进入api POST呼叫

数字2取决于数字1

1&amp; 2将始终在点击事件上执行。

修改:发布图片以清楚说明

  • 我有2个来源(可以是3个或更多)
  • 这些来源来自点击事件
  • 每个来源都会处理不同的网络电话
  • 我试图在不同的线程中执行它(使其异步)
  • 每个都会在服务器上发布不同的值 enter image description here

  • 但似乎它只处理最后一个事件(点击)

  • 使用上面的图像,即时预期POST A和POST B将以并行/不同方式发生
  • 但它只执行POST B(实际上是2个POST B)
  • 我希望它能执行POST A&amp;以不同方式发布B

3 个答案:

答案 0 :(得分:2)

当您发送第一个POST请求时,request的变化值已经是4.那是因为在您单击4次之后,第一个POST请求将会那时的request(有4个),而不是设置其变化值时的request

解决方案是使request对象在onClick()方法

中成为本地对象
public void onClick(View v) {
    RequestClass request = new RequestClass();
    request.setName("rober");
    request.setVarryingValue(count);

    //Your code
}

或者将count值分配给临时变量,并在发送POST请求之前将其设置为request,但要注意线程安全性

public void onClick(View v) {
    //Saving the value
    int temp = count++;
    request.setName("rober");

    mApiService.apiService()
            .getAccessToken(<params>)
            .subscribeOn(Schedulers.newThread())
            .flatMap(new Function<Auth, ObservableSource<?>>() {
                @Override
                public ObservableSource<?> apply(Auth authentication) throws Exception {
                    //Set it to the request
                    //BE CAREFUL  because the `request` object is now being accessed from multiple threads
                    request.setVarryingValue(temp);

                    Observable<Void> postObservable = 
                        mApiService
                            .apiService()
                            .postCall(request, authentication.getAuth())
                            .subscribeOn(Schedulers.io())
                            .subscribe();

                    return postObservable;
                }
            })
            .subscribe();
}

答案 1 :(得分:1)

我不太清楚为什么所有的帖子请求都是同时完成的,包含onClick()时间和getAccessToken()请求的完整日志,以及{{1}排放可能会有所帮助。

您的代码似乎正确,您将为每个请求打开一个新线程 但是,无论如何,由于您在日志上有4个打印件,但所有打印件都相同,问题可能是因为onNext()参数是一个字段,因此在 {之后共享和访问 {1}}发出一个项目,因此你基本上做了4个请求但是具有相同的数据 您应该为每个新创建的request分配一个专用的计数变量。

除此之外,订阅getAccessToken()运算符中的flatMap()是错误的,您应该只返回它,然后流将订阅它并将其合并为{{1}排放。
使用您的代码,您执行每个帖子请求两次,一个由您明确执行,另一个由postObservable运算符执行(这也可能解释了同一请求的多个日志,但是如果没有看到日志中的所有数据,很难说清楚。)

答案 2 :(得分:0)

根据您建议的两个答案,我想出了以下代码,

  • 请求成为局部变量而不是字段
  • 取消平面地图内的订阅
  • 将其链接在外部可观察

    的onNext上
    @Override
    public void onClick(View v) {
    
    count++;
    Request request = new Request();
    request.setName("rober");
    request.setVarryingValue(count);
    
    mApiService.apiService()
            .getAccessToken(<params>)             
            .subscribeOn(Schedulers.io())
            .flatMap(new Function<Auth, ObservableSource<Void>>() {
                @Override
                public ObservableSource<Void> apply(Auth authentication) throws Exception {
                    return mApiService.apiService().postCall(request, authentication.getAuth());
                }
            })  
            .subscribe(new Observer<ObservableSource<Void>>() {
    
                @Override
                public void onSubscribe(Disposable d) {}
    
                @Override
                public void onNext(ObservableSource<Void> sourceFromFlatMap) {
    
                    sourceFromFlatMap.subscribe(new Observer<Void>() {
    
                        @Override
                        public void onSubscribe(Disposable d) {}
    
                        @Override
                        public void onNext(Void value) {
                        }
    
                        @Override
                        public void onError(Throwable e) {}
    
                        @Override
                        public void onComplete() {}
                    });
                }
    
                @Override
                public void onError(Throwable e) {}
    
                @Override
                public void onComplete() {}
            });
     });
    

虽然我还不确定我是否以正确的方式使用Rx