web-dev-qa-db-ja.com

Android "シングルトップ"起動モードとonNewIntentメソッド

Androidドキュメントで、IntentにFLAG_ACTIVITY_SINGLE_TOPフラグを追加してアクティビティのlaunchModeプロパティをsingleTop ORに設定すると、startActivity(intent)を呼び出すと単一のアクティビティが再利用されるインスタンスとonNewIntentコールバックでインテントを与えます。私はこれらの両方を行いましたが、onNewIntentは起動せず、onCreateは毎回起動します。また、ドキュメントは、this.getIntent()が最初に作成されたときにアクティビティに最初に渡されたインテントを返すと述べています。 onCreategetIntentを呼び出して、毎回新しいものを取得しています(別のアクティビティでインテントオブジェクトを作成し、それに余分なものを追加しています...同じインテントオブジェクトを返す場合は、毎回同じにしてください)。これはすべて、私の活動が「シングルトップ」のように振る舞っていないことを信じるように導き、私はその理由を理解していません。

単に必要な手順が欠落している場合に背景を追加するために、マニフェストのアクティビティ宣言と、アクティビティを起動するために使用しているコードを示します。アクティビティ自体は、これに関して言及する価値はありません。

androidManifest.xmlで:

    <activity
        Android:name=".ArtistActivity"
        Android:label="Artist"
        Android:launchMode="singleTop">
    </activity>     

私の呼び出しアクティビティで:

        Intent i = new Intent();
        i.putExtra(EXTRA_KEY_ARTIST, id);
        i.setClass(this, ArtistActivity.class);
        i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        startActivity(i);
43
Rich

onDestroy()も呼び出されたかどうかを確認しましたか?おそらく、onCreate()の代わりにonNewIntent()が毎回呼び出される理由でしょう。これは、アクティビティが既に存在する場合にのみ呼び出されます。

たとえば、[戻る]ボタンを使用してアクティビティを終了すると、デフォルトで破棄されます。ただし、アクティビティスタックの上位に移動して他のアクティビティに移動し、そこからArtistActivity.classを再度呼び出すと、onCreate()をスキップしてonNewIntent()に直接移動します。作成し、singleTop Androidとして定義したため、新しいインスタンスは作成されませんが、既に存在するインスタンスを取得します。

何が起こっているのかを確認するために何をするかは、各アクティビティのすべての異なる状態に対してダミー関数を実装するため、常に何が起こっているのかを常に把握しています。

@Override
public void onDestroy() {
    Log.i(TAG, "onDestroy()");
    super.onDestroy();
}

onRestart()onStart()onResume()onPause()onDestroy()でも同じ

上記([戻る]ボタン)が問題ではなかった場合、これらのダミーを実装すると、少なくともデバッグの改善に役立ちます。

36
znq

受け入れられた答えはまったく正しくありません。 onDestroy()が以前に呼び出された場合、はい、onCreate()が常に呼び出されます。ただし、このステートメントは間違っています:「アクティビティスタックを他のアクティビティに移動して、そこからArtistActivity.classを再度呼び出すと、スキップされますonCreate()でonNewIntent()に直接移動します」

http://developer.Android.com/guide/components/tasks-and-back-stack.html の「singleTop」セクションでは、その仕組みがわかりやすく説明されています(以下の太字のテキストに注意してください。私自身のデバッグでもこれを証明しました):

「たとえば、タスクのバックスタックがルートアクティビティAで構成され、アクティビティB、C、およびDが最上部にあるとします(スタックはABCDです。Dは最上部にあります)。タイプDのアクティビティのインテントが到着します。Dにデフォルトの「標準」起動モードがある場合、クラスの新しいインスタンスが起動され、スタックはABCDDになります。ただし、Dの起動モードが「singleTop」の場合、 Dの既存のインスタンスは、スタックの最上部にあるため、onNewIntent()を介してインテントを受け取ります。スタックはABCDのままですが、タイプBのアクティビティのインテントが到着した場合、起動モードが "singleTop"であっても、Bの新しいインスタンスがスタックに追加されます。 "

つまり、SINGLE_TOPを介してアクティビティを開始すると、スタックの最上部に既にがある場合にのみ、既存のアクティビティが再利用されます。同じタスク内の別のアクティビティが一番上にある場合は機能しません(たとえば、startActivity(SINGLE_TOP)を実行しているアクティビティ)。代わりに新しいインスタンスが作成されます。

これを修正する2つの方法がありますあなたが望むSINGLE_TOPの動作を得るために-その一般的な目的は、代わりに既存のアクティビティを再利用することです新しいものを作成する...

最初の方法(受け入れられた答えのコメントセクションで説明):アクティビティに「singleTask」のlaunchModeを追加できます。 singleTaskは、特定のタスクに特定のアクティビティのインスタンスが1つしか存在できないことを意味するため、onNewIntent()が強制されます。アプリが特定の状況でそのアクティビティの複数のインスタンスを必要とする場合(私のプロジェクトで行うように)、これはややハックなソリューションですが、あなたは台無しにされます。

2番目の方法(より良い):FLAG_ACTIVITY_SINGLE_TOPの代わりに、FLAG_ACTIVITY_REORDER_TO_FRONTを使用します。これにより、既存のアクティビティインスタンスがスタックの一番上に移動して再利用されます(onNewIntent()は予想どおりに呼び出されます)。

FLAG_ACTIVITY_SINGLE_TOPの主な目的は、アクティビティの複数のインスタンスの作成を防止することです。たとえば、アプリケーションのメインタスクの外部から来るインテントを介してそのアクティビティを起動できる場合。アプリ内のアクティビティ間の内部切り替えについては、FLAG_ACTIVITY_REORDER_TO_FRONTが一般的に私が望むものであることがわかりました。

28
Steve B

このフラグを意図に設定します。

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP)
3
Kodak