15

自明ではないアクティビティ構造を持つほぼ完成したアプリケーションがあります。このアプリにはプッシュ通知が関連付けられており、通知エントリを選択すると、アプリがフォアグラウンド/バックグラウンド/非アクティブのいずれであるかに関係なく、特定のアクティビティが表示されるはずです。

アプリがアクティブでない場合、アプリを正常に起動し、適切な部分に自動ナビゲートできました。ただし、アプリがアクティブな場合、問題があります。問題の性質を伝えるために、問題の簡略化されたバージョンを提示し、必要に応じてアプリのアクティビティ構造と関連コードの詳細を投稿します (実際には、現在取り組んでいます)。

したがって、私のアプリのアクティビティ スタック (大幅に簡略化) は次のようになります。

A -> B -> X

ここで、ルート アクティビティである A はログイン ページです。B は「ホームページ」のようなもので、X はホームページから開始できるいくつかのアクティビティの 1 つです (ただし、一度にアクティブになるインスタンスは 1 つだけです。これらは B からのみ開始できるためです)。

通知が選択されると、アプリケーションが B に自動的にナビゲートする必要があります。[A]、[A -> B]、[A -> B -> X]、または [ ] (アプリはアクティブではありません)。

私の通知は、インテントをアクティビティ A に渡します。CLEAR_TOP フラグと NEW_TASK フラグを使用してみましたが、何も使用しませんでした。A は現在、launchmode=singleTask を持っています。これを行うことで、考えられるすべての既存のスタック構成に対処し、それらを [A] に減らしていることがわかります。インテントには、通常の起動とは対照的に、通知からのものであることを識別するエクストラも含まれています。

アクティビティ A は、インテントが通知から送信されたことを識別すると ( onCreate() と onNewIntent() の両方でこれを行うことができます)、インテントをアクティビティ B に送信します。このインテントには、CLEAR_TOP と SINGLE_TOP が含まれます。B には launchmode=singleTop があります。

95% の確率で、これは希望どおりに機能し、通知を押した後、アプリのスタックは [A -> B] です。約 5% の確率で、アプリは [A -> B -> B] のスタックで終了します。

ここで何が起こっているのか、または私が間違っていることについてのアイデアはありますか?

これが重要な問題であることが判明した場合は、詳細を投稿します。実際、現在詳細を投稿しています...

~~~~~~~~~~~~~~~~~~~~~~詳細~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~

デバッガーをステップ実行すると、A がそのインテントを B に送信するたびに、B の既存のインスタンスが onCreate() される前に onDestroy() され、さらに onNewIntent() が呼び出されることがわかります。これは私には奇妙に思えます。使用しているフラグ (CLEAR_TOP と SINGLE_TOP) を誤解しているか、他の何かがそれらを妨害していることを示唆しています。

デバッグで誤ったスタック構造を再現できませんでした。デバッグで発生しないためか、十分な回数試していないためかどうかはわかりません。

作成中のインテントのコード:

C2DM 受信機サービスでは:

protected void onMessage(Context context, Intent intent) {
    int icon = R.drawable.some_drawable;
    CharSequence tickerText = "blah";
    long when = System.currentTimeMillis();
    Notification notification = new Notification(icon, tickerText, when);

    //Context context = getApplicationContext(); //Don't need this; using the context passed by the message.
    CharSequence contentTitle = intent.getStringExtra("payload");
    CharSequence contentText = "Lorem ipsum dolor si amet,";
    Intent notificationIntent = new Intent(this, LoginPage.class);
    //notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); //Tried with and without
    notificationIntent.putExtra(PushManager.PUSH_INTENT, PushManager.PUSH_INTENT); //Indicator that this was send from notification

    PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
    notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);

    notificationManager.notify(PushManager.ALARM_NOTIFICATION_ID, notification);
}

LoginPage (アクティビティ A) で、ログインに成功した後:

Intent i = new Intent(LoginPage.this, TabHomePage.class);
// (If we're automatically going to tab 2, inform next activity)
if(fromNotification) {
    i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
    i.putExtra(TabHomePage.TAB_NUMBER, TabHomePage.TAB_2);
}
startActivity(i);

アクティビティ スタック構造の詳細については、次の図をご覧ください。

http://i89.photobucket.com/albums/k207/cephron/ActivityStack.png

そして、ここに千の言葉があります:

アクティビティ A はログイン ページです。ログインに成功すると、B が開始されます。B は TabActivity であり、その中に 3 つのアクティビティ (C、D、E で表されます) が含まれています。C、D、および E のそれぞれは、実際には子アクティビティがアクティビティの通常のスタック動作を模倣する ActivityGroup です。

そのため、各タブには独自のアクティビティ スタックが含まれており、タブを切り替えると、ユーザーのナビゲーションによって現在プッシュ/ポップされているこれらのスタックが変更されます (各タブには、エンティティの階層構造を参照する ListActivities のスタックが含まれます)。これらは、巨大な 'B' TabActivity (X で表される) を超えて新しいアクティビティを開始することもできます。

そのため、アクティビティ A からログインすると、さらにユーザー入力が受け入れられる前に、少なくとも 3 つのアクティビティが作成されます。 : デフォルトのタブに属するもの。この ActivityGroup は画面には表示されませんが、子アクティビティのスタックの最上位のアクティビティのみが表示されます。-最後に、その ActivityGroup のスタックの「ルート」アクティビティが作成されます (図では、F がそのようなアクティビティの例です)。このアクティビティは、TabWidget の下に表示されます。

各タブに 1 回アクセスした後は、タブを切り替えてもアクティビティが作成/破棄されることはありません (メモリ キルはカウントされません)。任意のタブを押すと、そのスタックの一番上にあるアクティビティが終了し、その下にあるアクティビティが表示されます。任意のタブでルート アクティビティ (F など) から戻ると、TabActivity 全体が終了し、ユーザーが A に戻ります。

B に渡されるインテントは、デフォルトとは異なるタブに自動的に移動するように指示します。[A -> B -> B] のスタックになった場合、最初の B は正しいタブに移動し、2 番目はデフォルトです。

4

1 に答える 1

15

TL;DR; CLEAR_TOP と SINGLE_TOP を同時に使用しないでください

5% の確率でしかエラーが発生しない場合は、同時実行の問題である可能性があります。あなたは SINGLE_TOP | を持っていると言った。アクティビティ B を呼び出すための CLEAR_TOP。CLEAR_TOP はアクティビティ B の現在のインスタンスを破棄し、インテントは onCreate() に配信されます。SINGLE_TOP はアクティビティ B の現在のインスタンスを破棄せず、インテントを onNewIntent() に渡します。

SINGLE_TOP フラグが最初に読み取られると、onNewIntent() を呼び出すアクティビティ B の現在のインスタンスにインテントが配信されます。次に、CLEAR_TOP が読み取られ、Activity B が破棄され、onCreate() で新しいインスタンスが作成され、すべて正常に動作します。

CLEAR_TOP が最初に読み取られると、アクティビティ B の既存のインスタンスが破棄され、onCreate() で新しいインスタンスが作成されます。次に、SINGLE_TOP が読み取られ、インテントが onNewIntent() にも配信されます。繰り返しますが、うまくいきます。

CLEAR_TOP と SINGLE_TOP が同時に読み取られると、現在のアクティビティのインスタンスが破棄され、CLEAR_TOP が onCreate() を呼び出し、SINGLE_TOP も onCreate() を呼び出します。これは、現時点でアクティビティ B のインスタンスが存在しないためです。したがって、A->B->B となります。

于 2011-04-02T08:40:57.083 に答える