Picasso + RxJava2: Method call should happen from the main thread

匿名 (未验证) 提交于 2019-12-03 00:56:02

问题:

This was my initial Question:

I am trying to show a few images in the AutoScrollViewPager. I am using Picasso to achieve the same. However, I would like to do the same with using Rxjava2 + Picasso. I am kinda new to this RxJava concept. So if anyone can help me with details if possible, to convert the below into RxJava code, I would really appreciate it.

This is what I do in onViewCreated()

imageAdapter = new ImageAdapter(getActivity()); autoScrollViewPager.setAdapter(imageAdapter); autoScrollViewPager.setCurrentItem(imageAdapter.getCount() - 1); autoScrollViewPager.startAutoScroll(); autoScrollViewPager.setInterval(4000); 

This is my 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); } 

How can I convert this into RxJava code? Any help will be appreciated.

This is what I tried to do

I changed my ImageAdapter a bit:

@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);                             }                         });        }    }); } 

But this, unfortunately, did not work and I ended up with this error:

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) 

Any help will be appreciated. :)

回答1:

You are loading the image from the executor thread, which Picasso doesn't allow (this is pour choice if you ask me, there are better ways to deal with sync issues, but that's the way it is now).

You can see the details of this decision in this thread:

It was a mistake from Picasso to allow external callers to invoke into() other than the main thread. Those methods deal with view recycling and canceling without synchronization, hence in Picasso 2.3 we added the checks.

There are several options for you. You can do the whole instantiateItem work in the UI thread, if you pass Looper.getMainLooper() in, or you can use RequestCreator.get() method instead of RequestCreator.into(), or wrap your Picasso work with:

context.runOnUiThread(new Runnable() {     @Override     public void run() {          // Can call RequestCreator.into here     } }); 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!