Ustaw widoczność paska postępu po zakończeniu ładowania obrazu za pomocą biblioteki Glide


90

Cześć, chcę mieć pasek postępu dla obrazu, który będzie się pojawiał podczas ładowania obrazu, ale gdy ładowanie obrazu zostanie zakończone, chcę go wyłączyć. Wcześniej używałem do tego biblioteki Picassa. Ale nie wiem, jak go używać z biblioteką Glide. Wydaje mi się, że istnieje funkcja gotowa do użycia zasobów, ale nie wiem, jak jej użyć. Czy ktoś może mi pomóc?

Kod biblioteki Picassa

Picasso.with(mcontext).load(imgLinkArray.get(position).mUrlLink)
       .into(imageView, new Callback() {
           @Override
           public void onSuccess() {
               progressBar.setVisibility(View.GONE);
           }

           @Override
           public void onError() {
           }
        })
;

Jak mogę to zrobić z Glide?

Glide.with(mcontext).load(imgLinkArray.get(position).mUrlLink)
     .into(imageView);

Jestem w stanie załadować obraz za pomocą Glide, ale jak mogę napisać progressBar.setVisibility(View.GONE);gdzieś w kodzie, jeśli obraz zostanie załadowany?


2
Dlaczego zmieniłeś swoją bibliotekę? Picasso jest świetny.
tasomaniac

Poleciłbym również trzymać się Picassa, chyba że masz dobry powód do zmiany bibliotek
Chris

Odpowiedzi:


229

Pytanie jest dość stare i nie wiem, jak wyglądała sytuacja z szybowaniem w tamtych czasach, ale teraz można to łatwo zrobić ze słuchaczem (nie tak, jak proponowano w odpowiedzi wybranej jako poprawna).

progressBar.setVisibility(View.VISIBLE);
Glide.with(getActivity())
     .load(args.getString(IMAGE_TO_SHOW))
     .listener(new RequestListener<String, GlideDrawable>() {
         @Override
         public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
             return false;
         }

         @Override
         public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
             progressBar.setVisibility(View.GONE);
             return false;
         }
     })
     .into(imageFrame)
;

Zwracasz wartość true, jeśli chcesz samodzielnie obsługiwać takie rzeczy, jak animacje, a false, jeśli chcesz, aby szybka poradziła sobie z nimi za Ciebie.


13
Rozważ również ukrycie tego, progressBarw onExceptionprzeciwnym razie będzie się obracał w nieskończoność, dając fałszywą nadzieję. Raz onExceptionnazywa się Glide nie zrobi nic poza ustawieniem tego, co zostało przekazane .error().
TWiStErRob

2
Może to spowodować NullPointerException, jeśli opuścisz fragment / działanie przed załadowaniem obrazu.
aProperFox

1
Nie pobudzam cię do tworzenia słuchaczy z klasy wewnętrznej, tylko najbardziej zwięzły sposób pokazania narzędzia do wykonania zadania.
Jarosław

1
Jasne, rozwiązałem to, dodając wywołanie onDestroyVIew () przed super wywołaniem, aby powiedzieć Glide.clear (yourImageView)
aProperFox

7
UWAGA: .listenernależy zadzwonić wcześniej.into()
Ahmed Mostafa

31

Jeśli chcesz to zrobić w KOTLINIE, możesz spróbować w ten sposób:

    Glide.with(context)
            .load(url)
            .listener(object : RequestListener<Drawable> {
                override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
                    //TODO: something on exception
                }
                override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
                    Log.d(TAG, "OnResourceReady")
                    //do something when picture already loaded
                    return false
                }
            })
            .into(imgView)

5
Należy również zaimportować Target:import com.bumptech.glide.request.target.Target
Gibolt,

@Gibolt to mnie męczyło przez 10 minut prosto
johnrao07,

17

Moja odpowiedź została oparta na przestarzałych interfejsach API. Zobacz tutaj, aby uzyskać bardziej aktualną odpowiedź.


.listener()jest lepsza, ponieważ otrzymasz więcej informacji o swoim obciążeniu (model, pamięć podręczna, ...), więc łatwiej jest zdecydować o bardziej niestandardowej logice. RequestListenerjest również bardziej stabilny, a nadpisanie którego Targetutworzenie nie przyniesie korzyści z przyszłych poprawek. Możesz także łatwo utworzyć plik, VisibilityListener<T, R>który będzie można ponownie wykorzystać w różnych kontekstach.
TWiStErRob

10

Wyjątkiem jest postawienie warunku ponownego pokazania ProgressBar

 Glide.with(context)
    .load(image_url)
    .listener(new RequestListener<String, GlideDrawable>() {
        @Override
        public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
            if(e instanceof UnknownHostException)
                progressBar.setVisibility(View.VISIBLE);
            return false;
        }

        @Override
        public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
            progressBar.setVisibility(View.GONE);
            return false;
        }
    })
    .into(imageView);

7

Powyższe rozwiązanie działa również dla mnie całkiem dobrze, ale kiedy używam asBitmap () do pobierania obrazu. To nie działa.

Musimy użyć BitmapImageViewTarget

Glide.with(this) .load(imageURL)
 .asBitmap()
 .placeholder(R.drawable.bg)
 .into(new BitmapImageViewTarget(imageView) {
            @Override
            public void onResourceReady(Bitmap  drawable, GlideAnimation anim) {
                super.onResourceReady(drawable, anim);
                progressBar.setVisibility(View.GONE);
            }
        });

Zobacz mój komentarz: stackoverflow.com/questions/26054420/… . Ta odpowiedź jest dobrym przykładem tego, co tam powiedziałem.
TWiStErRob

7

GlideDrawable są przestarzałe, użyj prostego Drawable

RequestOptions requestOptions = new RequestOptions();
requestOptions.placeholder(R.drawable.placeholder);
requestOptions.error(R.drawable.error);

Glide.with(getContext())
                 .setDefaultRequestOptions(requestOptions)
                 .load(finalPathOrUrl)
                 .listener(new RequestListener<Drawable>() {
                        @Override
                        public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
                            progressBar.setVisibility(View.GONE);
                            return false;
                        }

                        @Override
                        public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
                            progressBar.setVisibility(View.GONE);
                            return false;
                        }
                    })
                 .into(mImageView);

4

W Kotlinie możesz zrobić jak poniżej

Glide.with(context)
            .setDefaultRequestOptions(RequestOptions().placeholder(R.drawable.ic_image_placeholder).error(R.drawable.ic_image_placeholder))
            .load(url)
            .listener(object : RequestListener<Drawable>{
                override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
                    return false
                }

                override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
                    return false
                }

            })
            .into(imageView)

2
  1. W xml weź pasek postępu z wysokością i szerokością (match_parent).
  2. Przed wywołaniem poniżej wspomnij o metodzie, ustaw widoczność paska postępu Visible.

    public void setImageWIthProgressBar(Context context, final ImageView imageView, String imageUrl, final ProgressBar progressBar) {
    
            Glide.with(context)
                    .load(imageUrl)
                    .listener(new RequestListener<String, GlideDrawable>() {
                        @Override
                        public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
                            progressBar.setVisibility(View.GONE);
                            return false;
                        }
    
                        @Override
                        public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
                            progressBar.setVisibility(View.GONE);
                            return false;
                        }
                    })
                    .into(imageView);
    
        }//setImageWIthProgressBar
    

Czym różni się Twoja odpowiedź od stackoverflow.com/a/31675796/3812404 ? Punkt 1 również nie jest potrzebny.
HariRam

2

Aktualizacja:

Glide.with(this)
            .load(imageUrl)
            .listener(new RequestListener<Drawable>() {
                @Override
                public boolean onLoadFailed(@Nullable final GlideException e,
                                            final Object model, final Target<Drawable> target,
                                            final boolean isFirstResource) {
                    showProgress(false);

                    mNoContentTextView.setVisibility(View.VISIBLE);

                    return false;
                }

                @Override
                public boolean onResourceReady(final Drawable resource, 
                                               final Object model, 
                                               final Target<Drawable> target, 
                                               final DataSource dataSource, 
                                               final boolean isFirstResource) {
                    showProgress(false);

                    mNoContentTextView.setVisibility(View.GONE);
                    mContentImageView.setImageDrawable(resource);

                    return false;
                }
            })
            .into(mContentImageView);

Powiedz, jeśli masz już onResourceReady, jaki jest pożytek z „into”? Czy nie mogę po prostu używać samego słuchacza? Jeśli tak, jak mogę rozpocząć ładowanie bez „do?”
programista Androida

Programista @android, jak wiem, można używać bez
Narek Hayrapetyan

jest do spróbowania
Narek Hayrapetyan

Ale jeśli nie używam słowa „into”, myślę, że to ostrzega.
programista Androida

1

Jak to zrobiłem. krótszy sposób, czystszy kod

przykład:

progress_bar.visibility = View.VISIBLE

profilePicturePath?.let {
    GlideApp.with(applicationContext)
        .load(CloudStorage.pathToReference(it))
        .placeholder(R.drawable.placeholder)
        .listener(GlideImpl.OnCompleted {
            progress_bar.visibility = View.GONE
        })
    .into(profile_picture)
} ?: profile_picture.setImageResource(R.drawable.placeholder)

stosowanie:

GlideImpl.OnCompleted {
    // completed
}

po prostu przejdź GlideImpl.OnCompleted { }do Glide's.listener()

GlideImpl.kt, która akceptuje RequestListener Glide

import android.graphics.drawable.Drawable
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target

object GlideImpl {

    object OnCompleted : RequestListener<Drawable> {

        private lateinit var onComplete: () -> Unit

        operator fun invoke(onComplete: () -> Unit): OnCompleted {
            OnCompleted.onComplete = { onComplete() }
            return this
        }

        override fun onResourceReady(
            resource: Drawable?,
            model: Any?,
            target: Target<Drawable>?,
            dataSource: DataSource?,
            isFirstResource: Boolean
        ): Boolean {
            onComplete()
            return false
        }

        override fun onLoadFailed(
            e: GlideException?,
            model: Any?,
            target: Target<Drawable>?,
            isFirstResource: Boolean
        ): Boolean {
            onComplete()
            return false
        }
    }
}

i to jest to!


0

Droga Kotlina

Glide.with(context)
                .load(image_url)
                .listener(object : com.bumptech.glide.request.RequestListener<Drawable> {
                    override fun onLoadFailed(
                        e: GlideException?,
                        model: Any?,
                        target: Target<Drawable>?,
                        isFirstResource: Boolean
                    ): Boolean {
                        return false
                    }

                    override fun onResourceReady(
                        resource: Drawable?,
                        model: Any?,
                        target: Target<Drawable>?,
                        dataSource: DataSource?,
                        isFirstResource: Boolean
                    ): Boolean {
                        img_product_banner.visibility = View.VISIBLE
                        return false
                    }

                }).placeholder(R.drawable.placeholder)
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .into(img_product_banner)

-1

To najlepsza odpowiedź, ponieważ nie wykorzystuje żadnych hacków, takich jak ustawianie widoczności, aby uzyskać pożądane wyniki.

Pobierz plik gif progressbar, wywołaj go progressbargifi umieść w folderze do rysowania.

        Glide.with(ctx)
            .load(url)
            .thumbnail(Glide.with(ctx).load(R.drawable.progressbargif))
            .diskCacheStrategy(DiskCacheStrategy.SOURCE)
            .error(R.drawable.image_unavailable)
            .crossFade(200)
            .into(iv);

Po załadowaniu obrazu adresu URL miniatura znika. Miniatura znika natychmiast po załadowaniu buforowanego obrazu.


4
Myślę, że to dlatego, że nie odpowiada na pytanie: OP ma już spinner, z którego jest zadowolony. Jest to również sprzeczne z najlepszymi praktykami Androida: używanie GIF-a jako spinnera trwa tak 90 lat i znacznie zwiększa rozmiar APK; a umieszczenie GIF-a w drawablejest samo w sobie złe, ponieważ nie jest ładowane przez framework, powinno być w rawlub assetsco najwyżej. Nie ma nic złego w zmianie widoczności, gdy w Twojej aplikacji zachodzą zdarzenia, Android jest do tego zaprojektowany.
TWiStErRob

1
Użytkownik zobaczy również puste miejsce podczas dekodowania GIF-a, jest to asynchroniczne i nie natychmiastowe. RESULTBuforujesz również pasek postępu, co oznacza, że ​​ładowanie zajmie trochę czasu. SOURCEGIFy powinny być najlepiej buforowane w celu zwiększenia wydajności; ale ponieważ jest to plik lokalny, pamięć podręczna NONEnie może powielać go na dysku, zajmując jeszcze więcej miejsca dla użytkownika.
TWiStErRob
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.