Picasso + RxJava2: вызов метода должен происходить из основного потока

Это был мой первоначальный вопрос:

Я пытаюсь показать несколько изображений в файле 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)

Любая помощь будет оценена. :)


person Kamil Kamili    schedule 28.01.2017    source источник
comment
Что если удалить .subscribeOn(Schedulers.newThread())? Ошибка говорит, что вызов метода должен происходить из основного потока, но вы указываете своему коду подписаться на новый поток. Или, может быть, .subscribeOn(AndroidSchedulers.mainThread()), что может быть тем же самым...   -  person JonasVautherin    schedule 30.01.2017


Ответы (1)


Вы загружаете изображение из потока исполнителя, что Пикассо не разрешает (это выбор заливки, если вы спросите меня, есть лучшие способы решения проблем с синхронизацией, но сейчас это так).

Вы можете ознакомиться с подробностями этого решения в этой ветке:

Со стороны Пикассо было ошибкой разрешить внешним вызывающим объектам вызывать метод into(), отличный от основного потока. Эти методы имеют дело с перезапуском и отменой просмотра без синхронизации, поэтому в Picasso 2.3 мы добавили проверки.

Есть несколько вариантов для вас. Вы можете выполнить всю работу instantiateItem в потоке пользовательского интерфейса, если вы передадите Looper.getMainLooper(), или вы можете использовать метод RequestCreator.get() вместо RequestCreator.into(), или обернуть свою работу Picasso с помощью:

context.runOnUiThread(new Runnable() {
    @Override
    public void run() {
         // Can call RequestCreator.into here
    }
});
person Maxim    schedule 17.03.2017
comment
В итоге я использовал get() вместо into(), который возвращает растровое изображение, - person Mightian; 13.11.2019