皮卡索 + RxJava2: 方法调用应该发生在主线程

4
这是我的初始问题:
我想在AutoScrollViewPager中展示几张图片。我使用Picasso来实现这一点。但是,我希望使用Rxjava2 + Picasso来完成相同的功能。我对RxJava的概念还比较陌生。如果有人能提供详细的帮助,将下面的代码转换为RxJava代码,我会非常感激。
这是我在onViewCreated()方法中所做的事情:
imageAdapter = new ImageAdapter(getActivity());
autoScrollViewPager.setAdapter(imageAdapter);
autoScrollViewPager.setCurrentItem(imageAdapter.getCount() - 1);
autoScrollViewPager.startAutoScroll();
autoScrollViewPager.setInterval(4000);

这是我的ImageAdapter
ImageAdapter(Context context){
    this.context=context;
    mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

@Override
public int getCount() {
    return GalImages.length;
}

@Override
public boolean isViewFromObject(View view, Object object) {
    return view == ((RelativeLayout) object);
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    LayoutInflater inflater = (LayoutInflater) container.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View view = inflater.inflate(R.layout.pager_item,null);
    ((ViewPager) container).addView(view);
    final ImageView img = (ImageView) view.findViewById(R.id.imageView);
    Picasso.with(context)
            .load(GalImages[position])
            .fit()
            .into(img);
    return view;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    container.removeView((RelativeLayout)object);
}

我该如何将这段代码转换成 RxJava 代码呢?感谢您的帮助。

以下是我的尝试:

我对我的 ImageAdapter 进行了一些修改:

@Override
public Object instantiateItem(ViewGroup container, int position) {
    LayoutInflater inflater = (LayoutInflater) container.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View view = inflater.inflate(R.layout.pager_item,null);
    ((ViewPager) container).addView(view);
    img = (ImageView) view.findViewById(R.id.imageView);
    loadImagesWithPicasso(position)
        .subscribeOn(Schedulers.newThread())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe();
    return view;
}

public Completable loadImagesWithPicasso(int position) {
   return Completable.fromAction(new Action() {
       @Override
       public void run() throws Exception {
           Picasso.with(context)
                  .load(GalImages[position])
                  .fit()
                  .into(new Target() {
                            @Override
                            public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {

                            }

                            @Override
                            public void onBitmapFailed(Drawable errorDrawable) {

                            }

                            @Override
                            public void onPrepareLoad(Drawable placeHolderDrawable) {
                                img.setImageDrawable(placeHolderDrawable);
                            }
                        });
       }
   });
}

但是不幸的是,这种方法并没有奏效,我最终遇到了以下错误:
java.lang.IllegalStateException: Method call should happen from the main thread.
at com.squareup.picasso.Utils.checkMain(Utils.java:136)
at com.squareup.picasso.RequestCreator.into(RequestCreator.java:496)
at com.kaaddevelopers.myprescriptor.ImageAdapter$1.run(ImageAdapter.java:79)
at io.reactivex.internal.operators.completable.CompletableFromAction.subscribeActual(CompletableFromAction.java:34)
at io.reactivex.Completable.subscribe(Completable.java:1613)
at io.reactivex.internal.operators.completable.CompletableSubscribeOn$SubscribeOnObserver.run(CompletableSubscribeOn.java:64)
at io.reactivex.Scheduler$1.run(Scheduler.java:134)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:59)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:51)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)

非常感谢任何帮助。:)


如果你移除了.subscribeOn(Schedulers.newThread())会发生什么?错误提示说“方法调用应该在主线程中进行”,但是你告诉你的代码在一个新线程上订阅。或者也许是.subscribeOn(AndroidSchedulers.mainThread()),这可能是一样的... - JonasVautherin
1个回答

6
您正在从执行器线程加载图像,这是Picasso不允许的(如果您问我,这是一种选择,有更好的处理同步问题的方法,但现在就是这样)。您可以在此主题中查看此决定的详细信息:
“Picasso允许外部调用者调用into()而不是主线程是一个错误。这些方法在没有同步的情况下处理视图回收和取消,因此在Picasso 2.3中我们添加了检查。”
您有几个选项。如果您传递了Looper.getMainLooper(),则可以在UI线程中完成整个instantiateItem工作,或者您可以使用RequestCreator.get()方法而不是RequestCreator.into(),或者将您的Picasso工作封装在:
context.runOnUiThread(new Runnable() {
    @Override
    public void run() {
         // Can call RequestCreator.into here
    }
});

我最终使用了get()而不是into(),这样可以获取位图。 - Mightian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接