74

我的主要活动Aandroid:launchMode="singleTask"在清单中设置。现在,每当我从那里开始另一个活动时,例如B并按下HOME BUTTON手机上的返回主屏幕然后再次返回我的应用程序,或者通过按下应用程序的按钮或HOME BUTTON长按显示我最近的应用程序它没有'不保留我的活动堆栈并直接返回A而不是预期的活动B

这里有两种行为:

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

是否有我缺少的设置或者这是一个错误?如果是后者,在修复错误之前是否有解决方法?

仅供参考:这个问题已经在这里讨论过了。但是,似乎还没有任何真正的解决方案。

4

12 回答 12

45

这不是错误。当启动现有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 的 launchMode 为“Standard”时,情况就不同了。包含 A 的任务将进入前台并保持与以前相同的状态。

您可以创建一个“标准”活动,例如。C作为启动器和C的onCreate方法中的startActivity(A)

或者

每当向 A 调用意图时,只需删除launchMode="singleTask"and 设置标志FLAG_ACTIVITY_CLEAR_TOP|FLAG_ACTIVITY_SINGLE_TOP

于 2010-06-09T03:16:20.157 回答
8

来自http://developer.android.com/guide/topics/manifest/activity-element.htmlsingleTask

系统在新任务的根部创建活动并将意图路由到它。但是,如果活动的实例已经存在,系统会通过调用其 onNewIntent() 方法将意图路由到现有实例,而不是创建一个新实例。

这意味着当 action.MAIN 和 category.LAUNCHER 标志从 Launcher 指向您的应用程序时,系统宁愿将意图路由到现有的 ActivityA,而不是创建新任务并将新的 ActivityA 设置为根。它宁愿拆除现有任务 ActivityA 所在的所有活动,并调用它的 onNewIntent()。

如果您想同时捕获 singleTop 和 singleTask 的行为,请使用 singleTask launchMode 创建一个名为 SingleTaskActivity 的单独“委托”活动,该活动只需在其 onCreate() 中调用 singleTop 活动,然后自行完成。singleTop 活动仍将具有 MAIN/LAUNCHER 意图过滤器以继续充当应用程序的主要 Launcher 活动,但当其他活动希望调用此 singleTop 活动时,它必须改为调用 SingleTaskActivity 以保留 singleTask 行为。传递给 singleTask 活动的意图也应该传递给 singleTop 活动,所以像下面这样的东西对我有用,因为我想同时拥有 singleTask 和 singleTop 启动模式。

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

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

并且您的 singleTop 活动将继续具有其 singleTop 启动模式。

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

祝你好运。

于 2015-08-31T18:20:09.560 回答
5

Stefan,你找到答案了吗?我为此编写了一个测试用例,并且看到了相同的(令人困惑的)行为......我将粘贴下面的代码以防有人出现并看到明显的东西:

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>

活动A.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 );
  }
}

活动B.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”活动在堆栈中可能有也可能没有其他活动。如果是这样,它就无法处理该意图,并且该意图被丢弃。(即使意图被放弃,它的到来也会导致任务来到前台,它会保留在那里。)

于 2010-06-07T05:54:13.530 回答
3

我认为这是您想要的行为:

singleTask 出于某种我不明白的迟钝原因重置了家庭印刷机上的堆栈。解决方案是不使用 singleTask 而是使用标准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 中添加

如果设置,此活动将成为此历史堆栈上新任务的开始。任务(从启动它的活动到下一个任务活动)定义了用户可以移动到的活动的原子组。任务可以移到前台和后台;特定任务中的所有活动始终保持相同的顺序。有关任务的更多信息,请参阅任务和返回堆栈。

该标志通常由想要呈现“启动器”样式行为的活动使用:它们为用户提供可以完成的单独事情的列表,否则这些事情会完全独立于启动它们的活动运行。

使用此标志时,如果您现在正在启动的 Activity 已经在运行任务,则不会启动新的 Activity;相反,当前任务将简单地以其上次所处的状态被带到屏幕的前面。有关禁用此行为的标志,请参见 FLAG_ACTIVITY_MULTIPLE_TASK。

当调用者从正在启动的活动中请求结果时,不能使用此标志。

和:

FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 在 API 级别 1 中添加

如果设置,并且此活动在新任务中启动或将现有任务置于顶部,则它将作为任务的前门启动。这将导致应用使该任务处于适当状态所需的任何关联(将活动移入或移出),或者在需要时将该任务简单地重置为其初始状态。

没有它们,启动的活动将被推送到旧堆栈或其他一些不良行为的顶部(当然在这种情况下)

我相信没有收到最新 Intent 的问题可以这样解决(我想不到):

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

试试看!

于 2014-10-14T11:09:49.923 回答
2

我发现这个问题只有在启动器活动的启动模式设置为 singleTask 或 singleInstance 时才会发生。

因此,我创建了一个新的启动器活动,其启动模式为标准或单顶。并使这个启动器活动调用我的启动模式为单任务的旧主要活动。

LauncherActivity (standard/no history) -> MainActivity (singleTask).

将启动画面设置为启动器活动。并在我调用主要活动后立即终止了启动器活动。

public LauncherActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Intent intent = new Intent(this, HomeActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
    startActivity(intent);
    finish();
  }
}
<activity
  android:name=".LauncherActivity"
  android:noHistory="true"
  android:theme="@style/Theme.LauncherScreen">

    <intent-filter>
      <action android:name="android.intent.action.MAIN"/>

      <category android:name="android.intent.category.DEFAULT"/>
      <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>

</activity>

<!-- Launcher screen theme should be set for the case that app is restarting after the process is killed. -->
<activity
  android:name=".MainActivity"
  android:launchMode="singleTask"
  android:theme="@style/Theme.LauncherScreen"/>

优点:可以将 MainActivity 的启动模式保持为 singleTask,以确保 MainActivity 始终不超过一个。

于 2019-12-09T15:02:38.527 回答
1

如果 A 和 B 都属于同一个Application,请尝试删除

android:launchMode="singleTask"

来自您的Activities和测试,因为我认为默认行为是您所描述的预期行为。

于 2010-03-10T15:41:24.827 回答
0

每当您按下主页按钮返回主屏幕时,活动堆栈都会杀死一些以前启动和运行的应用程序。

要验证这一事实,请尝试在您的应用程序中从 A 转到 B 后从通知面板启动一个应用程序,然后使用返回按钮.........您会发现您的应用程序处于与您相同的状态留下它。

于 2010-08-11T06:16:26.960 回答
0

Add below in android manifest activity, it will add new task to top of the view destroying earlier tasks. android:launchMode="singleTop" as below

 <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:launchMode="singleTop"
        android:theme="@style/AppTheme.NoActionBar">
    </activity>
于 2018-08-27T19:10:42.060 回答
0

在儿童活动或 B 活动中

@Override
public void onBackPressed() {
   
        Intent intent = new Intent(getApplicationContext(), Parent.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
        startActivity(intent);
        finish();
    

}
于 2022-01-24T12:19:56.127 回答
0

This is how I finally solved this weird behavior. In AndroidManifest, this is what I added:

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>"
于 2016-11-30T16:31:27.833 回答
0

当将启动模式用作 singleTop 时,请确保在启动下一个活动(使用 startActivity(Intent) 方法说 B)时调用 finish()(在当前活动上说 A)。这样当前的活动就会被破坏。A -> B -> 暂停应用并点击启动器图标,启动 A 在 A 的 oncreate 方法中,您需要进行检查,

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

这样,在启动应用程序时,我们正在检查根任务,而之前的根任务是 B 而不是 A。因此,此检查会破坏活动 A 并将我们带到当前位于堆栈顶部的活动 B。希望这对你有用!。

于 2016-07-07T15:53:42.897 回答
-1
        <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”来维护您的应用程序的单个实例。去显化和改变。

于 2017-10-13T03:54:30.050 回答