엄코딩의 개발 일지

Fabric에서 오류를 확인하던 도중에


Glide  관련 You cannot start a load for a destroyed activity 에러를 확인했다.

에러 로그는 다음과 같다.


Fatal Exception: java.lang.IllegalArgumentException: You cannot start a load for a destroyed activity

       at com.bumptech.glide.manager.RequestManagerRetriever.b(SourceFile:302)

       at com.bumptech.glide.manager.RequestManagerRetriever.a(SourceFile:127)

       at com.bumptech.glide.Glide.a(SourceFile:632)

       at com.likealocal.wenwo.dev.wenwo_android.utils.glide.GlideApp.a(SourceFile:84)

       at com.likealocal.wenwo.dev.wenwo_android.ui.begin.SplashActivity.onAdvertisementSuccess(SourceFile:383)

       at com.likealocal.wenwo.dev.wenwo_android.http.protocol.AdvertisementRequest$send$1.accept(SourceFile:43)

       at com.likealocal.wenwo.dev.wenwo_android.http.protocol.AdvertisementRequest$send$1.accept(SourceFile:23)

       at io.reactivex.internal.observers.ConsumerSingleObserver.a(SourceFile:61)

       at io.reactivex.internal.operators.single.SingleObserveOn$ObserveOnSingleObserver.run(SourceFile:81)

       at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run(SourceFile:109)

       at android.os.Handler.handleCallback(Handler.java:790)

       at android.os.Handler.dispatchMessage(Handler.java:99)

       at android.os.Looper.loop(Looper.java:164)

       at android.app.ActivityThread.main(ActivityThread.java:7002)

       at java.lang.reflect.Method.invoke(Method.java)

       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:441)

       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1408)


해당 에러 내용은 액티비티가 destroy되고 load를 시작할 수 없다는 내용인데,

해결 방법은 무엇일까? 


https://github.com/bumptech/glide/issues/803 Glide 깃헙에도 해당 에러를 가지고 얘기가 많았다.

하지만 위 링크에서는 내가 원하는 정확한 해답을 찾을 수 없었다.

구글링을 통해 문제 상황을 검색하던 도중 내가 원하던 답을 찾을 수 있었다.


https://stackoverflow.com/questions/31964737/glide-image-loading-with-application-context/32887693#32887693


문제 상황 인식


해당 액티비티가 종료되고 나서 Glide load를 진행할 수 없다.


해결 방법


1. Fragment의 경우를 생각해보면 이해하기 쉽다.

프레그먼트의 onCreateView 메소드에서 Glide.with~를 사용하는 경우,

사용자가 Back key를 눌렀을 경우 어떻게 될까?

해당 이미지가 5MB인 경우 with(getActivity.getApplicatonContext())를 사용하는경우 5MB의 데이터가 모두 다운로드되어 디코딩되고 캐싱되고, 해당 ImageView에 세팅된다. 그리고 이것은 Glide의 garbage collect된다.


2. with((Fragment)this) 를 사용하면 Glide는 Fragment의 생명주기를 구독하고, Fragment가 stop되자마자 해결되지 않은 모든 request를 멈추어야 한다. 그리고 destroy될 때 보류중인 요청은 모두 삭제된다. 즉, 이미지 다운로드가 중단될 것이고, 종료된 프레그먼트에서 더이상 리소스가 사용되지 않을 것이다.


3.with(getActivity())를 사용하면 Glide는 Activity의 생명주기를 구독하고, 위(Fragment)와 같은 일이 일어날 것이다. 하지만 Activity의 활동이 중지되거나 소멸된 경우에만 발생할 것이다.


4. 가장 좋은 방법은 사용 가능한 request들의 완료를 피하기 위해 가장 가까운 context/fragment를 사용하는 것이다. 또한, load를 수동으로 중지하는 방법도 있다. Glide.clear(ImageView|Target)


마지막으로 중요한 점은,

with(this)가 가능한 경우 이 방법을 사용하고, Adapter의 경우 RequestManger를 인자로 받는 것을 추천.