LoginSignup
10
9

More than 5 years have passed since last update.

クラス名の文字列を使わずに別ModuleのActivityを呼び出す

Last updated at Posted at 2019-02-22

はじめに

クラス名の文字列を使わずにDynamic Feature ModuleのActivityを呼び出す - Qiita を参考に、普通のモジュール構成でこの activity-alias のテクニックを使うにはどうすればいいのか検証してみました。

対象アプリのモジュール構成

巨大でモノリシックな app のみで構成されたアプリから legacy モジュールや比較的独立性の高いモジュールをコツコツ分離しています。

image.png

ゴチャゴチャしていますが今回考える対象は configlogin モジュールだけです。

image.png

この某アプリでは、login モジュールに存在する「ログイン画面」(LoginActivity)のメニューから、config モジュールに属する「設定画面」(ConfigActivity)を開くことができます。

| image.png | image.png

image.png

この設定画面を開くコードは下記のようになっています。

modules/login/src/main/java/com/twitpane/login/ui/LoginActivity.java
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        if (id == R.id.action_settings) {

            final Intent intent;
            try {
                intent = new Intent(this, Class.forName("com.twitpane.config.ui.ConfigActivity"));
                startActivityForResult(intent, REQUEST_SETTINGS);
            } catch (ClassNotFoundException ignored) {
            }

            return true;
        }

別モジュールの Activity なので Class.forName() でクラス名を FQDN で指定しています。当然ながら補完は効かず、Activityのクラス名やパッケージ変更時にリファクタリングで追随してくれません。モジュール分離のような作業ではパッケージ変更が数多く発生するので、割と致命的です(何度もやらかしました)。

activity-alias を導入する

config login の両モジュールから見える core モジュールに activity-alias となるクラスを用意します。

modules/core/src/main/java/com/twitpane/core/ActivityAlias.kt
package com.twitpane.core

sealed class ConfigActivityAlias

sealed classとして定義しているのは、インスタンス化を防ぐためです。

LoginActivity から呼び出す部分には
ConfigActivityAlias を指定することで Class.forName が不要になります。やったね!(しかも try-catch も不要になっています。Kotlin なら元から不要だけど)。

modules/login/src/main/java/com/twitpane/login/ui/LoginActivity.java
...
            final Intent intent = new Intent(this, ConfigActivityAlias.class);
            startActivityForResult(intent, REQUEST_SETTINGS);
...

そして肝心の activity-aliasconfig モジュールの AndroidManifest.xml に追記します。

modules/config/src/main/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.twitpane.config">

    <application>
        <activity
            android:name="com.twitpane.config.ui.ConfigActivity" ... />

        <activity-alias
            android:name="com.twitpane.core.ConfigActivityAlias"
            android:targetActivity="com.twitpane.config.ui.ConfigActivity" />

    </application>
</manifest>

これで実行してみると、ログイン画面から設定画面を無事呼び出すことができました。

ちなみに logcat には下記のように ConfigActivityAlias のほうが出力されていました。

02-22 21:59:40.099 780-3022/? I/ActivityManager: START u0 {cmp=com.twitpane.debug/com.twitpane.core.ConfigActivityAlias} from uid 10083 on display 0
02-22 21:59:40.402 780-801/? I/ActivityManager: Displayed com.twitpane.debug/com.twitpane.core.ConfigActivityAlias: +275ms

実運用では、クラス名の文字列を使わずにDynamic Feature ModuleのActivityを呼び出す - Qiita で解説されているように、ProGuard/R8でリネームされないように、アプリケーションのproguard-rules.proに設定を追加すべきです。お忘れなく。

マルチモジュール化が捗りそうですね。

以上でございます。

10
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
9