Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Picasso queue for me?

Here's a critical point I don't know concerning the behavior of Picasso.

Imagine you are, say, showing a slide-show of ten items. Say, they are on-screen for ten seconds each.

The ideal behavior would be this: at the start of the slide show, I simply perform following:

picasso.get( url1 )
picasso.get( url2 )
picasso.get( url3 )
picasso.get( url4 )
picasso.get( url5 )
picasso.get( url6 )
picasso.get( url7 )
picasso.get( url8 )
picasso.get( url9 )
picasso.get( url10 )

And, in fact, Picasso would do those one at a time, in a queue.

What is the behavior of Picasso, if I tell it to pre-warm 10 urls all at once?

Is it possible to have Picasso do things only one at a time, in order - is there such an option?

(Other questions arising are, can you cancel the queue, or ...?)


Fresco

thanks to an amazing answer @alicanozkara on this page I learned for the first time about

https://github.com/facebook/fresco

(13k stars) for better or worse I think the Picasso era is probably over.

like image 304
Fattie Avatar asked Sep 09 '17 14:09

Fattie


People also ask

Is Picasso better than Glide?

Glide's loading times are faster and it uses a small amount of memory for cache, but the library size is quite large. It, too, is easy to implement. Glide might be a better alternative to Picasso when memory footprint is less of a concern or more and larger images need to be processed.


2 Answers

Is it possible to have Picasso do things only one at a time, in order - is there such an option?

I am not sure it can be done with Picasso itself, but at least RxJava may be applicable to this problem.

I'll post a snippet of code with comments:

public class MainActivity extends AppCompatActivity {

    public static final List<String> urlList = Arrays.asList(
            "http://i.imgur.com/UZFOMzL.jpg",
            "http://i.imgur.com/H981AN7.jpg",
            "http://i.imgur.com/nwhnRsZ.jpg",
            "http://i.imgur.com/MU2dD8E.jpg"
    );

    List<Target> targetList = new ArrayList<>();
    List<Completable> completables = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final long start = System.currentTimeMillis();
        // emit each url separately
        Observable.fromIterable(urlList)
                // flatmap to an Observable<Completable>
                .flatMap(url ->
                        // fromCallable ensures that this stream will emit value as soon as it is subscribed
                        // Contrary to this, Observable.just() would emit immediately, which we do not want
                        Observable.fromCallable(() ->
                                // We need to know whether either download is
                                // completed or no, thus we need a Completable
                                Completable.create(e -> {
                                    Target target = new Target() {
                                        @Override
                                        public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                                            Log.i("vvv", "downloaded " + url + ", " + (System.currentTimeMillis() - start));
                                            e.onComplete();
                                        }

                                        @Override
                                        public void onBitmapFailed(Drawable errorDrawable) {
                                            e.onError(new IllegalArgumentException("error happened"));
                                        }

                                        @Override
                                        public void onPrepareLoad(Drawable placeHolderDrawable) {

                                        }
                                    };
                                    // need to keep a strong reference to Target, because Picasso holds weak reference
                                    targetList.add(target);
                                    Picasso.with(MainActivity.this)
                                            .load(url)
                                            .into(target);
                                })))
                // collecting all Completables into a list
                .collectInto(completables, List::add)
                // flatmap-ing this Observable into a Completable, concatenating each completable
                // to next, thus they will be downloaded in order
                .flatMapCompletable(Completable::concat)
                // clearing the strong reference we retained earlier
                .doFinally(() -> {
                    targetList.clear();
                    targetList = null;
                })
                .subscribe(
                        () -> Log.i("vvv", "done: " + (System.currentTimeMillis() - start)),
                        throwable -> Log.e("vvv", "err " + throwable.getMessage()
                        ));
    }

}

This will be the output in logcat:

enter image description here

This is the ideal case scenario, when each image gets successfully loaded. This snippet doesn't handle the case, when one of images cannot be loaded. As soon as Picasso fails to load one of them - the stream will be interrupted and onError() would be called.

like image 161
azizbekian Avatar answered Nov 10 '22 17:11

azizbekian


In Picasso.Builder you can give a specific ExecutorService: https://square.github.io/picasso/2.x/picasso/com/squareup/picasso/Picasso.Builder.html#executor-java.util.concurrent.ExecutorService-

If you give a new single thread executor, https://developer.android.com/reference/java/util/concurrent/Executors.html#newSingleThreadExecutor(), Picasso will download all your images one at a time.

like image 21
Gut Avatar answered Nov 10 '22 17:11

Gut