2017-01-28 3 views
3

Ce fut ma première question:Picasso + RxJava2: Appel de méthode devrait se produire à partir du thread principal

Je suis en train de montrer quelques images dans le AutoScrollViewPager. J'utilise Picasso pour réaliser la même chose. Cependant, j'aimerais faire la même chose avec Rxjava2 + Picasso. Je suis un peu nouveau dans ce concept de RxJava. Donc, si quelqu'un peut m'aider avec des détails si possible, pour convertir le code ci-dessous en RxJava, je l'apprécierais vraiment.

C'est ce que je fais dans onViewCreated()

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

Ceci est mon 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); 
} 

Comment puis-je convertir en un code RxJava? Toute aide serait appréciée.

C'est ce que j'essayé de faire

J'ai changé ImageAdapter un peu:

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

Mais cela, malheureusement, ne fonctionne pas et j'ai fini avec cette erreur:

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) 

Toute aide sera appréciée. :)

+0

si vous supprimez '.subscribeOn (ordonnanceurs .newThread()) '? L'erreur indique que "l'appel de méthode doit se produire à partir du thread principal", mais vous indiquez à votre code de vous inscrire sur un nouveau thread. Ou peut-être '.subscribeOn (AndroidSchedulers.mainThread())', qui pourrait être le même ... – JonesV

Répondre

3

Vous chargez l'image du fil d'exécuteur testamentaire, que Picasso ne permet pas (c'est de verser le choix si vous me demandez, il y a de meilleures façons de traiter les problèmes de synchronisation, mais c'est la façon dont il est maintenant) .

Vous pouvez voir les détails de cette décision 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.

Il y a plusieurs options pour vous. Vous pouvez faire tout le travail instantiateItem dans le thread d'interface utilisateur, si vous passez Looper.getMainLooper(), ou vous pouvez utiliser RequestCreator.get() méthode au lieu de RequestCreator.into(), ou envelopper votre Picasso travail avec:

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