Glide.withに渡す引数による処理の違いについて
Androidの画像読み込みライブラリの Glide で画像を読み込む際に、 Glide.with
に渡す引数による処理の違いについて書きます。
Glide.withの処理を追いかける
Glide.with
では以下のように getRetriever(Context)
を使って取得した RequestManagerRetriever
の get
メソッドに with
の仮引数を渡して、最終的に RequestManager
を取得しています。
この流れは仮引数の型が Activity
や View
の場合も同様です。
public static RequestManager with(@NonNull Context context) { return getRetriever(context).get(context); }
private static RequestManagerRetriever getRetriever(@Nullable Context context) { ... return Glide.get(context).getRequestManagerRetriever(); }
RequestManager を生成するまで
RequestManagerRetriever#get
には Glide.with
と同じく Context
やActivity
, View
など様々な引数をとるメソッドが定義されています。
まずはじめに、 ApplicationContext
を指定した場合の処理を見ていきます。 get(Context)
のコードは以下のようになっており、 FragmentActivity
や Activity
などにキャストできる場合はキャストしてから再度 get
を呼び出しています。
ApplicationContext
の場合は getApplicationManager(Context)
が呼ばれ、その中で RequestManager
が作成されます。
@NonNull public RequestManager get(@NonNull Context context) { if (context == null) { ... } else if (Util.isOnMainThread() && !(context instanceof Application)) { if (context instanceof FragmentActivity) { return get((FragmentActivity) context); } else if (context instanceof Activity) { return get((Activity) context); } else if (context instanceof ContextWrapper && ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) { return get(((ContextWrapper) context).getBaseContext()); } } return getApplicationManager(context); }
private RequestManager getApplicationManager(@NonNull Context context) { ... if (applicationManager == null) { Glide glide = Glide.get(context.getApplicationContext()); applicationManager = factory.build( glide, new ApplicationLifecycle(), new EmptyRequestManagerTreeNode(), context.getApplicationContext()); } ... return applicationManager; }
次に Activity
を指定した場合や、Context
が Activity
にキャストできた場合の処理について見ていきます。
バックグラウンドスレッドで呼び出された場合は、先ほどみた ApplicationContext
を指定した時と同じ処理が呼ばれます。
そうでない場合は Factory
から RequestManager
を生成します。生成したインスタンスは RequestManager
を管理するための Fragment
で保持されています。
getRequestManagerFragment
では、 1つの FragmentManager
に対して1つの RequestManagerFragment
が保持されるように処理が行われています。
public RequestManager get(@NonNull Activity activity) { if (Util.isOnBackgroundThread()) { return get(activity.getApplicationContext()); } else { assertNotDestroyed(activity); android.app.FragmentManager fm = activity.getFragmentManager(); return fragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity)); } }
private RequestManager fragmentGet( @NonNull Context context, @NonNull android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible) { RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible); RequestManager requestManager = current.getRequestManager(); if (requestManager == null) { Glide glide = Glide.get(context); requestManager = factory.build(glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context); current.setRequestManager(requestManager); } return requestManager; }
Fragment
や FragmentActivity
, androidxの Fragment
の場合も FragmentManager
を取得して Activity
の時と同様の処理が行われます。
また、 View
の場合は View#getContext
を元に Activity
とその配下のすべての Fragment
を取得して、 View
が属する Fragment
や Activity
を探し出しています。
RequestManagerRetriever#get(View)
RequestManagerRetriever#findSupportFragment
RequestManagerを生成した後
ここまでで Glide.with
の返り値である RequestManager
を生成するタイミングが特定でき、以下のように大きく2パターンの RequestManager
が生成されることがわかりました。
ApplicationContextまたはバックグラウンドスレッド上で生成
factory.build( glide, new ApplicationLifecycle(), new EmptyRequestManagerTreeNode(), context.getApplicationContext() );
それ以外
factory.build( glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context );
factory
Factoryは、GlideBuilder
で指定することができます。指定しない場合は RequestManagerRetriever.DEFAULT_FACTORY
が使用されます。
RequestManagerRetriever.DEFAULT_FACTORY
Lifecycleによる違い
RequestManager
を生成する処理で、注目したいことは Lifecycle
の違いです。
ApplicationLifecycle
は常にアクティブなライフサイクルとなっています。
一方、 RequestManagerFragment#getGlideLifecycle()
は Fragment
のライフサイクルと等しくなります。
Glideでは、この Lifecycle
に応じて画像読み込みリクエストの開始/中断などが行われます。例えば、 Fragment
で画像を読み込みリクエストを開始し、読み込み完了前に Fragment
が破棄された時にリクエストを中断するということが可能です。
バックグラウンドスレッドでリクエストを行う時には、 Activity
や Fragment
のライフサイクルに応じてリクエストを止めたくないケースであることが想定されるため、 ApplicationLifecycle
で実行させているということが分かりました。
まとめ
Glide.with
に渡す引数によって、画像読み込み処理のライフサイクルが変わります。
Activity
や Fragment
と同じライフサイクルで画像を読み込めば十分な時には、 Activity
や Fragment
, View
を渡すと端末のリソースが無駄に使用されることがなくなります。そうでない場合は、ApplicationContext
を渡したり、バックグラウンドスレッド上で Glide.with
を呼び出す必要があります。