我正在为我的应用程序建立网络.所以我决定试试Square's Retrofit.我看到他们支持simple Callback

@GET("/user/{id}/photo")
void getUserPhoto(@Path("id") int id, Callback<Photo> cb);

和RxJava的Observable

@GET("/user/{id}/photo")
Observable<Photo> getUserPhoto(@Path("id") int id);

乍一看,两者看起来非常相似,但当涉及到实现时,它就变得有趣了...

而对于简单的回调实现,则与此类似:

api.getUserPhoto(photoId, new Callback<Photo>() {
    @Override
    public void onSuccess() {
    }
});

这是非常简单和直截了当的.对于Observable,它很快就变得冗长而相当复杂.

public Observable<Photo> getUserPhoto(final int photoId) {
    return Observable.create(new Observable.OnSubscribeFunc<Photo>() {
        @Override
        public Subscription onSubscribe(Observer<? super Photo> observer) {
            try {
                observer.onNext(api.getUserPhoto(photoId));
                observer.onCompleted();
            } catch (Exception e) {
                observer.onError(e);
            }

            return Subscriptions.empty();
        }
    }).subscribeOn(Schedulers.threadPoolForIO());
}

不是这样的.你还得做这样的事:

Observable.from(photoIdArray)
        .mapMany(new Func1<String, Observable<Photo>>() {
            @Override
            public Observable<Photo> call(Integer s) {
                return getUserPhoto(s);
            }
        })
        .subscribeOn(Schedulers.threadPoolForIO())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Action1<Photo>() {
            @Override
            public void call(Photo photo) {
                //save photo?
            }
        });

我错过什么了吗?或者使用Observable是一种错误的情况?

使现代化

正如@Niels在他的回答中或Jake Wharton的示例项目U2020中所示,使用改装比上面的例子简单得多.但从本质上来说,问题是一样的——什么时候应该使用这种或那种方式?

推荐答案

对于简单的联网工作,RxJava相对于回调的优势非常有限.简单的getUserPhoto示例:

RxJava:个个

api.getUserPhoto(photoId)
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Action1<Photo>() {
            @Override
            public void call(Photo photo) {
               // do some stuff with your photo 
            }
     });

Callback:

api.getUserPhoto(photoId, new Callback<Photo>() {
    @Override
    public void onSuccess(Photo photo, Response response) {
    }
});

RxJava变量并不比回调变量好多少.现在,让我们忽略错误处理.

RxJava:个个

api.getUserPhotos(userId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(new Func1<List<Photo>, Observable<Photo>>() {
    @Override
    public Observable<Photo> call(List<Photo> photos) {
         return Observable.from(photos);
    }
})
.filter(new Func1<Photo, Boolean>() {
    @Override
    public Boolean call(Photo photo) {
         return photo.isPNG();
    }
})
.subscribe(
    new Action1<Photo>() {
    @Override
        public void call(Photo photo) {
            list.add(photo)
        }
    });

Callback:

api.getUserPhotos(userId, new Callback<List<Photo>>() {
    @Override
    public void onSuccess(List<Photo> photos, Response response) {
        List<Photo> filteredPhotos = new ArrayList<Photo>();
        for(Photo photo: photos) {
            if(photo.isPNG()) {
                filteredList.add(photo);
            }
        }
    }
});

现在,RxJava变体仍然没有变小,尽管使用Lambdas,它将更接近回调变量.

First conclusion

当你加载一个简单的JSON时,它不会让你的代码库变小,你已经准备好使用正确的格式.

现在,让我们让事情变得更有趣一点.假设您不仅想要检索userPhoto,还拥有一个Instagram克隆,并且想要检索2个JSON:

您希望并行加载这两个JSON,当这两个JSON都加载时,应该会显示页面. 回调变量将变得有点困难:您必须创建2个回调,将数据存储在活动中,如果加载了所有数据,则显示页面:

Callback:

api.getUserDetails(userId, new Callback<UserDetails>() {
    @Override
    public void onSuccess(UserDetails details, Response response) {
        this.details = details;
        if(this.photos != null) {
            displayPage();
        }
    }
});

api.getUserPhotos(userId, new Callback<List<Photo>>() {
    @Override
    public void onSuccess(List<Photo> photos, Response response) {
        this.photos = photos;
        if(this.details != null) {
            displayPage();
        }
    }
});

RxJava:个个

private class Combined {
    UserDetails details;
    List<Photo> photos;
}


Observable.zip(api.getUserDetails(userId), api.getUserPhotos(userId), new Func2<UserDetails, List<Photo>, Combined>() {
            @Override
            public Combined call(UserDetails details, List<Photo> photos) {
                Combined r = new Combined();
                r.details = details;
                r.photos = photos;
                return r;
            }
        }).subscribe(new Action1<Combined>() {
            @Override
            public void call(Combined combined) {
            }
        });

我们有进展了!RxJava的代码现在和回调选项一样大.RxJava代码更健壮;

另一个例子;我们想要创建一个自动完成字段,它使用改装加载数据.

inputObservable.debounce(1, TimeUnit.SECONDS).subscribe(new Action1<String>() {
            @Override
            public void call(String s) {
                // use Retrofit to create autocompletedata
            }
        });

我不会创建回调变量,但是您会理解这是更多的工作.

结论:

Android相关问答推荐

编写Landscape BoxWithRequests具有错误的高度.(aspectRatio matchHeight约束第一次未按预期工作)

Google Play测试应用程序Crash-java.lang.NoSuchFieldError:没有Lkotlinx/coroutines/CoroutineExceptionHandler类型的字段键

推断的类型是片段,但应为上下文

在模块中找到重复的类com.google.Firebase.auth.ktx.AuthKt||Android Studio

数据绑定在Android中等待填充值时显示未填充的值

安卓Azure通讯聊天UI库导入?

android crashlytics 显示崩溃但不显示我的课程中的位置

页面标题未显示在内容页面上

Android Drawable文件夹中的图像显示模糊

在移动设备上看到时如何增加 PasswordField 文本?

如何使用 Jetpack Compose 制作两个圆圈

如何在屏幕旋转或系统主题更改后将光标移动到 TextField 的末尾并保持键盘显示?

没有互联网连接时,Firebase Storage putFile() 永远不会完成

为 AlertDialog 的消息文本设置自定义字体

在jetpack compose中将图像添加到脚手架顶部栏

在 Android Studio 中替换字符串中的 "

Android Studio (Kotlin):无法启动活动

Jetpack Compose Tapjacking:过滤对模糊 UI 的touch

WearOS - 有没有办法从心电图传感器收集原始数据?

dagger2 抛出错误:如果没有 @Provides-annotated 方法就无法提供.在我的 android 项目的构建中