Может очереди Пикассо для меня?

вот критический момент, который я не знаю относительно поведения Пикассо.

представьте, что вы, скажем, показываете слайд-шоу из десяти элементов. Скажем, они на экране по десять секунд.

идеальным поведением было бы следующее: В начале слайд-шоу Я просто выполняю следующее:

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 )

и, на самом деле, Пикассо сделал бы это по одному, в очереди.

каково поведение Пикассо, Если я скажу ему предварительно согреться 10 адресов сразу?

возможно ли, чтобы Пикассо делал вещи только по одному за раз, по порядку - есть ли такой вариант?

(другие возникающие вопросы: можете ли вы отменить очередь или ...?)


фреска

благодаря удивительному ответу @alicanozkara на этой странице Я впервые узнал о

https://github.com/facebook/fresco

(13k звезд) к лучшему или худшему я думаю, что Пикассо эра, вероятно, закончилась.

4 ответов


используя только Picasso, Я думаю, что вы можете достичь, это:

1) загрузить все изображения асинхронно в кэше с помощью fetch() вот так:

Picasso.with(context).load(URL).fetch();

вы также можете добавить приоритет для изображений, которые вы хотите загрузить раньше: (возможно, упомянуть высокий приоритет для первых нескольких изображений слайда)

Picasso.with(context)
.load(URL)
.priority(Picasso.Priority.HIGH) // Default priority is medium
.fetch();

2) об отмене очереди, вы можете добавить общие tag() к вашим изображениям и вы можете пауза / отмена / возобновление в любое время!

private static final Object TAG_OBJECT = Object();

Picasso.with(context)
.load(URL)
.tag(TAG_OBJECT) 
// can be any Java object, must be the same object for all requests you want to control together.

тогда мы можем управлять тегом так:

Picasso.with(context)
.pauseTag(TAG_OBJECT)
//.resumeTag(TAG_OBJECT)
//.cancelTag(TAG_OBJECT)

3) еще одна важная вещь, которую я хотел бы предложить, - это когда вы предварительно загружаете свои изображения, только сохраняете их в свой дисковый кэш и загружаете их в свой кэш памяти только во время отображения. Это предотвратит промывку других важных изображений из кэша памяти:

Picasso  
.with(context)
.load(URL)
.memoryPolicy(MemoryPolicy.NO_STORE) //Skips storing the final result into memory cache.
.fetch()

4) для последовательной загрузки изображений в очереди, вы можете пройти свой собственный ExecutorService (SingleThreadExecutor в вашем случае) с помощью executor(ExecutorService) способ, присутствующий в Picasso.Builder

вы даже можете изменить размер кэша диска с помощью downloader(Downloader) способ и кэш-памяти с помощью memoryCache(Cache) метод, как нашли в Picasso.Builder класса.

Другие Удивительные Библиотеки:

скольжения

фреска


возможно ли, чтобы Пикассо делал вещи только по одному за раз, по порядку - есть ли такой вариант?

Я не уверен, что это можно сделать с самим Пикассо, но, по крайней мере, RxJava может быть применима к этой проблеме.

я опубликую фрагмент кода с комментариями:

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

}

это будет вывод в logcat:

enter image description here

Это идеальный сценарий, когда каждое изображение получает успешно загружен. Этот фрагмент не обрабатывает случай, когда одно из изображений не может быть загружено. Как только Пикассо не сможет загрузить один из них - поток будет прерван и onError() будет называться.


В Пикассо.Builder вы можете дать конкретный ExecutorService: https://square.github.io/picasso/2.x/picasso/com/squareup/picasso/Picasso.Builder.html#executor-java.util.concurrent.ExecutorService-

Если вы даете новый исполнитель одного потока, https://developer.android.com/reference/java/util/concurrent/Executors.html#newSingleThreadExecutor(), Picasso будет загружать все ваши изображения по одному за раз.


нет исправления с одним методом вызова для цепочки с Пикассо, но вы можете создать помощника следующим образом:

public PicassoSlideshow {

    private static PicassoSlideshow instance;
    private WeakReference<ImageView> view;
    private Handler handler;
    private int index;
    private String[] urls;
    private long delay;

    private PicassoSlideshow() {
       //nothing
    }

    public static PicassoSlideshow with(ImageView view) {
        if (instance == null) {
            instance = new PicassoSlideshow();
        }
        instance.setView(view);
    }

    private void setView(ImageView view) {
        this.view = new WeakReference<>(view);
    }

    //Note: I'm only suggesting varargs because that's what you seem to have in the question  
    public void startSlideshow(long interval, String... urls) {
        if (handler == null) {
            handler = new Handler();
        }
        index = 0;
        this.urls = urls;
        delay = interval;
        displayNextSlide();
    }

    private void displayNextSlide() {
        //display one 
        ImageView iv = view.get();
        if (iv != null) {
            Picasso.with(iv.getContext())
                   .load(urls[index]).into(iv);
            index++;
            if (index < urls.length) {
                //preload next
                Picasso.with(iv.getContext()).fetch(urls[index]); 
                //on timer switch images
                handler.postDelayed(PicassoSlideshow::displayNextSlide, delay); 
            }
        }
    }

}

использование:

PicassoSlideshow.with(view).startSlideshow(10000, url1, url2, url3, url9);

обратите внимание, я только что написал это с верхней части головы, в то время как моя IDE аннулирует свои кэши, поэтому вам может потребоваться немного настроить его