RXJava Android 进行多个不同长度的调用

Posted

技术标签:

【中文标题】RXJava Android 进行多个不同长度的调用【英文标题】:RXJava Android make multiple calls with different lengths 【发布时间】:2021-10-07 06:33:23 【问题描述】:

我需要从服务器获取相机ID,然后通过ID获取此相机的事件,最后通过ID获取图像。 然后,所有这些都需要组合成一个 UI 帖子 Camera name - image url - it events 例如,我们可能有 5 个摄像头名称、30 个事件 ID(一个摄像头名称对应 6 个)和 30 个 url。 我尝试使用 zip 来组合 Observable api 调用(分别)获取相机名称、事件 ID 和图像 url。但据我了解,由于 zip 无法正确匹配 5 个名称和 30 个 ID,因此它无法正常工作 告诉我什么可以用来做这个?

 GetApiMethods getApiMethods = NetworkService.getInstance().createService(GetApiMethods.class);
    Observable<Camera> cameras = getCamera();
    Observable<Event> events = getEvents();
    Observable<Post> combined = Observable.zip(cameras, events, (camera, event) -> new Post(camera.getDisplayName(),"null",event.getType()));


    public LiveData<String> CameraRequests() 
        combined.subscribeOn(Schedulers.io())
                .observeOn(androidSchedulers.mainThread())
                .concatMap(Observable::fromArray)
                .subscribe(new Observer<Post>() 

                    @Override
                    public void onSubscribe(@NonNull Disposable d) 

                    

                    @Override
                    public void onNext(@NonNull Post post) 
                    

                    @Override
                    public void onError(@NonNull Throwable e) 

                    

                    @Override
                    public void onComplete() 

                    
                );

        return liveData;
    

    public Observable<Event> getEvents() 
        return Observable.create(allEvents -> getApiMethods.getCameras()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .concatMap(Observable::fromIterable)
                .concatMap(Observable::fromIterable)
                .concatMap(camera -> getApiMethods.getEvents(camera.getAccessPoint().replace("hosts", "")))
                .concatMap(Observable::fromIterable)
                .map(Event::getId)
                .subscribe(new Observer<String>() 
                    @Override
                    public void onSubscribe(@NonNull Disposable d) 

                    

                    @Override
                    public void onNext(@NonNull String event) 
                    

                    @Override
                    public void onError(@NonNull Throwable e) 
                        Log.d("RXJAVA1", String.valueOf(e));
                    

                    @Override
                    public void onComplete() 

                    
                )
        );

    



    public Observable<Camera> getCamera() 

        return Observable.create(cameras1 -> getApiMethods.getCameras()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .concatMap(Observable::fromIterable)
                .map(Camera::getDisplayName)
                .subscribe(new Observer<String>() 
                    @Override
                    public void onSubscribe(@NonNull Disposable d) 

                    

                    @Override
                    public void onNext(@NonNull String s) 

                    

                    @Override
                    public void onError(@NonNull Throwable e) 
                        Log.d("RXJAVA", String.valueOf(e));
                    

                    @Override
                    public void onComplete() 
                        

                    
                )

        );

    

【问题讨论】:

@MikkelT 谢谢!但是我对 Livedata 没有任何问题,只有 RXJava omg 对不起,我一定是回错帖了 你能添加你到目前为止尝试过的代码吗? @DatPhamTat 你好!我已附上代码 【参考方案1】:

如果使用flatMap,对我来说似乎很期待:

Observable<Post> getPostsObservable() 
        return getCameras().flatMap(camera ->
                // for each camera, build observable to get events
                getEvents(camera.accessPoint).flatMap(event ->
                        // for each event, build observable to get imageUrl
                        getImageUrl(event.id).map(imageUrl ->
                                // combine camera, event and imageUrl in current rx-chain
                                new Post(camera, event, imageUrl)
                        )
                )
        );
    

您可能需要稍微调整您的代码,例如简化您的 getCamerasgetEvents 方法。您可以查看下面模仿您的应用程序的演示,以更好地了解它的工作原理以及要返工的内容。如果调用 getPosts 方法,您应该在 logcat 中看到帖子正在正确创建和接收。

import android.util.Log;

import androidx.annotation.NonNull;

import java.util.ArrayList;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;

public class RxDemo 
    // your Camera class
    public class Camera 
        private final String accessPoint;

        public Camera(String accessPoint) 
            this.accessPoint = accessPoint;
        

        public String getAccessPoint() 
            return accessPoint;
        
    

    // your Event class
    public class Event 
        private final String id;

        public Event(String id) 
            this.id = id;
        

        public String getId() 
            return id;
        
    

    // your Post class
    public class Post 
        private final Camera camera;
        private final Event event;
        private final String imageUrl;

        public Post(Camera camera, Event event, String imageUrl) 
            this.camera = camera;
            this.event = event;
            this.imageUrl = imageUrl;
        

        public Camera getCamera() 
            return camera;
        

        public Event getEvent() 
            return event;
        

        public String getImageUrl() 
            return imageUrl;
        

        @NonNull
        @Override
        public String toString() 
            return "camera: " + camera.accessPoint + "; event: " + event.id + "; imageUrl: " + imageUrl;
        
    

    // mocked getApiMethods.getCameras(), return 5 mocked cameras
    private Observable<List<Camera>> apiGetCameras() 
        List<Camera> cameras = new ArrayList<>();
        cameras.add(new Camera("cam_1"));
        cameras.add(new Camera("cam_2"));
        cameras.add(new Camera("cam_3"));
        cameras.add(new Camera("cam_4"));
        cameras.add(new Camera("cam_5"));
        return Observable.just(cameras);
    

    // mocked getApiMethods.getEvents, return 6 mocked events with cameraId postFix
    private Observable<List<Event>> apiGetEvents(String cameraId) 
        List<Event> events = new ArrayList<>();
        events.add(new Event("event_1_" + cameraId));
        events.add(new Event("event_2_" + cameraId));
        events.add(new Event("event_3_" + cameraId));
        events.add(new Event("event_4_" + cameraId));
        events.add(new Event("event_5_" + cameraId));
        events.add(new Event("event_6_" + cameraId));
        return Observable.just(events);
    

    // mocked getApiMethods.getImageUrl
    private Observable<String> apiGetImageUrl(String eventId) 
        return Observable.just("http://my.domain.com/" + eventId + ".png");
    

    public Observable<Camera> getCameras() 
        return apiGetCameras().concatMapIterable(cam -> cam);
    

    public Observable<Event> getEvents(String cameraId) 
        return apiGetEvents(cameraId).concatMapIterable(event -> event);
    

    // build observable that emits posts
    private Observable<Post> getPostsObservable() 
        return getCameras().flatMap(camera ->
                // for each camera, build observable to get events
                getEvents(camera.accessPoint).flatMap(event ->
                        // for each event, build observable to get imageUrl
                        apiGetImageUrl(event.id).map(imageUrl ->
                                // combine camera, event and imageUrl in current rx-chain
                                new Post(camera, event, imageUrl)
                        )
                )
        );
    

    // call this in your activity/fragment/viewModel to get the posts
    public void getPosts() 
        getPostsObservable()
                .subscribeOn(Schedulers.io())
                .subscribe(new Observer<Post>() 
                    @Override
                    public void onSubscribe(@NonNull Disposable d) 

                    

                    @Override
                    public void onNext(@NonNull Post post) 
                        Log.d("AAAA", post.toString());
                    

                    @Override
                    public void onError(@NonNull Throwable e) 

                    

                    @Override
                    public void onComplete() 

                    
                );
    

【讨论】:

非常感谢!这完全解决了我的问题。如果可能的话,你能告诉我如何根据 event.getID 添加到从服务器下载的照片吗? (没有代码,只是理论) 不确定您的下载逻辑是什么样的,但在getPosts 内的onNext 回调中,您拥有发布所需的所有信息,包括imageUrl,因此您可以在那里执行下载.假设您的下载函数名为public void downloadImage(String imageUrl),那么您将在onNext 回调中调用它,使用post.imageUrl 作为参数。 如果我的评论没有回答您关于图像下载的问题,那么可能会使用代码(您尝试过的内容/您认为可行的内容)和进一步的解释创建一个新问题。如果我能更好地理解您的问题,我会更容易为您提供帮助。 谢谢!新问题***.com/questions/68619492/… 抱歉再次询问,但return cameras.concatMap(camera -&gt; getArchive().concatMap( archive -&gt; getEvents(archive.getAccessPoint().replace("hosts", "")).flatMap(event -&gt; getdetectorImage(archive.getAccessPoint().replace("hosts", ""), event.getTimestamp(), event.getId()).map(image -&gt; new Post(camera.getDisplayName(), image.byteStream(), event.getType())) ))); 无法正常工作,摄像头名称显示为随机显示。我做错了什么?

以上是关于RXJava Android 进行多个不同长度的调用的主要内容,如果未能解决你的问题,请参考以下文章

Android RxJava使用介绍 RxJava的操作符

android学习笔记--RxJava

“再见RxJava,你好Flow”,Android线程切换哪家最强?

Android - 框架之RxJava的使用

Android RXJava2 内存性能

RxJava(11-线程调度Scheduler)