Android:launchMode ="singleTask"中的错误? - >活动堆栈未保留

znq*_*znq 63 android activity-stack

我的主要活动A已经android:launchMode="singleTask"在清单中设置了.现在,每当我从那里开始另一个活动,例如B并按下HOME BUTTON手机上的电话返回到主屏幕,然后再次返回我的应用程序,可以通过按应用程序的按钮或按下HOME BUTTON长按来显示我最近的应用程序不保留我的活动堆栈并直接返回A而不是预期的活动B.

这里有两个行为:

Expected: A > B > HOME > B
Actual: A > B > HOME > A (bad!)
Run Code Online (Sandbox Code Playgroud)

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

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

小智 42

这不是一个错误.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}
Run Code Online (Sandbox Code Playgroud)

结果是A> B> HOME> A.

当A的launchMode为"标准"时,它会有所不同.包含A的任务将到达前台并保持状态与以前相同.

您可以创建"标准"活动,例如.C作为启动器和C的onCreate方法中的startActivity(A)

要么

只要调用A的意图,只需删除launchMode="singleTask"并设置FLAG_ACTIVITY_CLEAR_TOP|FLAG_ACTIVITY_SINGLE_TOP标志即可

  • 嗨,但是在文档中,没有任何关于"当一个已存在的"singleTask"活动正在启动时,它上面的所有其他活动都将被销毁." 以及为什么在启动模式为"标准"时行为会有所不同?如果任务已从最近的列表中恢复,那么至少应该恢复任务,不是吗?活动管理器应该设置`FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY`而不是`FLAG_ACTIVITY_RESET_IF_NEEDED`. (10认同)

Rya*_*yan 7

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

系统在新任务的根目录下创建活动,并将意图路由到该任务.但是,如果活动的实例已存在,系统会通过调用其onNewIntent()方法将意图路由到现有实例,而不是创建新实例.

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

如果要同时捕获singleTop和singleTask的行为,请使用singleTask launchMode创建一个名为SingleTaskActivity的单独"委托"活动,该活动只是在其onCreate()中调用singleTop活动,然后完成自身.singleTop活动仍然有MAIN/LAUNCHER intent-filters继续充当应用程序的主要Launcher活动,但是当其他活动需要调用此singleTop活动时,它必须调用SingleTaskActivity以保留singleTask行为.传递给singleTop活动的意图也应该转移到singleTop Activity,所以类似下面的内容对我有用,因为我想同时拥有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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

    <activity
        android:name=".activities.SingleTopActivity"
        android:launchMode="singleTop"/>
Run Code Online (Sandbox Code Playgroud)

祝好运.

  • 很棒的解决方案。为了完整起见,您还需要重定向发送到`SingleTaskActivity`的`onNewIntent()`函数的意图。另外,如果您的应用使用深层链接,请确保在清单中的“ SingleTaskActivity”上声明深层链接意图过滤器。 (2认同)

Eri*_*ric 5

斯蒂芬,你有没有找到答案?我为此设置了一个测试用例,并且看到了同样的(令人困惑的)行为......我会粘贴下面的代码,以防有人出现并看到明显的东西:

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>
Run Code Online (Sandbox Code Playgroud)

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 );
  }
}
Run Code Online (Sandbox Code Playgroud)

ActivityB.java:

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

我试过改变minSdkVersion无济于事.这似乎只是一个错误,至少根据文档说明,其中说明如下:

如上所述,"singleTask"或"singleInstance"活动永远不会超过一个实例,因此该实例应该处理所有新意图."singleInstance"活动始终位于堆栈的顶部(因为它是任务中唯一的活动),因此它始终处于处理意图的位置.但是,"singleTask"活动在堆栈中可能有也可能没有其他活动.如果是,则无法处理意图,并且意图被删除.(即使意图被删除,它的到来也会导致任务进入前台,它将保留在前台.)


Die*_*ano 1

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

android:launchMode="singleTask"
Run Code Online (Sandbox Code Playgroud)

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