Google I/O 2017 で Android Architecture Components が公開されました。
簡単に Lifecycle の Observer を作成できます。どうやって実現しているのでしょうか?
試しに簡単な LifecycleObserver を作ってみましょう。
class MyActivity extends LifecycleActivity { static class MyLifecycleObserver implements LifecycleObserver { private static final String TAG = MyLifecycleObserver.class.getSimpleName(); @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) void onResume() { Log.d(TAG, "onResume"); } } void onCreate() { getLifecycle().addObserver(new MyLifecycleObserver()); } }
APT で生成された実装は以下です。
// 同一パッケージ public class MyActivity_MyLifecycleObserver_LifecycleAdapter implements GenericLifecycleObserver { final MyActivity.MyLifecycleObserver mReceiver; MyActivity_MyLifecycleObserver_LifecycleAdapter(MyActivity.MyLifecycleObserver receiver) { this.mReceiver = receiver; } @Override public void onStateChanged(LifecycleOwner owner, Lifecycle.Event event) { if (event == Lifecycle.Event.ON_RESUME) { mReceiver.onResume(); } if (event == Lifecycle.Event.ON_CREATE) { mReceiver.onCreate(); } } public Object getReceiver() { return mReceiver; } }
上記はとてもシンプルですね。分かりやすいです。では LifecycleRegistry#addObserver
を追っていきます。
// in : LifecycleRegistry @Override public void addObserver(LifecycleObserver observer) { ObserverWithState observerWithState = new ObserverWithState(observer); mObserverSet.putIfAbsent(observer, observerWithState); observerWithState.sync(); }
なるほどなるほど。では ObserverWithState
の中へ。
// in : LifecycleRegistry class ObserverWithState { private State mObserverCurrentState = INITIALIZED; private GenericLifecycleObserver mCallback; ObserverWithState(LifecycleObserver observer) { mCallback = Lifecycling.getCallback(observer); } }
GenericLifecycleObserver
は自分では実装していませんね。APT で作成したクラスから取るのでしょう。では Lifecycling#getCallback
へ。
// in : LifecycleRegistry @NonNull static GenericLifecycleObserver getCallback(Object object) { if (object instanceof GenericLifecycleObserver) { return (GenericLifecycleObserver) object; } ...
違いますね。次です。
// in : LifecycleRegistry //noinspection TryWithIdenticalCatches try { final Class<?> klass = object.getClass(); Constructor<? extends GenericLifecycleObserver> cachedConstructor = sCallbackCache.get( klass); if (cachedConstructor != null) { return cachedConstructor.newInstance(object); } cachedConstructor = getGeneratedAdapterConstructor(klass); if (cachedConstructor != null) { sCallbackCache.put(klass, cachedConstructor); if (!cachedConstructor.isAccessible()) { cachedConstructor.setAccessible(true); } return cachedConstructor.newInstance(object); } else { sCallbackCache.put(klass, sREFLECTIVE); } return new ReflectiveGenericLifecycleObserver(object); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); }
コンストラクタをキャッシュして早くしてるだけなので、一回キャッシュ周りの処理を消しましょう。
// in : LifecycleRegistry final Class<?> klass = object.getClass(); cachedConstructor = getGeneratedAdapterConstructor(klass); if (cachedConstructor != null) { if (!cachedConstructor.isAccessible()) { cachedConstructor.setAccessible(true); } return cachedConstructor.newInstance(object); } return new ReflectiveGenericLifecycleObserver(object);
つまり getGeneratedAdapterConstructor
を見ればいいわけですね。
// in : LifecycleRegistry @Nullable private static Constructor<? extends GenericLifecycleObserver> getGeneratedAdapterConstructor( Class<?> klass) { final String fullPackage = klass.getPackage().getName(); String name = klass.getCanonicalName(); // anonymous class bug:35073837 if (name == null) { return null; } final String adapterName = getAdapterName(fullPackage.isEmpty() ? name : name.substring(fullPackage.length() + 1)); try { @SuppressWarnings("unchecked") final Class<? extends GenericLifecycleObserver> aClass = (Class<? extends GenericLifecycleObserver>) Class.forName( fullPackage.isEmpty() ? adapterName : fullPackage + "." + adapterName); return aClass.getDeclaredConstructor(klass); } catch (ClassNotFoundException e) { final Class<?> superclass = klass.getSuperclass(); if (superclass != null) { return getGeneratedAdapterConstructor(superclass); } } catch (NoSuchMethodException e) { // this should not happen throw new RuntimeException(e); } return null; } static String getAdapterName(String className) { return className.replace(".", "_") + "_LifecycleAdapter"; }
bug とか書いてあって不穏ですが、canonical name は匿名クラスだと null になります。問題ありません。さて canonical name がある場合、パッケージ名等から LifecycleAdapter 名を作成します。最初の APT で生成されたクラスを作り、そのコンストラクタを返します。
// in : LifecycleRegistry final Class<?> klass = object.getClass(); cachedConstructor = getGeneratedAdapterConstructor(klass); if (cachedConstructor != null) { if (!cachedConstructor.isAccessible()) { cachedConstructor.setAccessible(true); } return cachedConstructor.newInstance(object); } return new ReflectiveGenericLifecycleObserver(object);
コンストラクタがあれば、最初に渡した Observer を引数として GenericLifecycleObserver を、今回は MyActivity_MyLifecycleObserver_LifecycleAdapter
を作成します。非常にシンプルですね。
canonical name がなかった場合は getGeneratedAdapterConstructor
が null を返していましたね。つまり ReflectiveGenericLifecycleObserver
なるものにたどり着きます。
その中身は黒魔術の塊・・・といいたいんですが、Reflection ではクラスを作れないので、本来は APT でクラスにしておく部分を Runtime で処理しています。
ということで、匿名クラスで LifecycleObserver
を作成してしまうと初回のみコストが高いことになります。コストが高いといっても感はありますが。 それに一度生成すればオンメモリキャッシュする機構もありますし、問題はなさそうです。というか、匿名クラスで作る必要を感じないんですがそれは・・・
とりあえず定義した LifecycleObserver を wrap するクラスがあり、それを動的に生成しているようです。またその wrapper は Lifecycle State を監視していて、時が来たら LifecycleObserverの該当メソッドを叩くという非常にシンプルな構造でした。とさ。