我在使用Android市场上的“Open”按钮启动应用程序时遇到了一个错误。似乎从市场上推出它会使用不同的意图,然后从手机的应用程序菜单中启动它。这导致启动相同活动的多个副本,这些副本相互冲突。
例如,如果我的应用包含活动A-B-C,则上述问题可能导致堆栈A-B-C-A。
我尝试在所有活动上使用android:launchMode="singleTask"
来解决这个问题,但每当我点击HOME时,它都会产生不必要的副作用,即将活动堆栈清除为root。
示例: A-B-C - >首页 - > A当我需要的是A-B-C - >首页 - > A-B-C
使用HOME时,是否有一种防止启动相同类型的多个活动而不重置root活动的好方法?
答案 0 :(得分:174)
将此添加到onCreate,你应该好好去:
// Possible work around for market launches. See https://issuetracker.google.com/issues/36907463
// for more details. Essentially, the market launches the main activity on top of other activities.
// we never want this to happen. Instead, we check if we are the root and if not, we finish.
if (!isTaskRoot()) {
final Intent intent = getIntent();
if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && Intent.ACTION_MAIN.equals(intent.getAction())) {
Log.w(LOG_TAG, "Main Activity is not the root. Finishing Main Activity instead of launching.");
finish();
return;
}
}
答案 1 :(得分:23)
我只想解释它失败的原因,以及如何以编程方式重现此错误,以便将其合并到测试套件中:
当您通过Eclipse或Market App启动应用时,它会使用意图标记启动:FLAG_ACTIVITY_NEW_TASK。
通过启动器(home)启动时,它使用标志:FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_BROUGHT_TO_FRONT | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,并使用操作“ MAIN ”和类别“ LAUNCHER ”。
如果您想在测试用例中重现这一点,请使用以下步骤:
adb shell am start -f 0x10000000 -n com.testfairy.tests.regression.taskroot/.MainActivity
然后做任何事情来进行其他活动。为了我的目的,我只是放了一个按钮来启动另一个活动。然后,用:
返回启动器(主页)adb shell am start -W -c android.intent.category.HOME -a android.intent.action.MAIN
并模拟通过启动器启动它:
adb shell am start -a "android.intent.action.MAIN" -c "android.intent.category.LAUNCHER" -f 0x10600000 -n com.testfairy.tests.regression.taskroot/.MainActivity
如果您尚未合并isTaskRoot()解决方法,则会重现该问题。我们在自动测试中使用它来确保此错误不再发生。
希望这有帮助!
答案 2 :(得分:6)
您是否尝试过 singleTop 启动模式?
以下是http://developer.android.com/guide/topics/manifest/activity-element.html的一些说明:
......“singleTop”的新实例 也可以创建活动来处理 一个新的意图。但是,如果是目标 任务已经有一个现有的实例 在其顶部的活动 堆栈,该实例将收到 新意图(在onNewIntent()调用中); 未创建新实例。在 其他情况 - 例如,如果 一个现有的实例 “singleTop”活动在目标中 任务,但不是在堆栈的顶部, 或者如果它位于堆栈的顶部,但是 不在目标任务中 - 一个新的 将创建并推送实例 在堆栈上。
答案 3 :(得分:4)
也许是this issue?或者同一个bug的其他形式?
答案 4 :(得分:2)
我认为接受的答案(Duane Homick)有未处理的案例:
你有不同的额外内容(结果是app重复):
这是一个解决方案(SDK_INT> = 11用于通知),我相信它们也可以处理这些案例和状态栏通知。
<强>清单强>:
<activity
android:name="com.acme.activity.LauncherActivity"
android:noHistory="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<service android:name="com.acme.service.LauncherIntentService" />
启动器活动:
public static Integer lastLaunchTag = null;
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mInflater = LayoutInflater.from(this);
View mainView = null;
mainView = mInflater.inflate(R.layout.act_launcher, null); // empty layout
setContentView(mainView);
if (getIntent() == null || getIntent().getExtras() == null || !getIntent().getExtras().containsKey(Consts.EXTRA_ACTIVITY_LAUNCH_FIX)) {
Intent serviceIntent = new Intent(this, LauncherIntentService.class);
if (getIntent() != null && getIntent().getExtras() != null) {
serviceIntent.putExtras(getIntent().getExtras());
}
lastLaunchTag = (int) (Math.random()*100000);
serviceIntent.putExtra(Consts.EXTRA_ACTIVITY_LAUNCH_TAG, Integer.valueOf(lastLaunchTag));
startService(serviceIntent);
finish();
return;
}
Intent intent = new Intent(this, SigninActivity.class);
if (getIntent() != null && getIntent().getExtras() != null) {
intent.putExtras(getIntent().getExtras());
}
startActivity(intent);
}
<强>服务强>:
@Override
protected void onHandleIntent(final Intent intent) {
Bundle extras = intent.getExtras();
Integer lastLaunchTag = extras.getInt(Consts.EXTRA_ACTIVITY_LAUNCH_TAG);
try {
Long timeStart = new Date().getTime();
while (new Date().getTime() - timeStart < 100) {
Thread.currentThread().sleep(25);
if (!lastLaunchTag.equals(LauncherActivity.lastLaunchTag)) {
break;
}
}
Thread.currentThread().sleep(25);
launch(intent);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void launch(Intent intent) {
Intent launchIintent = new Intent(LauncherIntentService.this, LauncherActivity.class);
launchIintent.addCategory(Intent.CATEGORY_LAUNCHER);
launchIintent.setAction(Intent.ACTION_MAIN);
launchIintent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
launchIintent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
if (intent != null && intent.getExtras() != null) {
launchIintent.putExtras(intent.getExtras());
}
launchIintent.putExtra(Consts.EXTRA_ACTIVITY_LAUNCH_FIX, true);
startActivity(launchIintent);
}
<强>通知强>:
ComponentName actCN = new ComponentName(context.getPackageName(), LauncherActivity.class.getName());
Intent contentIntent = new Intent(context, LauncherActivity.class);
contentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= 11) {
contentIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); // if you need to recreate activity stack
}
contentIntent.addCategory(Intent.CATEGORY_LAUNCHER);
contentIntent.setAction(Intent.ACTION_MAIN);
contentIntent.putExtra(Consts.EXTRA_CUSTOM_DATA, true);
答案 5 :(得分:2)
我意识到这个问题与Xamarin Android没有任何关系,但我想发帖,因为我没有在其他任何地方看到它。
要在Xamarin Android中修复此问题,我使用了@DuaneHomick中的代码并添加到MainActivity.OnCreate()
中。与Xamarin的区别在于必须在Xamarin.Forms.Forms.Init(this, bundle);
和LoadApplication(new App());
之后。所以我的OnCreate()
看起来像是:
protected override void OnCreate(Bundle bundle) {
base.OnCreate(bundle);
Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App());
if(!IsTaskRoot) {
Intent intent = Intent;
string action = intent.Action;
if(intent.HasCategory(Intent.CategoryLauncher) && action != null && action.Equals(Intent.ActionMain, System.StringComparison.OrdinalIgnoreCase)) {
System.Console.WriteLine("\nIn APP.Droid.MainActivity.OnCreate() - Finishing Activity and returning since a second MainActivity has been created.\n");
Finish();
return; //Not necessary if there is no code below
}
}
}
*编辑:从Android 6.0开始,上述解决方案对于某些情况来说还不够。我现在还将LaunchMode
设置为SingleTask
,这似乎使事情再次正常运行。不幸的是,不确定这会对其他事情产生什么影响。
答案 6 :(得分:0)
我也有这个问题
android:configChanges="mcc|mnc"
- 如果您已连接到蜂窝网络,请参阅http://developer.android.com/guide/topics/manifest/activity-element.html#config,了解启动系统或推开或其他任何配置。 答案 7 :(得分:0)
试试这个解决方案:
创建Application
类并在那里定义:
public static boolean IS_APP_RUNNING = false;
然后在onCreate
之前的setContentView(...)
中的第一个(启动器)活动添加此内容:
if (Controller.IS_APP_RUNNING == false)
{
Controller.IS_APP_RUNNING = true;
setContentView(...)
//Your onCreate code...
}
else
finish();
P.S。 Controller
是我的Application
课程。
答案 8 :(得分:-1)
我遇到了同样的问题,我使用以下解决方案修复了它。
在您的主要活动中,将此代码添加到onCreate
方法的顶部:
ActivityManager manager = (ActivityManager) this.getSystemService( ACTIVITY_SERVICE );
List<RunningTaskInfo> tasks = manager.getRunningTasks(Integer.MAX_VALUE);
for (RunningTaskInfo taskInfo : tasks) {
if(taskInfo.baseActivity.getClassName().equals(<your package name>.<your class name>) && (taskInfo.numActivities > 1)){
finish();
}
}
不要忘记在清单中添加此权限。
< uses-permission android:name="android.permission.GET_TASKS" />
希望它可以帮到你。
答案 9 :(得分:-2)
尝试使用 SingleInstance 启动模式,并将亲缘关系设置为 allowtaskreparenting 这将始终在新任务中创建活动,但也允许其重新创建。 检查dis:Affinity attribute
答案 10 :(得分:-2)
我找到了一种防止开始相同活动的方法,这对我很有用
if ( !this.getClass().getSimpleName().equals("YourActivityClassName")) {
start your activity
}