2021年8月22日日曜日

Activityの遷移時、すでに生成しているActivityへ遷移する方法

startActivityでActivityを切り替える場合、
デフォルトのままだと、毎回新規でActivityのインスタンスを作ってしまう。
なので、すでに同名Activityが存在していても、新しいActivityがスタック上にできあがる。


Intentで指定したActivityがすでに生成されている場合は、
生成済みActivityに遷移させるにはどうするか。について書いていく。


Activityの管理

アプリ内でActivityを切り替えていくとき、
Activity達はスタックに積み上げられていく仕組みになっている。
これのおかげで、Backキー押下や今の画面でfinish()をCallしたとき、最上位のActivityをスタックから取り除き、一つ前の画面に戻すことができるわけだ。

なので
古いActivityをstartActivityで呼び出したい場合、スタックの順番を入れ替えることができれば問題は解決する。
例えば
ActivityA ⇒ B ⇒ Cの順で画面遷移をした後に、Aを表示したい場合、
以下のスタック切り替えができればよい。


しかし、このスタックの入れ替え機能は
Androidでは提供されていない(スタック管理なのでLIFO。順番入れ替えは不可)
なので、
どうやってスタックをから任意の古いActivityを抜き出すかが焦点となる。


AndroidManifestのLaunchModeを利用

Activityのスタックの挙動は
AndroidManifestのlaunchModeである程度制御できる。
(さすがに、上の理想形の制御はできないのだが....)

上に習い
ActivityA ⇒ B ⇒ Cの順で画面遷移をした後に、Aを表示したい場合を例に
設定毎の挙動を解説する。

launchMode:standard(デフォルト)、singleTop


ActivityAを呼び出しても、新規で作成してスタックに積む動作になる。 
古いActivityAとは関係ないので変数も引き継がれない。
この設定で古いActivityに戻すなら、自信をfinishさせるかBackキー押下させて、 
ActivityBへ移動し、さらにfinishさせる必要がある。ActivityBもCも消えるし制御が難しい。。


launchMode:singleTask


ActivityAがスタックにあれば、その上に積まれているActivityを全て削除してActivityAを表示させる。これなら古いActivityAに戻せる。 
ただ、ActivityBやCは消えるので、この後にB,Cを呼ぶと新規で作られる


launchMode:singleInstance

1つのタスクに1つのActivityとする制御。なのでスタックに積まれない。
バックキー押下すると1つ前のタスクが表示されるから前の画面への遷移もできる。一番理想に近い形。
ただし、HOMEキーでホーム画面へ戻ったり、別のアプリへ切り替えたりすると
フォアグラウンドだったタスク以外全て捨てられるので、その場合は他のActivityは作り直しとなる。


まとめ

Activityで任意の古いActivityへ遷移させたい場合
AndroidManifestでActivityのlaunchMode設定を全て"singleInstance"にする
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.sample.test.myapplication">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyApplication">
        <activity
            android:name=".MainActivity3"
            android:exported="true"
            android:launchMode="singleInstance" />★コレ!
        <activity
            android:name=".MainActivity2"
            android:exported="true"
            android:launchMode="singleInstance" />★コレ!
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleInstance">★コレ!
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

これも
別アプリへ一時遷移する場合を考慮すると問題ありますけどね。。。(^_^;

0 件のコメント:

コメントを投稿