안드로이드 글라이드(Glide) IllegalArgumentException ~ You cannot start a load for a destroyed activity
안드로이드 이미지 로드 대표 라이브러리라고 해도 과언이 아닐 만큼 유명한 라이브러리
글라이드 Glide
글라이드 라이브러리를 사용하다보면 가끔 파이어베이스 크레쉬 리포트에 IllegalArgumentException 크레쉬가 뜨는 걸 확인 할 수 있는데, 이는 글라이드 라이브러리 내에 null체크 하는 과정에서 생기는 exception이다.
라고 나는 생각이 든다..
이를 확인할 수 있는 코드가 글라이드 라이브러리 내에서 확인을 할 수 있는데
RequestManagerRetriever 클래스에서
@Nullable
private Activity findActivity(@NonNull Context context) {
if (context instanceof Activity) {
return (Activity) context;
} else if (context instanceof ContextWrapper) {
return findActivity(((ContextWrapper) context).getBaseContext());
} else {
return null;
}
}
코드를 통해 Activity인지와 null체크를 하는데, return이 된다면 앱이 죽지 않고, 글라이드가 아마 동작을 하지 않을 것이다. 아니면 혹은 미리 설정해둔 에러 이미지가 나온다든가..?
문제는 이 아래 메소드이다.
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private static void assertNotDestroyed(@NonNull Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed()) {
throw new IllegalArgumentException("You cannot start a load for a destroyed activity");
}
}
if문의 마지막에 activity.isDestroyed에서 true일 경우 바로 IllegalArgumentExecption을 던지는데 이 때문에 앱이 죽고 크레쉬 리포트에는 "You cannot start a load for a destroyed activity"로그가 찍히는 것이 아닐까 싶다.
그런데 지금 다시 보니 TargetApi 어노테이션을 보았는데, 저 해당 버전에서만 저 메소드를 타는게 아닌가..?
심지어 저 안드로이드 버전을 사용하는 사람이 아직도 있는가...
결국 activity.isDestroyed가 중요하지 않을까
이를 방어하기 위해서는 위 null체크구문을 타기 전에 미리 Activity인지와 null체크를 해주고
if(!activity.isDestroyed && ...) {
...
}
위와 같이 !isDestroyed 일 때 글라이드를 동작시켜주면 되지 않을 까 싶다. 이를 위해서는 글라이드를 공통 클래스 혹은 메소드로 빼서 관리를 해야할까 싶다.
glideRequestManager = GlideApp.with(this);
그런데 이는 단순한 방어로직으로 생각이 들며, activity 혹은 context를 받는 glideRequestManager을 만들어서 글라이드를 작동시키면 되지 않을까 싶다.