Нажмите на уведомление, чтобы перейти к текущей деятельности
Я использую это решение: Как возобновить намерение уведомления, а не новое намерение?
Я работаю нормально, когда я запускаю свое приложение в обычном режиме... однако мое приложение имеет функцию общего доступа.
Когда я выбираю изображения, которыми хочу поделиться, из приложения галереи и открываю его в своей активности, я создаю уведомление в активности. Я хочу, чтобы, когда пользователь нажимает на уведомление, он открывает существующее действие (открытое приложением галереи)
Проблема в том, что когда я нажимаю на уведомление, оно не возобновляет эту активность, а вместо этого открывает новый экземпляр действия или другой экземпляр, уже открытый ранее.
Изменить: больше объяснений
Мое приложение называется ShareApp, а действие называется ShareActivity, проблема в том, что когда я открываю ShareActivity через приложение галереи, экземпляр ShareActivity создается в верхней части стека задач приложения галереи. Теперь, когда я создаю уведомление, которое указывает на мою ShareActivity, я использую намерение:
Intent intent = new Intent(this, ShareActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
проблема в том, что когда я нажимаю на уведомление, оно указывает на экземпляр ShareActivity в стеке задачи ShareApp вместо стека задачи приложения галереи.
Любая идея, как указать на правильный стек задач?
редактировать 2: мой код
int defaults = Notification.FLAG_NO_CLEAR;
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(getString(R.string.app_name))
.setContentText(text)
.setDefaults(defaults);
Intent intent = new Intent(this, this.getClass());
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
mBuilder.setContentIntent(pendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(_ID, mBuilder.build());
Правка 3: активность в дампах оболочки adb (после применения кода Дэвидом /questions/16485360/nazhmite-na-uvedomlenie-chtobyi-perejti-k-tekuschej-deyatelnosti/16485378#16485378)
Мое приложение называется shareApp, а моя деятельность - ShareActivity.
Прежде чем нажать на уведомление:
Main stack:
TaskRecord{41965708 #6 A com.android.gallery3d}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.gallery3d/.app.Gallery bnds=[364,50][108,108]}
Hist #2: ActivityRecord{417ccc28 com.yeahman.shareapp/.ShareActivity}
Intent { act=android.intent.action.SEND_MULTIPLE typ=image/* cmp=com.yeahman.shareapp/.ShareActivity (has extras) }
ProcessRecord{41c868d0 6088:com.yeahman.shareapp/10116}
Hist #1: ActivityRecord{4135e540 com.android.gallery3d/.app.Gallery}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.gallery3d/.app.Gallery bnds=[364,50][108,108] }
После нажатия на уведомление:
Main stack:
TaskRecord{41965708 #6 A com.android.gallery3d}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.gallery3d/.app.Gallery bnds=[364,50][108,108]}
Hist #3: ActivityRecord{4169f358 com.android.gallery3d/.app.Gallery}
Intent { flg=0x20000000 cmp=com.android.gallery3d/.app.Gallery bnds=[0,205][480,301] }
ProcessRecord{4175dd28 5808:com.android.gallery3d/10036}
Hist #2: ActivityRecord{417ccc28 com.yeahman.shareapp/.ShareActivity}
Intent { act=android.intent.action.SEND_MULTIPLE typ=image/* cmp=com.yeahman.shareapp/.ShareActivity (has extras) }
ProcessRecord{41c868d0 6088:com.yeahman.shareapp/10116}
Hist #1: ActivityRecord{4135e540 com.android.gallery3d/.app.Gallery}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.gallery3d/.app.Gallery bnds=[364,50][108,108] }
4 ответа
Если у вас есть несколько экземпляров ShareActivity
Если вы активны в разных задачах, у вас нет возможности сообщить Android, какую задачу нужно активировать, запустив свою деятельность. Для меня это звучит так, как будто вы хотите в данном случае запустить не вашу деятельность, а приложение "Галерея". Если приложение Галерея уже запущено и ваша деятельность находится на вершине стека задач, то все, что вам нужно сделать, это вывести приложение Галерея на передний план. Для этого создайте "намерение запуска" для приложения "Галерея" и обязательно установите Intent.FLAG_ACTIVITY_NEW_TASK
по намерению. Вы должны быть в состоянии получить "намерение запуска" от PackageManager
используя getLaunchIntentForPackage()
РЕДАКТИРОВАТЬ: Пример кода с использованием ActivityManager
Вы можете попробовать это:
// Get the root activity of the task that your activity is running in
ActivityManager am = (ActivityManager)getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
ActivityManager.RunningTaskInfo task = tasks.get(0); // Should be my task
ComponentName rootActivity = task.baseActivity;
// Now build an Intent that will bring this task to the front
Intent intent = new Intent();
intent.setComponent(rootActivity);
// Set the action and category so it appears that the app is being launched
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
ПРИМЕЧАНИЕ: вам понадобится GET_TASKS
разрешение на это. Я не пробовал это и не могу гарантировать, что это будет работать. Использование getRunningTasks()
не одобряется документацией, но это не значит, что она не будет соответствовать вашим целям.
ИЗМЕНИТЬ добавленное действие / категорию к намерению
ПРИМЕЧАНИЕ: я на самом деле создал небольшое приложение, чтобы проверить это. Мне нужно было добавить ACTION=MAIN и CATEGORY=LAUNCHER в Intent (что было бы, если бы вы использовали PackageManager.getLaunchIntentForPackage()
, У меня есть HTC One S, поэтому на моем устройстве приложение "Галерея" фактически называется com.htc.album/.AlbumMain.ActivityMainDropList
, но это все равно должно работать для вас.
Notification.Builder mBuilder =
new Notification.Builder(this)
.setSmallIcon(R.drawable.cmplayer)
.setContentTitle("CoderoMusicPlayer")
.setContentText("PLayer0!");
Intent resultIntent = new Intent(this, AndroidBuildingMusicPlayerActivity.class);
resultIntent.setAction(Intent.ACTION_MAIN);
resultIntent.addCategory(Intent.CATEGORY_LAUNCHER);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
resultIntent, 0);
mBuilder.setContentIntent(pendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNotificationManager.notify(1, mBuilder.build());
Просто скопируйте код и вставьте его в свой основной актив запуска.
Задавать
android:launchMode="singleTop"
в вашем manifest.xml
для вашей основной деятельности и посмотреть, поможет ли это.
Это решение, которым я пользуюсь годами.
Ваша проблема в том, что ваш PendingIntent запускает свою цель из контента без приложений.
Ваш первый шаг - представить результат вашего намерения в контексте ваших приложений. Для этого сделайте свое уведомление, позвоните в "ForwardingReceiver".
Intent newIntent = new Intent(context, ForwardingReceiver.class);
...
mBuilder.setContentIntent(PendingIntent.getBroadcast(context, category, newIntent, PendingIntent.FLAG_UPDATE_CURRENT));
ForwardingReceiver
продолжается BroadcastReceiver
и в это onReceive()
метод у вас теперь у вас есть приложения текущий контекст и можете использовать sendOrderedBroadcast()
вот так:
Intent forwardIntent = new Intent();
forwardIntent.putExtras(intent.getExtras());
forwardIntent.setAction(GenericReceiver.class.getCanonicalName());
context.sendOrderedBroadcast(forwardIntent, null);
Теперь самое интересное. Вы должны расширить все свои действия в приложениях от общего родителя действий. Вы уже можете сделать это для регистрации или аналитики. В этом CommonActivityParent onResume()
вам нужно зарегистрироваться, чтобы получать трансляции с приоритетом выше 0 (например, 10)
mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
performActionUsingIntent(intent);
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(GenericReceiver.class.getCanonicalName());
filter.setPriority(10);
registerReceiver(mReceiver, filter);
(Не забудьте отменить это в onPause())
Это будет означать, что если ваше приложение находится на переднем плане, оно получит уведомление о щелчке (косвенно) и позволит вам выполнить действие.
Однако, если ваша активность находится в фоновом режиме, этот получатель не будет зарегистрирован. Нет проблем, ваш "GenericReceiver" должен выглядеть примерно так
@Override
public void onReceive(Context context, Intent intent) {
PackageManager pm = context.getPackageManager();
Intent newIntent = pm.getLaunchIntentForPackage(context.getPackageName());
newIntent.putExtras(intent.getExtras());
context.startActivity(newIntent);
}
Который начнет вашу деятельность по запуску. Эта операция запуска должна содержать код в onCreate(), чтобы определить, является ли это корнем задачи. Если это не так, он должен немедленно закрыться (и, следовательно, никогда не будет виден пользователю). Это эффективно выводит последнюю открытую задачу на передний план:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!isTaskRoot()
&& getIntent().hasCategory(Intent.CATEGORY_LAUNCHER)
&& getIntent().getAction() != null
&& getIntent().getAction().equals(Intent.ACTION_MAIN)) {
// Use this space to add the intent to a static singleton. This will be used in CommonActivityParent to perform an action.
CommonActivityParent.sIntent = getIntent();
finish();
return;
}
}
Чтобы закончить, убедитесь, что сразу после вашего registerReceiver()
вызов выше в CommonActivityParent, вы выполняете следующую проверку:
if(sIntent != null) {
Intent tempIntent = sIntent;
sIntent = null;
performActionUsingIntent(tempIntent);
}
Привет предыстория - Ваше приложение теперь будет действовать так, как если бы клик по уведомлению был фактически кликом из вашего приложения. И все это заняло чертовски много работы!
Надеюсь, у кого-то есть менее запутанный способ сделать это.
Для получения дополнительной информации не забудьте добавить флаг ожидающего намерения, чтобы onNewIntent работал!
правда:
PendingIntent.getActivity(context, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT)
ложный:
PendingIntent.getActivity(context, 0, resultIntent, 0)
Пожалуйста, проголосуйте, если эта выгода для вас, ура!