Как я могу вернуться к родительской деятельности правильно?

У меня есть 2 действия (A и B) в моем приложении для Android, и я использую намерение перейти от действия A к действию B. Использование parent_activity включено:

 <activity
        android:name=".B"
        android:label="B" >
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.app_name.A" />
  </activity>

Я также использую тему, которая обеспечивает кнопку UP.

Поэтому после того, как я вызвал операцию B I, можно использовать кнопку UP, чтобы вернуться к операции A. Проблема заключается в том, что приложение, похоже, снова вызывает функцию onCreate() операции A, и это не то поведение, которое мне нужно. Мне нужно, чтобы упражнение A выглядело так же, как оно выглядело до того, как я назвал упражнение B.

Есть ли способ добиться этого?

заранее спасибо

РЕДАКТИРОВАТЬ:

Я не написал никакого кода для запуска действия B из действия A. Я думаю, что он автоматически генерируется Eclipse.

Класс B выглядит так:

    @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_b);
    getActionBar().setDisplayHomeAsUpEnabled(true);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_b, menu);
    return true;
}


@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            NavUtils.navigateUpFromSameTask(this);
            return true;
    }
    return super.onOptionsItemSelected(item);
}

17 ответов

Решение

Вы объявили активность А со стандартом launchMode в манифесте Android. Согласно документации это означает следующее:

Система всегда создает новый экземпляр действия в целевой задаче и направляет намерение к нему.

Следовательно, система вынуждена воссоздать действие A (т.е. onCreate), даже если стек задач обрабатывается правильно.

Чтобы решить эту проблему, вам нужно изменить манифест, добавив следующий атрибут в объявление действия A:

android:launchMode="singleTop"

Примечание: звонок finish() (как предлагалось ранее в качестве решения) работает только в том случае, если вы абсолютно уверены, что экземпляр действия B, который вы прерываете, живет поверх экземпляра действия A. В более сложных рабочих процессах (например, при запуске действия B из уведомления) это может не произойти. в этом случае, и вы должны правильно запустить действие A из B.

Обновленный ответ: Навигация вверх

Вы должны указать, какое действие является подходящим родителем для каждого действия. Это позволяет системе упростить шаблоны навигации, такие как Up, поскольку система может определить логическое родительское действие из файла манифеста.

Поэтому для этого вы должны объявить родительскую активность в теге Activity с атрибутом

android:parentActivityName

Подобно,

<!-- The main/home activity (it has no parent activity) -->
    <activity
        android:name="com.example.app_name.A" ...>
        ...
    </activity>
    <!-- A child of the main activity -->
    <activity
        android:name=".B"
        android:label="B"
        android:parentActivityName="com.example.app_name.A" >
        <!-- Parent activity meta-data to support 4.0 and lower -->
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.app_name.A" />
    </activity>

С родительским действием, объявленным таким образом, вы можете перейти к соответствующему родителю, как показано ниже,

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    // Respond to the action bar's Up/Home button
    case android.R.id.home:
        NavUtils.navigateUpFromSameTask(this);
        return true;
    }
    return super.onOptionsItemSelected(item);
}

Поэтому, когда вы звоните NavUtils.navigateUpFromSameTask(this); этот метод завершает текущее действие и запускает (или возобновляет) соответствующее родительское действие. Если целевое родительское действие находится в заднем стеке задачи, оно переносится, как определено FLAG_ACTIVITY_CLEAR_TOP,

И чтобы отобразить кнопку вверх, вы должны объявить setDisplayHomeAsUpEnabled():

@Override
public void onCreate(Bundle savedInstanceState) {
    ...
    getActionBar().setDisplayHomeAsUpEnabled(true);
}

Старый ответ: (без навигации вверх, по умолчанию навигация назад)

Это происходит только в том случае, если вы снова запускаете Занятие A из Занятия B.

С помощью startActivity(),

Вместо этого из Занятия А начните Занятие Б, используя startActivityForResult() и переопределить onActivtyResult() в Деятельности А.

Теперь в Деятельности B просто позвоните finish() на кнопку вверх. Итак, теперь вы направили на деятельность А onActivityResult() без создания Действия A снова..

У меня была почти такая же настройка, которая привела к тому же нежелательному поведению. Для меня это сработало: добавление следующего атрибута в действие A в Manifest.xml моего приложения:

android:launchMode="singleTask"

Смотрите эту статью для более подробного объяснения.

Хотя это старый вопрос, здесь есть другое (imho самое чистое и лучшее) решение, так как все предыдущие ответы не работали на меня, так как я связал действие B с виджетом.

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

[ /questions/5652355/navutilsnavigateupto-ne-zapuskaet-nikakih-dejstvij/5652398#5652398 ]

Но также смотрите: https://speakerdeck.com/jgilfelt/this-way-up-implementing-effective-navigation-on-android

Лучший способ добиться этого - использовать две вещи: call:

NavUtils.navigateUpFromSameTask(this);

Теперь, чтобы это работало, вам нужно, чтобы в файле манифеста было указано, что действие A имеет родительское действие B. Для родительского действия ничего не нужно. В версии 4 и выше вы получите красивую стрелку назад без каких-либо дополнительных усилий (это можно сделать и в более низких версиях с небольшим кодом, я опишу это ниже). Эти данные можно установить на вкладке manifest->application в графическом интерфейсе (прокрутите вниз до имени родительского действия и введите его вручную)

Узел поддержки:

если вы хотите поддерживать версию ниже версии 4, вам также необходимо включить метаданные. щелкните правой кнопкой мыши на активности, добавьте-> метаданные, name =android.support.PARENT_ACTIVITY и value = your.full.activity.name

чтобы получить красивую стрелку в более низких версиях:

getSupportActionBar().setDisplayHomeAsUpEnabled(true);

обратите внимание, вам понадобится поддержка библиотеки версии 7, чтобы все это заработало, но оно того стоит!

Что сработало для меня, это добавить:

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch (item.getItemId()) {
            case android.R.id.home:
                onBackPressed();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public void onBackPressed() {
        finish();
    }

в TheRelevantActivity.java и теперь он работает как положено

и да, не забудьте добавить:

getSupportActionbar.setDisplayHomeAsUpEnabled(true); в onCreate() метод

Добавление к ответу @LorenCK, изменение

NavUtils.navigateUpFromSameTask(this);

в приведенный ниже код, если ваша деятельность может быть инициирована из другой деятельности, и это может стать частью задачи, запущенной другим приложением

Intent upIntent = NavUtils.getParentActivityIntent(this);
if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
    TaskStackBuilder.create(this)
            .addNextIntentWithParentStack(upIntent)
            .startActivities();
} else {
    NavUtils.navigateUpTo(this, upIntent);
}

Это запустит новую задачу и запустит родительскую активность вашей деятельности, которую вы можете определить в манифесте, как показано ниже в версии Min SDK <= 15

<meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value="com.example.app_name.A" />

Или используя parentActivityName если его> 15

Я старался android:launchMode="singleTask", но это не помогло. Работал для меня, используя android:launchMode="singleInstance"

У меня была похожая проблема с использованием Android 5.0 с плохим именем родительского действия

<activity
        android:name=".DisplayMessageActivity"
        android:label="@string/title_activity_display_message"
        android:parentActivityName=".MainActivity" >
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.myfirstapp.MainActivity" />
    </activity>

Я удалил com.example.myfirstapp из имени родительского действия, и он работал правильно

В классе Java:-

    toolbar = (Toolbar) findViewById(R.id.apptool_bar);
    setSupportActionBar(toolbar);

    getSupportActionBar().setTitle("Snapdeal");

    getSupportActionBar().setHomeButtonEnabled(true);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

В Манифесте:-

<activity
            android:name=".SubActivity"
            android:label="@string/title_activity_sub"
            android:theme="@style/AppTheme" >
            <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".MainActivity"></meta-data>
    </activity>

Это поможет тебе

Добавьте к своей деятельности информацию манифеста с атрибутом

android:launchMode="singleTask"

работает хорошо для меня

Попробуй это:

Intent intent;
@Override
public void onCreate(Bundle savedInstanceState) {
intent = getIntent();   
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
getActionBar().setDisplayHomeAsUpEnabled(true);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_b, menu);
return true;
}  


@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
    case android.R.id.home:
    NavUtils.navigateUpTo(this,intent);
        return true;
}
return super.onOptionsItemSelected(item);
}
    @Override
public boolean onOptionsItemSelected(MenuItem item) {
   switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
    case android.R.id.home:
        finish();
        return true;
}
return super.onOptionsItemSelected(item);

как бэк пресс

В любом контексте, если вы хотите открыть родительскую активность на onBackPressed

      protected fun navigateToParent() {
        NavUtils.getParentActivityIntent(this)?.let { upIntent ->
            if (NavUtils.shouldUpRecreateTask(this, upIntent) || isTaskRoot) {
                Timber.d("navigateToParent: sourceActivity should recreate")
                startActivity(upIntent)
            } else {
                Timber.d("navigateToParent: sourceActivity in stack, just finish")
            }
        }
        super.onBackPressed()
    }

Установлен android:parentActivityNameв манифесте

       <activity
            android:name=".feature.signup.SignUpActivity"
            android:parentActivityName=".feature.welcome.WelcomeActivity"
            android:windowSoftInputMode="adjustResize" />

Попробуйте это решение использовать NavUtils.navigateUpFromSameTask(это); в детской деятельности: /questions/9634927/android-obnovit-roditelskuyu-aktivnost-kogda-dochernyaya-aktivnost-zakanchivaetsya/9634932#9634932

Зайдя в мой манифест и добавив android:launchMode="singleTop" для деятельности сделал свое дело для меня.

Это определенно решило мою проблему, потому что я не хотел, чтобы Android создавал новый экземпляр предыдущего действия после нажатия кнопки Up кнопка на панели инструментов - вместо этого я хотел использовать существующий экземпляр предыдущего действия, когда я поднялся вверх по иерархии навигации.

Ссылка: android: launchMode

Использование finish() в действии, чтобы вернуться, когда в вашем событии клика.

Другие вопросы по тегам