【问题标题】:Converting an image loading asynctask to rxjava, why is it lagging the ui?将图像加载asynctask转换为rxjava,为什么会滞后ui?
【发布时间】:2016-09-08 08:13:17
【问题描述】:

我正在尝试学习 RxJava,我正在转换 AsyncTask 我必须成为 Observable/Subscriber。原来的AsyncTask在后台加载了一张图片,然后在onPostExecute中为加载的图片设置了一个ImageView的drawable。显示的图像在回收视图中,并且随着列表滚动,为列表中的每个项目加载图像。我将它转换为 Rx,但现在滚动时有很多滞后。每次在 RecyclerView 的适配器中调用 onBind 时,都会调用方法 fetchThumbnail。下面你会看到我原来的实现被注释掉了,新的实现。使用 RxJava 时,我发现内存或 CPU 使用率没有显着增加。我相信我也在订阅和观察正确的线程。什么给了?

public class ThumbnailWorker {

    public static void fetchThumbnail(final Context context, final GalleryItem galleryItem, final int thumbId, final ThumnailFetchedListener completionListener) {

        galleryItem.thumbnail.setImageBitmap(null);
        galleryItem.progressBar.setVisibility(View.VISIBLE);

        Observable.just(MediaStore.Video.Thumbnails.getThumbnail(context.getContentResolver(),
                thumbId
                , MediaStore.Video.Thumbnails.MINI_KIND,
                null))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<Bitmap>() {
                    @Override
                    public void call(Bitmap bitmap) {
                        completionListener.thumbnailFetched(galleryItem, bitmap, thumbId);
                        galleryItem.progressBar.setVisibility(View.GONE);
                    }
                });


//
//        new AsyncTask<Void,Bitmap,Bitmap>() {
//
//
//            @Override
//            protected void onPreExecute() {
//                super.onPreExecute();
//                galleryItem.thumbnail.setImageBitmap(null);
//                galleryItem.progressBar.setVisibility(View.VISIBLE);
//            }
//
//            @Override
//            protected Bitmap doInBackground(Void... params) {
//                Bitmap bitmap = MediaStore.Video.Thumbnails.getThumbnail(context.getContentResolver(),
//                        thumbId
//                        ,MediaStore.Video.Thumbnails.MINI_KIND,
//                        null
//                );
//
//                return bitmap;
//            }
//
//
//            @Override
//            protected void onPostExecute(Bitmap bitmap) {
//                super.onPostExecute(bitmap);
//                completionListener.thumbnailFetched(galleryItem, bitmap,thumbId);
//                galleryItem.progressBar.setVisibility(View.GONE);
//
//            }
//        }.execute();


    }
}

这就是听众所做的一切。侦听器回调适配器。

@Override
public void thumbnailFetched(GalleryItem item, Bitmap thumbnail, int thumbId) {
    if(thumbId == item.id) {
        item.thumbnail.setImageBitmap(thumbnail);
    }
}

【问题讨论】:

  • 如果有一件事,你似乎没有在任何地方退订。

标签: android android-asynctask rx-java rx-android


【解决方案1】:

Observable.just 可用于已计算的值。

我假设此调用 MediaStore.Video.Thumbnails.getThumbnail(...) 处理您的图像,因此可能会滞后您的 UI。你必须推迟你的电话。为此,您可以使用Observable.fromCallable

  Observable.fromCallable(() -> MediaStore.Video.Thumbnails.getThumbnail(context.getContentResolver(), thumbId                 , MediaStore.Video.Thumbnails.MINI_KIND, null))
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(bitmap -> {
                    completionListener.thumbnailFetched(galleryItem, bitmap, thumbId);
                    galleryItem.progressBar.setVisibility(View.GONE);
            });

【讨论】:

  • 推迟通话是什么意思?这是否意味着后台调用?
  • 在订阅 observable 时执行调用,而不是在创建 observable 时执行调用
【解决方案2】:

UI阻塞的原因是just(...)运算符中的表达式是在当前线程中执行的。

如果要在subscribeOn(..) 中指定的线程中执行表达式,则必须使用create(..) 方法创建Observable,而不是just(..) 方法。

对你来说,它看起来像这样:

Observable.create(new Observable.OnSubscribe<Bitmap>(){
        @Override
        public void call(Subscriber<? super Bitmap> subscriber){
            subscriber.onNext(MediaStore.Video.Thumbnails.getThumbnail(context.getContentResolver(),
                    thumbId
                    , MediaStore.Video.Thumbnails.MINI_KIND,
                    null));

            subscriber.onCompleted();
        }
    })
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Action1<Bitmap>() {
                @Override
                public void call(Bitmap bitmap) {
                    completionListener.thumbnailFetched(galleryItem, bitmap, thumbId);
                    galleryItem.progressBar.setVisibility(View.GONE);
                }
            });

【讨论】:

  • 使用Observable.create 会给您带来错误处理和背压方面的负担。 fromCallable 是一个更优雅的解决方案。
  • 我同意。 @dwursteisen 的答案更优雅。但是你必须记住fromCallable() 不会在订阅者之间共享结果(发射),它会为每个新订阅者执行传递的函数。
  • 好点!我对 Rx 还是有点陌生​​,但不会链接到 cache() 的调用来补救这种行为吗?
  • @npace ,cache() 会给你这样的行为。但我只需要提到fromCallable() 用法的这一部分
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多