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

时间:2010-03-10 14:12:36

标签: 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!)

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

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

11 个答案:

答案 0 :(得分:41)

这不是错误。当启动现有的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的launchMode为“标准”时,情况有所不同。包含A的任务将到达前台并保持状态与之前相同。

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

只要调用A

意图,只需删除launchMode="singleTask"并设置FLAG_ACTIVITY_CLEAR_TOP|FLAG_ACTIVITY_SINGLE_TOP标记即可

答案 1 :(得分:6)

singleTask

上的Frome http://developer.android.com/guide/topics/manifest/activity-element.html
  

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

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

如果要同时捕获singleTop和singleTask的行为,请创建一个单独的"委托"使用singleTask launchMode命名SingleTaskActivity的活动,它只是在onCreate()中调用singleTop活动,然后自行完成。 singleTop活动仍然会有MAIN / LAUNCHER intent-filters继续充当应用程序的主要Launcher活动,但是当其他活动希望调用此singleTop活动时,它必须调用SingleTaskActivity以保留singleTask行为。传递给singleTask活动的意图也应该转移到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);
    }
}

您的singleTop活动将继续使用singleTop启动模式。

    <activity
        android:name=".activities.SingleTopActivity"
        android:launchMode="singleTop"/>
祝你好运。

答案 2 :(得分: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>

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无济于事。这似乎只是一个错误,至少根据documentation,其中陈述如下:

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

答案 3 :(得分: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中添加

     

如果设置,此活动将成为此任务的新任务的开始   历史堆栈。任务(从启动它到下一个的活动   任务活动)定义用户可以进行的活动的原子组   搬去。任务可以移动到前台和后台;所有的   特定任务内部的活动始终保持不变   订购。有关任务的详细信息,请参阅任务和后台堆栈。

     

此标志通常由想要呈现的活动使用   &#34;发射器&#34;样式行为:它们为用户提供单独的列表   可以完成的事情,否则完全独立运行   启动它们的活动。

     

使用此标志时,如果某个任务已在运行该活动   你现在开始,然后一个新的活动将不会开始;   相反,当前的任务将被简单地带到前面   屏幕显示它的最后状态。请参阅FLAG_ACTIVITY_MULTIPLE_TASK   用于禁用此行为的标志。

     

当呼叫者请求结果时,不能使用此标志   正在推出的活动。

  

FLAG_ACTIVITY_RESET_TASK_IF_NEEDED在API级别1中添加

     

如果已设置,则此活动要么在新任务中启动,要么启动   将现有任务带到顶端,然后它将作为   前门的任务。这将导致任何应用   使这项任务处于适当状态所需的亲和力(要么是移动   来自或来自它的活动),或者只是将该任务重置为它   初始状态,如果需要。

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

我相信没有收到最新意图的问题可以像这样(我的头脑)解决:

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

尝试一下!

答案 4 :(得分:1)

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

android:launchMode="singleTask"
来自Activities

并进行测试,因为我认为默认行为是您所描述的预期行为。

答案 5 :(得分:0)

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

要验证此事实,请尝试在应用中从A到B之后从通知面板启动应用,然后使用后退按钮返回..........您将在同一个应用中找到您的应用当你离开它时说。

答案 6 :(得分:0)

当使用启动模式作为singleTop时,确保在启动下一个活动时调用finish()(在当前活动中说A)(使用startActivity(Intent)方法,如B)。这样,当前活动就会被破坏。 A - &gt; B - &gt;暂停应用程序并单击启动器图标,启动A 在A的oncreate方法中,您需要检查,

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

这种方式在启动app时我们正在检查root任务,之前的root任务是B而不是A.所以这个检查会破坏活动A并将我们带到活动B,这是当前堆栈的顶层。 希望它对你有用!。

答案 7 :(得分:0)

这就是我最终解决这种奇怪行为的方式。在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>"

答案 8 :(得分:0)

        <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 =&#34; singleTop&#34;在您的主要活动中维护您的应用程序的单个实例。去清单和改变。

答案 9 :(得分:0)

在android manifest活动中添加以下内容,它将在视图顶部添加新任务,从而销毁先前的任务。 android:launchMode =“ singleTop”如下

 <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:launchMode="singleTop"
        android:theme="@style/AppTheme.NoActionBar">
    </activity>

答案 10 :(得分:0)

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

因此,我创建了一个新的启动器活动,其启动模式为标准或singleTop。并将这个启动器活动称为我的旧主要活动,该活动的启动模式是单个任务。

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。