нажмите на уведомление, чтобы перейти к текущей деятельности

я использую это решение:Как возобновить намерение уведомления, а не новое?

Я работаю нормально, когда я запускаю свое приложение в обычном режиме ... однако мое приложение имеет функцию общего доступа.

Когда я выбираю изображения, которыми хочу поделиться, из приложения галереи и открываю его в своей деятельности, я создаю уведомление в этой деятельности. Я хочу, чтобы, когда пользователь нажимает на уведомление, он открывает существующее действие (открытое приложением галереи)

Проблема в том, что когда я нажимаю на уведомление, оно не возобновляет эту активность, а вместо этого открывает новый экземпляр действия или другой экземпляр, уже открытый ранее.

Изменить: больше объяснений

Мое приложение называется 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 shell dumpsys активность (после применения кода Дэвидомhttps://stackoverflow.com/a/16901603/1334268)

Мое приложение называется 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] }
 David Wasser02 июн. 2013 г., 22:20
опубликовать код, где вы создаете,IntentPendingIntent иNotification
 yeahman04 июн. 2013 г., 21:26
после прочтения поста и учебных пособий / документации после учебных пособий / документации ... я пришел к выводу, что, к сожалению, это невозможно :(
 yeahman03 июн. 2013 г., 18:17
я только что отредактировал мой вопрос с моим кодом
 yeahman04 июн. 2013 г., 20:19
есть ли решение? я приму этоне возможно в качестве ответа с резервным объяснением

Ответы на вопрос(4)

Решение Вопроса

Если у вас есть несколько экземпляровShareActivity Если вы активны в разных задачах, у вас нет возможности сообщить Android, какую задачу нужно активировать, запустив свою деятельность. Для меня это звучит так, как будто вы хотите, в данном случае, запустить не вашу деятельность, а приложение Gallery. Если приложение Галерея уже запущено и ваша деятельность находится на вершине стека задач, то все, что вам нужно сделать, это вывести приложение Галерея на передний план. Для этого создайтеЗапустить Намерение для приложения Галерея и не забудьте установить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 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, но это все равно должно работать для вас.

 yeahman13 июн. 2013 г., 19:14
хорошо и спасибо за вашу помощь! :)
 David Wasser08 июн. 2013 г., 12:45
Я неНе думаю, что это связано с этой ошибкой, но может быть связано с другой ошибкой. Как вы запустили приложение галереи? Можете ли вы опубликовать (до и после использования уведомления) выводadb shell dumpsys activity где-нибудь, где мы можем посмотреть на это?
 David Wasser10 июн. 2013 г., 18:19
Да, прости. Я неправильно прочитал дамп стека активности. Я'я все еще думаю об этом ...
 yeahman10 июн. 2013 г., 18:14
я использую твой примерПример кода с использованием ActivityManager " not getLaunchIntentForPackage ()
 yeahman09 июн. 2013 г., 09:16
хорошо ты был прав; я перезагрузился и обновил свой dumpsys в своем основном посте.
 yeahman04 июн. 2013 г., 21:02
да я знаю этоМожно сделать это через Singletask THX, но я бы предпочел иметь новый экземпляр каждый раз. с singletask раздражение, которое я получаю, когда я открываю общий доступ через приложение галереи и захожу в мое приложение, оно открывает общий доступ, открытый через галерею ... это не очень интуитивно
 David Wasser12 июн. 2013 г., 18:39
Да, в соответствии с документацией и исходя из собственного опыта использованияFLAG_ACTIVITY_NEW_TASK должен сделать именно это. По какой-то причине это не так. Я нене знаю почему. Мне нужно еще копать. Но, по крайней мере, теперь у вас есть рабочее решение, которое являетсяхорошая вещь", Рад, что мы могли помочь
 yeahman08 июн. 2013 г., 18:34
Я думаю о том, чтобы изменить свою деятельность, используя службы и привязку, поскольку решение кажется, что оно будет вполне "хак» но мне все еще любопытно узнать, как это сделать .. я многому научился, и у меня есть гораздо лучшее понимание задач и стеков в Android, чтобы попытаться найти решение этой проблемы и с вашей помощью. Спасибо
 David Wasser04 июн. 2013 г., 22:26
Ты можешь использоватьadb shell dumpsys activity взглянуть на задачи в системе и действия в них. Это даст вам хорошее представление о том, что происходит. Посмотрите, прежде чем нажать на уведомление, а затем еще раз после того, как вы нажмете на уведомление. Может быть, это даст некоторое представление о том, что происходит.
 David Wasser08 июн. 2013 г., 22:06
Попробуйте перезагрузить телефон и повторите попытку. У стека активности уже есть несколько экземпляров как активности Галереи, так и вашей ShareActivity, даже до того, как вы нажмете на уведомление! Дайте мне знать, если естьлюбое другое поведение
 yeahman04 июн. 2013 г., 21:49
Я попробовал ваш код, спасибо, но когда я нажимаю на уведомление, он открывает галерею (я нене знать, создал ли он новый экземпляр или возобновить предыдущий) вместо того, чтобы показывать активность, открытую в приложении галереи. :(
 yeahman08 июн. 2013 г., 18:31
хорошо опубликовано в моем edit3 в моем вопросе
 David Wasser04 июн. 2013 г., 20:35
Вам нужно иметьShareActivity существуют в галерее задачи? Если нет, вы могли бы объявитьShareActvity какlaunchMode="singleTask", Это создастShareActivity в новом задании, и вы бы неу вас не должно быть проблем, когда ваша деятельность присутствует в нескольких задачах. Вы можете попробовать это и посмотреть, решит ли это вашу проблему.
 David Wasser04 июн. 2013 г., 21:28
Так как вы указали, что вы неЯ не знаю, какое приложение могло начать твою деятельность, ямы добавили пример, используяActivityManager определить корневую активность текущей задачи. Я'Я не пробовал это, но это может сработать для вас. Дайте мне знать, как это происходит.
 yeahman12 июн. 2013 г., 18:25
оно работает!!! спасибо очень человек! Но я все еще неt понять, почему с Intent.FLAG_ACTIVITY_NEW_TASK это не работает? согласно документацииПредполагается ли выводить текущее состояние стека задачи, в которой обнаружена активность?
 David Wasser12 июн. 2013 г., 13:41
Я создал небольшую тестовую программу. Я запускал его на HTC One SV. Я смог воспроизвести вашу проблему. Мне нужно было добавить ACTION = MAIN и CATEGORY = LAUNCHER вIntent для уведомления. Теперь он делает то, что вы хотите (например, нажав на уведомление, вы вернетесь к задаче Галерея с вашимShareActivity наверху).
 yeahman03 июн. 2013 г., 20:54
у вас есть пример использования PackageManager? Что делать, если я использую другое приложение галереи или приложение файлового менеджера вместо приложения галереи по умолчанию?
 yeahman08 июн. 2013 г., 10:03
хорошо, я попробовал ADB Shell Dumpsys деятельности. Когда я нажимаю на уведомление, он создает новый экземпляр галереи поверх основного стека приложения галереи .... "Intent.FLAG_ACTIVITY_NEW_TASK» флаг неПредполагается вывести существующий основной стек на передний план вместо создания нового экземпляра?
 yeahman08 июн. 2013 г., 10:13
это связано с ошибкой, описанной там:stackoverflow.com/questions/9772927/...?
 David Wasser10 июн. 2013 г., 10:15
У тебя нетя попробовал код, который вы указали, вы используетеgetLaunchIntentForPackage(), Не могли бы вы попробовать другой код, который я предоставил? Это до сих пор для меня загадка ...
    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());

Просто скопируйте код и вставьте его в свой основной актив запуска.

 Zeus11 окт. 2014 г., 18:00
Ты спас мой день. благодарю вас
 sud00705 июн. 2016 г., 12:16
Прекрасный Диднне думаю, что это сработало бы !! Это'эти две строкиaction and category
 Hasan Masud29 февр. 2016 г., 05:31
Это очень просто. Вы можете отобразить значок и описание вашего приложения на панели задач. если кто-нибудь щелкнет значок на панели задач, он вернется к текущему действию, выполняемому в фоновом режиме.
 Ravi28 окт. 2014 г., 08:25
идеальное рабочее решение специально для сервисных приложений, где у вас есть один вид деятельности
 Hasan Masud05 янв. 2015 г., 05:54
Добро пожаловать. Счастливое кодирование.
 Selva25 февр. 2016 г., 18:48
@HasanMasud, отлично и спасибо, это сработало .. не могли бы вы объяснить, что делает код?

Задавать

android:launchMode="singleTop"

в вашемmanifest.xml для вашей основной деятельности и посмотреть, поможет ли это.

 yeahman02 июн. 2013 г., 20:30
не работает не работает :(
 Ken Wolf02 июн. 2013 г., 20:38
Вы определенно устанавливаете флаги для pendingIntent?i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
 Hamzeh Soboh28 нояб. 2017 г., 15:15
Ага! это сработало. Конечно, кроме реализацииonNewIntent внутри вашей деятельности.
 yeahman02 июн. 2013 г., 20:41
Ага! я думаю, что проблема в том, что когда активность открывается из галереи, она переходит в стек галереи, а не в мое приложение (не уверена,правильно). Поэтому, когда я нажимаю на уведомление, он пытается открыть действие из моего приложения.стек, а не из галереи один ... не уверен, что то, что я говорю, в порядке .. я немного запутался со стеком / экземпляром Android прямо сейчас

Это решение, которое яПользуюсь годами.

Ваша проблема в том, что ваш 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);

Теперь самое интересное. Вам нужно расширить все действия в своих приложениях от общего родителя действий. Вы можете уже сделать это для регистрации или аналитики. В этом CommonActivityParentonResume() вам нужно зарегистрироваться, чтобы получать трансляции с приоритетом выше 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);
}

Который начнет вашу деятельность по запуску. Эта операция запуска должна содержать кодs 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);
}

Эй, Престо - ТыПриложение теперь будет действовать так, как если бы щелчок уведомления был фактически кликом из вашего приложения. И все это заняло чертовски много работы!

Надеюсь, у кого-то есть менее запутанный способ сделать это.

Ваш ответ на вопрос