Google Play 스토어 앱 (이전에는 Android 마켓이라고 함) 의 “열기” 버튼을 사용하여 애플리케이션을 시작할 때 내 애플리케이션에서 버그를 발견했습니다 . Play 스토어 Intent
에서 실행하는 것은 전화의 응용 프로그램 메뉴 아이콘에서 실행 하는 것과 다른 것을 사용하는 것 같습니다 . 이로 인해 서로 충돌하는 동일한 활동의 여러 복사본이 실행됩니다.
예를 들어 내 앱이 활동 ABC로 구성된 경우이 문제로 인해 ABCA 스택이 발생할 수 있습니다.
android:launchMode="singleTask"
이 문제를 해결하기 위해 모든 활동을 사용하려고 시도했지만 홈 버튼을 누를 때마다 활동 스택을 루트로 지우는 원치 않는 부작용이 있습니다.
예상되는 동작은 다음과 같습니다. ABC-> HOME-> 앱이 복원되면 ABC-> HOME-> ABC가 필요합니다.
HOME 버튼을 사용할 때 루트 활동으로 재설정하지 않고 동일한 유형의 여러 활동이 시작되는 것을 방지하는 좋은 방법이 있습니까?
답변
이것을 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;
}
}
답변
실패한 이유와이 버그를 프로그래밍 방식으로 재현하여 테스트 스위트에 통합 할 수있는 방법을 설명하겠습니다.
-
Eclipse 또는 Market App을 통해 앱을 시작하면 FLAG_ACTIVITY_NEW_TASK 인 텐트 플래그와 함께 시작됩니다.
-
런처 (홈)를 통해 시작할 때 다음 플래그를 사용합니다. 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 () 해결 방법을 통합하지 않은 경우 문제가 재현됩니다. 이 버그가 다시 발생하지 않도록 자동 테스트에서이를 사용합니다.
도움이 되었기를 바랍니다!
답변
singleTop 실행 모드 를 사용해 보셨습니까 ?
다음은 http://developer.android.com/guide/topics/manifest/activity-element.html의 일부 설명입니다 .
… 새로운 인 텐트를 처리하기 위해 “singleTop”활동의 새 인스턴스를 만들 수도 있습니다. 그러나 대상 작업의 스택 맨 위에 이미 활동의 기존 인스턴스가있는 경우 해당 인스턴스는 onNewIntent () 호출에서 새 인 텐트를 수신합니다. 새 인스턴스가 생성되지 않습니다. 다른 상황에서 (예 : “singleTop”활동의 기존 인스턴스가 대상 작업에 있지만 스택의 맨 위에 있지 않은 경우 또는 스택의 맨 위에 있지만 대상 작업에는없는 경우) 새 인스턴스가 생성되고 스택에 푸시됩니다.
답변
아마도이 문제 일까요? 아니면 같은 버그의 다른 형태?
답변
받아 들인 답변 ( Duane Homick )에는 처리되지 않은 사례가 있다고 생각합니다 .
다른 추가 기능이 있으며 결과적으로 앱이 중복됩니다.
- 마켓 또는 홈 화면 아이콘 (마켓에서 자동으로 배치됨)에서 애플리케이션을 실행할 때
- 런처 또는 수동으로 만든 홈 화면 아이콘으로 응용 프로그램을 시작할 때
다음은 이러한 사례와 상태 표시 줄 알림도 처리 할 수있는 솔루션 (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);
답변
나는 질문이 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
일을 다시 한 번 제대로 작동 만든 것으로 보인다. 불행히도 이것이 다른 것들에 어떤 영향을 미칠지 확실하지 않습니다.
답변
나는 같은 문제가 있었고 다음 솔루션을 사용하여 수정했습니다.
주요 활동에서 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" />
도움이되기를 바랍니다.