다른 의도로 활동이 시작될 때 활동의 여러 인스턴스를 방지하는 방법
Google Play 스토어 앱 (이전의 Android 마켓) 에서 "열기" 버튼을 사용하여 애플리케이션을 시작할 때 버그가 발생했습니다 . Play 스토어 Intent
에서 시작하는 것은 전화의 응용 프로그램 아이콘 아이콘에서 시작 하는 것과는 다른 것 같습니다. 이로 인해 동일한 활동의 여러 사본이 시작되어 서로 충돌합니다.
예를 들어 내 앱이 Activities ABC로 구성된 경우이 문제로 인해 ABCA가 발생할 수 있습니다.
android:launchMode="singleTask"
이 문제를 해결하기 위해 모든 활동을 사용하려고 시도했지만 HOME 버튼을 누를 때마다 활동 스택을 루트로 지우는 원하지 않는 부작용이 있습니다.
예상되는 동작은 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.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
}
}
}
*Edit: Since Android 6.0, the above solution is not enough for certain situations. I have now also set LaunchMode
to SingleTask
, which seems to have made things work correctly once again. Not sure what effects this might have on other things though unfortunately.
I had this problem also
- Don't call finish(); in the home activity it would run endlessly - home activity is being called by ActivityManager when it finished.
- Usually when the configuration is changing (i.e. rotate screen, change language, telephony service changes i.e. mcc mnc etc.) the activity recreate - and if the home activity is running then it calls again to A. for that need to add to manifest
android:configChanges="mcc|mnc"
- if you have connection to cellular, see http://developer.android.com/guide/topics/manifest/activity-element.html#config for which configuration there is when booting the system or push open or whatever.
Try this solution:
Create Application
class and define there:
public static boolean IS_APP_RUNNING = false;
Then in your first (Launcher) Activity in onCreate
before setContentView(...)
add this:
if (Controller.IS_APP_RUNNING == false)
{
Controller.IS_APP_RUNNING = true;
setContentView(...)
//Your onCreate code...
}
else
finish();
P.S. Controller
is my Application
class.
I had the same problem, and I fixed it using the following solution.
In your main activity add this code on the top of the onCreate
method:
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();
}
}
don't forget to add this permission in your manifest.
< uses-permission android:name="android.permission.GET_TASKS" />
hope it helps you.
try using SingleInstance launch mode with affinity set to allowtaskreparenting This will always create the activity in new task but also allow its reparenting. Check dis :Affinity attribute
I found a way to prevent starting same activities, this works great for me
if ( !this.getClass().getSimpleName().equals("YourActivityClassName")) {
start your activity
}
'IT story' 카테고리의 다른 글
웹 애플리케이션이 iOS 기기에 푸시 알림을 보내려면 어떻게해야합니까? (0) | 2020.07.20 |
---|---|
Emacs에서 현재 줄을 어떻게 삭제합니까? (0) | 2020.07.20 |
ImportError : matplotlib.pyplot이라는 모듈이 없습니다. (0) | 2020.07.20 |
Postgres에서 두 필드의 MIN ()을 어떻게 얻습니까? (0) | 2020.07.20 |
앵커 링크에 alt 태그를 사용하는 것이 맞습니까? (0) | 2020.07.20 |