46

2つの活動をしています

  • MainActivity
  • DeepLinkActivity

herehere、およびhereNavUtilsのように、ナビゲートに使用するすべてをセットアップしました。

私が達成したいことは次のとおりです。

  1. DeepLinkActivityディープリンクから開始
  2. 押し上げる
  3. に行くMainActivity

最近のアプリに私のアプリのタスクがある限り、すべてがうまく機能します。

ただし、最近のアプリからアプリをスワイプすると、次のように動作します。

  1. 最近のアプリからアプリをスワイプして離す
  2. DeepLinkActivityディープリンクから開始
  3. 押し上げる
  4. 戻るボタンを押したときのように、アプリが閉じます

コードをデバッグしたところ、 がNavUtils.shouldUpRecreateTask()返されることがわかりましたfalseupIntent私のセットのように、すべてが正常に設定されていますComponent。それでも、NavUtils.navigateUpTo()への呼び出しと同じように動作しfinish()ます。ログステートメントも何もありません。

それを修正する方法はありますか?

AndroidManifest.xml

<activity
    android:name=".DeepLinkActivity"
    android:parentActivityName="my.package.MainActivity">
    <meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value="my.package.MainActivity"/>
    <intent-filter>
        <!-- Some intent filter -->
    </intent-filter>
</activity>

DeepLinkActivity.java

@Override
public boolean onOptionsItemSelected(final MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            Intent upIntent = NavUtils.getParentActivityIntent(this);
            if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
                // create new task
                TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent)
                        .startActivities();
            } else {
                // Stay in same task
                NavUtils.navigateUpTo(this, upIntent);
            }
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

- - - 編集 - - -

いくつかの Google Apps が同じように壊れていることに気付きました。たとえば、検索から連絡先にジャンプする場合、AB を上に押すと、連絡先アプリの代わりにホーム画面に自分自身が表示されます。(API19/cm11)

4

9 に答える 9

22

その方法はバグっていると思います。サポート ライブラリのソース コードを読みましたが、そのメソッドはインテントのアクションをチェックします。アプリが以前に作成された場合にのみ機能します。説明したように、アプリのプレビューから強制終了すると、shouldUp メソッドが機能しなくなります。

独自の「shouldUpRecreateTask」を使用してこれを修正しました。アクティビティを直接作成する通知を受け取ると (あなたの行動のように)、BroadCastReceiver からインテント内のカスタム アクションを送信します。次に、メソッドで次のことを行います。

private final boolean shouldUpRecreateTask(Activity from){
    String action = from.getIntent().getAction();
    return action != null && action.equals(com.xxxxxx.activities.Intent.FROM_NOTIFICATION);
}

...................................

 if (shouldUpRecreateTask(this)) {
      TaskStackBuilder.create(this)
       .addNextIntentWithParentStack(upIntent)
       .startActivities();
 } else {
       fillUpIntentWithExtras(upIntent);
       NavUtils.navigateUpTo(this, upIntent);
 }
于 2013-12-17T20:27:04.497 に答える
7

NavUtils.shouldUpRecreateTask(this, upIntent)この特殊なケースには対応していないようです。

私の現在の回避策は、Activityディープリンクされているかどうかを確認し、このような場合に新しいタスク スタックを強制することです。

私の場合、オブジェクトをEXTRAs で内部的に渡します。ただし、特定の URL へのリンクをたどることによって、または NFC 対応デバイスに触れることによって外部から が開始された場合は、ACTIONUriが設定されます。Activity

@Override
public boolean onOptionsItemSelected(final MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            Intent upIntent = NavUtils.getParentActivityIntent(this);
            if (NavUtils.shouldUpRecreateTask(this, upIntent)
                    || getIntent().getAction() != null) { // deep linked: force new stack
                // create new task
                TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent)
                        .startActivities();
            } else {
                // Stay in same task
                NavUtils.navigateUpTo(this, upIntent);
            }
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}
于 2013-12-17T10:22:05.333 に答える
4

<activity-alias>をメイン/ランチャーとして使用していますか? を に変更する<activity-alias><activity>、アップ ナビゲーションが正しく機能します。何らかの奇妙な理由で、エイリアスが関係している場合、ナビゲーションが正しく機能しません。

ネイティブの ActivityManager にバグがあることを示す奇妙な UI の不具合もあります。を使用してアプリのメイン アクティビティまで移動した後navigateUpTo()、デバイスの戻るキーを押します。現在のアプリがアクティビティ終了アニメーションを実行し、その直後に、次に新しいアプリもアクティビティ終了アニメーションを実行します。これは、Android のホーム画面から現在のアプリを起動した場合でも発生します。最近のすべてのアプリをクリアして、[上に移動してから戻る] 手順をもう一度試すと、終了アニメーション中にランダムな (つまり、予期しない) アプリが表示されます。

このような場合は、他のアプリを表示しないでください。アクティビティ マネージャーが履歴スタックを正しく管理していないようです。

問題のあるバグは、この diffの下部に表示される次のメソッド内で見つかる可能性があります。

+    public boolean navigateUpTo(IBinder token, Intent destIntent, int resultCode,
+            Intent resultData) {
+        ComponentName dest = destIntent.getComponent();
+
+        synchronized (this) {
+            ActivityRecord srec = ActivityRecord.forToken(token);
+            ArrayList<ActivityRecord> history = srec.stack.mHistory;
+            final int start = history.indexOf(srec);
+            if (start < 0) {
+                // Current activity is not in history stack; do nothing.
+                return false;
+            }
+            int finishTo = start - 1;
+            ActivityRecord parent = null;
+            boolean foundParentInTask = false;
+            if (dest != null) {
+                TaskRecord tr = srec.task;
+                for (int i = start - 1; i >= 0; i--) {
+                    ActivityRecord r = history.get(i);
+                    if (tr != r.task) {
+                        // Couldn't find parent in the same task; stop at the one above this.
+                        // (Root of current task; in-app "home" behavior)
+                        // Always at least finish the current activity.
+                        finishTo = Math.min(start - 1, i + 1);
+                        parent = history.get(finishTo);
+                        break;
+                    } else if (r.info.packageName.equals(dest.getPackageName()) &&
+                            r.info.name.equals(dest.getClassName())) {
+                        finishTo = i;
+                        parent = r;
+                        foundParentInTask = true;
+                        break;
+                    }
+                }
+            }
+
+            if (mController != null) {
+                ActivityRecord next = mMainStack.topRunningActivityLocked(token, 0);
+                if (next != null) {
+                    // ask watcher if this is allowed
+                    boolean resumeOK = true;
+                    try {
+                        resumeOK = mController.activityResuming(next.packageName);
+                    } catch (RemoteException e) {
+                        mController = null;
+                    }
+
+                    if (!resumeOK) {
+                        return false;
+                    }
+                }
+            }
+            final long origId = Binder.clearCallingIdentity();
+            for (int i = start; i > finishTo; i--) {
+                ActivityRecord r = history.get(i);
+                mMainStack.requestFinishActivityLocked(r.appToken, resultCode, resultData,
+                        "navigate-up");
+                // Only return the supplied result for the first activity finished
+                resultCode = Activity.RESULT_CANCELED;
+                resultData = null;
+            }
+
+            if (parent != null && foundParentInTask) {
+                final int parentLaunchMode = parent.info.launchMode;
+                final int destIntentFlags = destIntent.getFlags();
+                if (parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE ||
+                        parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TASK ||
+                        parentLaunchMode == ActivityInfo.LAUNCH_SINGLE_TOP ||
+                        (destIntentFlags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
+                    parent.deliverNewIntentLocked(srec.app.uid, destIntent);
+                } else {
+                    try {
+                        ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
+                                destIntent.getComponent(), 0, UserId.getCallingUserId());
+                        int res = mMainStack.startActivityLocked(srec.app.thread, destIntent,
+                                null, aInfo, parent.appToken, null,
+                                0, -1, parent.launchedFromUid, 0, null, true, null);
+                        foundParentInTask = res == ActivityManager.START_SUCCESS;
+                    } catch (RemoteException e) {
+                        foundParentInTask = false;
+                    }
+                    mMainStack.requestFinishActivityLocked(parent.appToken, resultCode,
+                            resultData, "navigate-up");
+                }
+            }
+            Binder.restoreCallingIdentity(origId);
+            return foundParentInTask;
+        }
+    }
于 2014-05-01T00:05:14.310 に答える
3

以下が私のために働いていることがわかりました。アクティビティが別のアクティビティまたは通知からディープ リンクされている場合、それ以外の場合は上に移動するとスタックが作成され、アクティビティは前面に表示されます。

case android.R.id.home:
Intent upIntent = NavUtils.getParentActivityIntent(this);
upIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(upIntent);
finish();
return true;

あなたが持っている場合

android:parentActivityName="parent.activity"

あなたのマニフェストで

于 2014-02-19T22:33:34.997 に答える
2

私にとってもうまくいきません。だから私はこのように処理します:

   @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == android.R.id.home) {

                Intent intent = new Intent(this, MainActivity.class);
                startActivity(intent);
                finish();
                return true;

        }
        return super.onOptionsItemSelected(item);
    }

私のMainActivityはAndroidマニフェストでsingleTaskとしてマークされています

android:launchMode="singleTask"
于 2013-12-13T17:37:47.483 に答える
1

これを試して :

@Override
public boolean onOptionsItemSelected(final MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            Intent upIntent = NavUtils.getParentActivityIntent(this);
            if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
                // create new task
                TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent)
                        .startActivities();
            } else {
                // Stay in same task
                NavUtils.navigateUpTo(this, upIntent);
            }
            break;
        default:
            return super.onOptionsItemSelected(item);
    }
    return true;
}
于 2013-12-12T04:50:44.923 に答える