NavUtils.navigateUpTo() nie uruchamia żadnej aktywności

Mam dwie aktywności

  • MainActivity
  • DeepLinkActivity

Ustawiłem wszystko, aby używać NavUtils do nawigacji w górę, jak zalecono tutaj, tutaj I tutaj .

Chcę osiągnąć:

  1. Uruchom {[3] } przez głęboki link
  2. naciśnij w górę
  3. przejdź do MainActivity

Wszystko działa ładnie tak długo, jak jest jakieś zadanie mojej aplikacji w ostatnich aplikacjach.

Jednakże, kiedy odciągam moja aplikacja z ostatnich aplikacji zachowuje się tak:

  1. Przesuń moją aplikację z ostatnich aplikacji
  2. Uruchom {[3] } przez głęboki link
  3. naciśnij w górę
  4. moja aplikacja zamyka się, jak po naciśnięciu wstecz

Debugowałem kod i dowiedziałem się, że NavUtils.shouldUpRecreateTask() zwraca false. upIntent ma wszystko ustawione na normalne, jak mój Component zestaw. Ale mimo to, NavUtils.navigateUpTo() zachowuje się jak wezwanie do finish(). Żadnych zapisów, nic.

Wszelkie pomysły, jak naprawić to?

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>

Deeplinkjava

@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);
    }
}

----- Edit - - - - -

Zdałem sobie sprawę, że kilka Aplikacji Google jest zepsute w ten sam sposób. Jeśli przeskoczysz np. do kontaktów z wyszukiwarki, naciśnij W GÓRĘ W AB, a znajdziesz się na ekranie głównym zamiast w aplikacji Kontakty. (API19 / cm11)

Author: flx, 2013-11-15

9 answers

Myślę, że ta metoda jest na podsłuchu. Przeczytałem kod źródłowy biblioteki wsparcia i ta metoda sprawdza działanie intent. Działa tylko wtedy, gdy aplikacja była wcześniej created..as opisałeś, jeśli zabijesz go z podglądu aplikacji, metoda shouldUp przestanie działać.

Naprawiłem to używając własnego "shouldUpRecreateTask". Kiedy otrzymam powiadomienie, które tworzy bezpośrednio aktywność (jak twoje zachowanie), wysyłam z mojego BroadCastReceiver niestandardową akcję wewnątrz intent. Następnie, w mojej metodzie I zrób następną rzecz:

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);
 }
 20
Author: noni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-17 20:27:04

Moje rozwiązanie problemu OPs:

public void navigateUp() {
    final Intent upIntent = NavUtils.getParentActivityIntent(this);
    if (NavUtils.shouldUpRecreateTask(this, upIntent) || isTaskRoot()) {
        Log.v(logTag, "Recreate back stack");
        TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent).startActivities();
    } else {
        NavUtils.navigateUpTo(this, upIntent);
    }
}

isTaskRoot() zwróci true, Jeśli DeepLinkActivity jest korzeniem zadania (początkowe uruchomienie aplikacji lub aplikacji zostało wcześniej zakończone przez Menedżera zadań). W ten sposób nie tracę istniejącego tylnego stosu, jeśli aktywność została uruchomiona przez link, gdy zadanie aplikacji było już na pierwszym planie.

 47
Author: Sokolov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-10 21:35:56

Wygląda na to, że NavUtils.shouldUpRecreateTask(this, upIntent) nie jest przygotowany do tego szczególnego przypadku.

Moje obecne obejście polega na sprawdzeniu, czy Activity było głęboko połączone i wymusić nowy stos zadań dla takich przypadków.

W moim przypadku przekazuję obiekty w EXTRAs wewnętrznie. Ale ACTION i Uri są ustawione, jeśli Activity jest uruchamiany z zewnątrz przez kliknięcie linku do określonego adresu URL lub dotknięcie urządzeń obsługujących NFC.

@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);
    }
}
 7
Author: flx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-17 10:22:05

Czy używasz <activity-alias> jako głównego / launchera? Gdy zmienię <activity-alias> na <activity>, nawigacja w górę działa poprawnie. Z jakiegoś dziwnego powodu nawigacja nie działa poprawnie, gdy aliasy są zaangażowane.

Istnieje również dziwna usterka interfejsu użytkownika, która wskazuje, że natywny Menedżer ActivityManager ma błąd. Po przejściu do głównej aktywności aplikacji za pomocą navigateUpTo() naciśnij klawisz Wstecz urządzenia. Bieżąca aplikacja wykona animację zakończenia aktywności, a następnie natychmiast po Następna-najnowsza aplikacja wykona również animację zakończenia aktywności. Dzieje się tak nawet po uruchomieniu bieżącej aplikacji z ekranu głównego Androida. Jeśli wyczyścisz wszystkie ostatnie aplikacje i spróbujesz ponownie wykonać kroki nav-up-then-back, podczas animacji zakończenia zostanie wyświetlona losowa (np. nieoczekiwana) aplikacja.

Inne aplikacje nie powinny być prezentowane w takich przypadkach. Wydaje się, że menedżer aktywności nie zarządza prawidłowo stosem historii.

Błąd można znaleźć w następująca metoda, która pojawia się na dole tego rozróżnienia :

+    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;
+        }
+    }
 4
Author: James Wald,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-01 00:27:38

Znalazłem następujące działa dla mnie. Jeśli aktywność była głęboko powiązana z inną aktywnością lub powiadomieniem, stos byłby tworzony podczas poruszania się w górę, w przeciwnym razie działania są po prostu przenoszone na front.

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

Pod warunkiem, że masz

android:parentActivityName="parent.activity"

W manifeście

 3
Author: David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-19 22:33:34

Mnie też to nie działa. Więc sobie radzę w ten sposób:

   @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);
    }

Moja główna aktywność jest oznaczona jako singleTask w manifeście Androida

android:launchMode="singleTask"
 2
Author: vandzi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-13 17:37:47

Jeśli przejdziesz do swojej aktywności z powiadomienia, będziesz musiał utworzyć stos podczas tworzenia powiadomienia, sprawdź tę odpowiedź: NavUtils.shouldUpRecreateTask nie działa na JellyBean

 2
Author: Ciprian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:53

Spróbuj tego:

@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;
}
 1
Author: SweetWisher ツ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-12 04:54:57

Wypróbuj następującą odpowiedź działającą dla mnie w obu przypadkach rozpocznij Aktywność od powiadomienia i rozpocznij Aktywność od aktywności rodzica.

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            Intent upIntent = NavUtils.getParentActivityIntent(this);
            if (NavUtils.shouldUpRecreateTask(this, upIntent) || isTaskRoot()) {
                TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent)
                        .startActivities();
            } else {
                finish();
            }
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}
 0
Author: user2837615,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-10 13:06:25