Подтвердить что ты не робот

Как закончить разрушенную деятельность

Как я понимаю, уничтожаемая деятельность не эквивалентна завершаемой деятельности.

  • Закончено
    • Действие удаляется из back stack.
    • Это может быть вызвано программой (например, вызывая finish()) или пользователем, нажимая клавишу возврата (которая неявно вызывает finish()).
    • Завершение действия уничтожит его.
  • Разрушенный
    • ОС Android может уничтожить невидимую активность для восстановления памяти. Активность будет воссоздана, когда пользователь перейдет к ней.
    • Действие уничтожается и воссоздается, когда пользователь поворачивает экран.
    • Ссылка: Восстанавливает активность

Итак как закончить уничтоженное действие? Для метода finish() требуется Activity объект, но если активность разрушена, у меня нет объекта Activity - я не должен ссылаться на уничтоженное действие, я


Пример:

У меня есть активность a, которая начинается с b, которая, в свою очередь, запускает c (используя Activity.startActivity()) поэтому теперь back stack:

a → b → c

В c пользователь заполнит форму и нажмите кнопку "Отправить". Сетевой запрос выполняется на удаленном сервере с помощью AsyncTask. После завершения задачи я покажу toast и закончу операцию, вызвав c.finish(). Совершенная.

Теперь рассмотрим этот сценарий:

Пока выполняется асинхронная задача, пользователь переключается на другое приложение. Затем ОС Android решила уничтожить все 3 действия (a, b, c) из-за ограничений памяти. Позже задача async завершена. Теперь как закончить c?

Что я пробовал:

  • Вызов c.finish():
    • Невозможно, потому что c уничтожен.
  • Вызов b.finishActivity():
    • Невозможно, потому что b уничтожен.
  • Используйте Context.startActivity() с FLAG_ACTIVITY_CLEAR_TOP, чтобы поднять b к вершине, тем самым завершая c:

    // appContext is an application context, not an activity context (which I don't have)
    Intent intent = new Intent(appContext, B.class);    // B is b class.
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    appContext.startActivity(intent);
    
    • Сбой, appContext.startActivity() выдает исключение:

android.util.AndroidRuntimeException: для вызова функции startActivity() извне контекста действия требуется флаг FLAG_ACTIVITY_NEW_TASK. Это действительно то, что вы хотите?

Изменить: Уточнение: мне нужно дождаться завершения задачи async и решить, завершить ли c на основе ответа сервера.

4b9b3361

Ответ 1

Невозможно закончить разрушенную деятельность напрямую, поэтому просто finish() в ее onCreate() (предлагается @Labeeb P). Вот как:

  • Если действие уже уничтожено при попытке его завершить, сохраните вместо этого логический флаг.

    if(activity != null)
    {
        // Activity object still valid, so finish() now.
        activity.finish();
    }
    else
    {
        // Activity is destroyed, so save a flag.
        is_activity_pending_finish = true;
    }
    
    • Если флаг должен оставаться, даже если приложение уничтожено, используйте постоянное хранилище, например. SharedPreferences (предлагается @Labeeb P).
  • В действии onCreate() установите флажок и вызовите finish().

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
    
        if(is_activity_pending_finish)
        {
            is_activity_pending_finish = false; // Clear the flag.
    
            // This activity should have been finished, so finish it now.
            finish();
            return;
        }
    
        ...
    }
    
    • Если существует несколько экземпляров одного и того же класса Activity, вам может понадобиться нечто большее, чем логический флаг, чтобы идентифицировать конкретный экземпляр действия для завершения.

Вызов finish() в onCreate() - фактически операция legimate, как указано в документ:

... вы можете называть finish() из onCreate(), чтобы уничтожить действие. В этом случае система немедленно вызывает onDestroy() без вызова каких-либо других методов жизненного цикла.


Другие соображения:

  • Возможно, неплохо завершить работу, пока приложение находится в фоновом режиме, особенно если это единственное действие. Убедитесь, что вы не путаете пользователя.
  • Чтобы улучшить работу пользователя, если вы закончите работу, когда приложение находится в фоновом режиме, вы можете сообщить об этом пользователю. Рассмотрите возможность использования toasts (полезно для коротких уведомлений) или notifications (полезно для длительных операций, которые пользователь мог забыть) (предложенный @Stephan Branczyk и @dilix).

Конечно, уничтожаемая деятельность не обязательно означает, что приложение находится в фоновом режиме (может быть другая деятельность переднего плана). Тем не менее, приведенное выше решение (вызов finish() в onCreate()) работает.

Ответ 2

android.util.AndroidRuntimeException: вызов функции startActivity() из вне контекста Activity требуется FLAG_ACTIVITY_NEW_TASK флаг. Это действительно то, что вы хотите?

  • Это исключение используется, когда вы начинаете действие с
    фоновый поток или услугу. Вам нужно пройти мимо FLAG_ACTIVITY_NEW_TASK флаг, когда вам нужна "пусковая установка"
    тип поведения.

    • Просто добавьте mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);, чтобы избежать этого исключения.

  • Способ, которым вы пытаетесь убить активность, не рекомендуется, пусть Андроид-ручка. Нет смысла заканчивать деятельность который уже уничтожен.

Теперь, что вы можете сделать?

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

  • Я думаю, что вы пытаетесь убить действие, когда приложение находится в фоновом режиме. Кажется, это немного сложно сделать, но вы можете использовать onUserLeaveHint, чтобы решить, когда приложение идет в фоновом режиме в порядке для завершения действия, или вы можете закончить действие, добавив finish(); в onStop(). Просто убедитесь, что asynctask onPost() не завершает его снова, чтобы избежать исключения.

  • Посмотрите android: clearTaskOnLaunch и установите для него значение true.

    Google Doc говорит об этом атрибуте:

    например, что кто-то запускает активность P с главного экрана, и оттуда переходит в действие Q. Затем пользователь нажимает "Домой" и затем возвращается к активности P. Обычно пользователь будет видеть активность Q, так как это то, что они в последний раз делали в задаче P. Однако, если P set этот флаг равен "true", все действия над ним (Q в этом случай) были удалены, когда пользователь нажал "Домой", и задача перешла к задний план. Таким образом, пользователь видит только P, когда возвращается к задаче.

    и я думаю, что это точный случай, который вы хотите.

Надеюсь, это даст вам некоторый намек на достижение желаемой задачи.

Ответ 3

вы можете транслировать свое действие с помощью метода onPostExecute в c и зарегистрировать широковещательный receiver для получения для этого действия в и b. Затем завершите метод приемника onRevice

В c, AsyncTask,

 void onPostExecute(Long result) {
         ----
         Intent intent1 = new Intent("you custom action");
    context.sendBroadcast(intent1);
     }

В a и b

registerReceiver(new BroadcastReceiver() {

            @Override
            public void onReceive(Context context, Intent intent) {
                finish();

            }
        },new IntentFilter("you custom action"));

Ответ 4

Лично я использовал панель уведомлений, чтобы уведомить пользователя о состоянии его запроса.

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

Ответ 5

Относительно андроидного руководства onDestroy() вызывается точно до того, как действие будет уничтожено, поэтому вы можете называть его завершением (даже вы можете остановить поток bg прежде чем убить деятельность полностью).

Мы можем предположить, что если активность была убита, мы также не заинтересованы в bg-ниве, и, например, если bg-поток должен загружать изображение или и т.д., которые должны быть завершены, так что вам нужно использовать службу вместо asynctask.

Ответ 6

Когда система пытается уничтожить вашу активность, она вызывает onSaveInstanceState. Здесь вы можете позвонить finish(). Что это.

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