Android: ошибка в launchMode = "singleTask"? -> стек активности не сохранился - PullRequest
61 голосов
/ 10 марта 2010

Моя основная деятельность A имеет значение android:launchMode="singleTask" в манифесте. Теперь, когда я начинаю другую деятельность оттуда, например B и нажмите HOME BUTTON на телефоне, чтобы вернуться на домашний экран, а затем снова вернитесь к моему приложению, либо нажав кнопку приложения, либо нажав HOME BUTTON, чтобы показать мои последние приложения, которых нет сохранить мой стек активности и вернуться прямо к A вместо ожидаемой активности B.

Вот два поведения:

Expected: A > B > HOME > B
Actual: A > B > HOME > A (bad!)

Есть ли настройка, которую я пропускаю или это ошибка? Если последнее, есть ли обходной путь для этого, пока ошибка не будет исправлена?

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

Ответы [ 10 ]

41 голосов
/ 09 июня 2010

Это не ошибка. Когда запускается существующее действие singleTask, все остальные действия над ним в стеке будут уничтожены.

Когда вы нажимаете HOME и снова запускаете действие, ActivityManger вызывает намерение

{act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER]flag=FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_RESET_IF_NEEDED cmp=A}

Итак, результат A> B> HOME> A.

Отличается, когда A запускающим режимом является «Стандартный». Задача, содержащая A, выйдет на передний план и сохранит состояние, как и прежде.

Вы можете создать "Стандартное" действие, например. C как средство запуска и startActivity (A) в методе onCreate C

OR

Просто снимите launchMode="singleTask" и установите флаг FLAG_ACTIVITY_CLEAR_TOP|FLAG_ACTIVITY_SINGLE_TOP всякий раз, когда вызываете намерение A

7 голосов
/ 31 августа 2015

С http://developer.android.com/guide/topics/manifest/activity-element.html на singleTask

Система создает действие в корне новой задачи и направляет намерение к ней. Однако, если экземпляр действия уже существует, система направляет намерение к существующему экземпляру посредством вызова его метода onNewIntent () вместо создания нового.

Это означает, что когда флаги action.MAIN и category.LAUNCHER нацелены на ваше приложение из Панели запуска, система скорее направит намерение к существующему ActivityA, чем к созданию новой задачи и установке новой ActivityA в качестве корневого. Скорее, он разрушит все действия над существующей задачей, в которой находится ActivityA, и вызовет ее onNewIntent ().

Если вы хотите зафиксировать как поведение singleTop, так и singleTask, создайте отдельное «делегированное» действие с именем SingleTaskActivity с singleTask launchMode, которое просто вызывает действие singleTop в его onCreate (), а затем завершает себя. Действие singleTop по-прежнему будет иметь фильтры-намерения MAIN / LAUNCHER, чтобы продолжать действовать как основное действие Launcher приложения, но когда другие действия хотят вызвать это действие singleTop, оно должно вместо этого вызывать SingleTaskActivity, чтобы сохранить поведение singleTask. Намерение, передаваемое в действие SingleTask, также должно быть перенесено в действие SingleTop, поэтому что-то вроде следующего сработало для меня, так как я хотел иметь режимы запуска и SingleTask, и SingleTop.

<activity android:name=".activities.SingleTaskActivity"
              android:launchMode="singleTask">

public class SingleTaskActivity extends Activity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent intent = getIntent();
        intent.setClass(this, SingleTop.class);
        startActivity(intent);
    }
}

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

    <activity
        android:name=".activities.SingleTopActivity"
        android:launchMode="singleTop"/>

Удачи.

5 голосов
/ 07 июня 2010

Стефан, ты когда-нибудь нашел ответ на это? Я собрал тестовый пример для этого и вижу то же (недоумение) поведение ... Я вставлю код ниже на случай, если кто-нибудь придет и увидит что-то очевидное:

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example" >

  <uses-sdk android:minSdkVersion="3"/>

  <application android:icon="@drawable/icon" android:label="testSingleTask">

    <activity android:name=".ActivityA"
              android:launchMode="singleTask">
      <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
      </intent-filter>
    </activity>

    <activity android:name=".ActivityB"/>

  </application>
</manifest>

ActivityA.java:

public class ActivityA extends Activity implements View.OnClickListener
{
  @Override
  public void onCreate( Bundle savedInstanceState )
  {
    super.onCreate( savedInstanceState );
    setContentView( R.layout.main );
    View button = findViewById( R.id.tacos );
    button.setOnClickListener( this );
  }

  public void onClick( View view )
  {
    //Intent i = new Intent( this, ActivityB.class );
    Intent i = new Intent();
    i.setComponent( new ComponentName( this, ActivityB.class ) );
    startActivity( i );
  }
}

ActivityB.java:

public class ActivityB extends Activity
{
  @Override
  public void onCreate( Bundle savedInstanceState )
  {
    super.onCreate( savedInstanceState );
    setContentView( R.layout.layout_b );
  }
}

Я попытался изменить minSdkVersion безрезультатно. Это просто ошибка, по крайней мере, согласно документации , которая гласит следующее:

Как отмечалось выше, никогда не бывает более одного экземпляра действия "singleTask" или "singleInstance", поэтому ожидается, что этот экземпляр будет обрабатывать все новые намерения. Действие "singleInstance" всегда находится на вершине стека (поскольку это единственное действие в задаче), поэтому оно всегда в состоянии обработать намерение. Однако действие «singleTask» может иметь или не иметь другие действия над ним в стеке. Если это так, он не в состоянии обработать намерение, и намерение отбрасывается. (Даже если намерение отброшено, его прибытие привело бы к тому, что задача вышла на передний план, где и осталась бы.)

3 голосов
/ 14 октября 2014

Я думаю, это поведение, которое вы хотите:

singleTask сбрасывает стек на домашней прессе по какой-то отсталой причине, которую я не понимаю. Вместо этого решение состоит в том, чтобы не использовать singleTask и использовать standard или singleTop вместо активности запуска (хотя на сегодняшний день я пробовал только с singleTop).

Поскольку приложения имеют сходство друг с другом, запускается такое действие:

Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);
if(launchIntent!=null) {
    launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
}

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

FLAG_ACTIVITY_NEW_TASK Добавлено на уровне API 1

Если установлено, это действие станет началом новой задачи на этом стек истории. Задача (от действия, которое запустило его до следующего действие задачи) определяет элементарную группу действий, которые пользователь может перейти к. Задачи могут быть перемещены на передний план и фон; все действия внутри конкретной задачи всегда остаются неизменными порядок. См. Задачи и Back Stack для получения дополнительной информации о задачах.

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

При использовании этого флага, если задача уже запущена для действия вы сейчас начинаете, тогда новое действие не начнется; вместо этого текущая задача будет просто перенесена на экран с состоянием, в котором он был последним. См. FLAG_ACTIVITY_MULTIPLE_TASK для флага, чтобы отключить это поведение.

Этот флаг нельзя использовать, когда вызывающая сторона запрашивает результат из запускаемая деятельность.

И

FLAG_ACTIVITY_RESET_TASK_IF_NEEDED Добавлено на уровне API 1

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

Без них запущенная активность будет просто перенесена поверх старого стека или какого-либо другого нежелательного поведения (в данном случае, конечно)

Я считаю, что проблему с неполучением последней версии намерения можно решить следующим образом (из моей головы):

@Override
public void onActivityReenter (int resultCode, Intent data) {
    onNewIntent(data);
}

Попробуйте!

1 голос
/ 10 марта 2010

Если A и B принадлежат одному и тому же Application, попробуйте удалить

android:launchMode="singleTask"

из вашего Activities и протестируйте, потому что я думаю, что поведение по умолчанию соответствует описанному вами.

0 голосов
/ 27 августа 2018

Добавьте ниже в активности манифеста Android, он добавит новую задачу в верхней части представления, уничтожая предыдущие задачи. android: launchMode = "singleTop", как показано ниже

 <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:launchMode="singleTop"
        android:theme="@style/AppTheme.NoActionBar">
    </activity>
0 голосов
/ 13 октября 2017
        <activity android:name=".MainActivity"
         android:launchMode="singleTop">
         <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
         </intent-filter>
       </activity>

// Попробуйте использовать launchMode = "singleTop" в своей основной деятельности, чтобы поддерживать один экземпляр вашего приложения. Идите, чтобы проявить и изменить.

0 голосов
/ 30 ноября 2016

Вот как я наконец решил это странное поведение. В AndroidManifest вот что я добавил:

Application & Root activity
            android:launchMode="singleTop"
            android:alwaysRetainTaskState="true"
            android:taskAffinity="<name of package>"

Child Activity
            android:parentActivityName=".<name of parent activity>"
            android:taskAffinity="<name of package>"
0 голосов
/ 07 июля 2016

При использовании режима запуска в качестве singleTop обязательно вызовите метод finish () (для текущей операции, скажем, A), при запуске следующей операции (используя метод startActivity (Intent), скажем, B). Таким образом, текущая активность уничтожается. A -> B -> Приостановить приложение и нажать значок запуска, запускает A В методе A, который требуется создать, вам нужно иметь чек,

if(!TaskRoot()) {
    finish();
     return;
  }

Таким образом, при запуске приложения мы проверяем корневую задачу, и ранее корневая задача была B, но не A. Таким образом, эта проверка уничтожает действие A и переносит нас к действию B, которое в настоящее время является вершиной стека. Надеюсь, у вас это получится!

0 голосов
/ 11 августа 2010

Каждый раз, когда вы нажимаете кнопку «Домой», чтобы вернуться на домашний экран, стек действий убивает некоторые из ранее запущенных и запущенных приложений.

Чтобы убедиться в этом, попробуйте запустить приложение из панели уведомлений после перехода от A к B в своем приложении и вернуться с помощью кнопки назад .......... вы найдете то же приложение укажите, как вы его оставили.

...