Android Architecture Components の Lifecycle モジュールの APT を追う

Google I/O 2017 で Android Architecture Components が公開されました。

developer.android.com

簡単に 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 なるものにたどり着きます。

f:id:jmatsu:20170522141928j:plain

その中身は黒魔術の塊・・・といいたいんですが、Reflection ではクラスを作れないので、本来は APT でクラスにしておく部分を Runtime で処理しています。

ということで、匿名クラスで LifecycleObserver を作成してしまうと初回のみコストが高いことになります。コストが高いといっても感はありますが。 それに一度生成すればオンメモリキャッシュする機構もありますし、問題はなさそうです。というか、匿名クラスで作る必要を感じないんですがそれは・・・

とりあえず定義した LifecycleObserver を wrap するクラスがあり、それを動的に生成しているようです。またその wrapper は Lifecycle State を監視していて、時が来たら LifecycleObserverの該当メソッドを叩くという非常にシンプルな構造でした。とさ。