Comment envoyer des paramètres d'un clic de notification à une activité?

206

Je peux trouver un moyen d'envoyer des paramètres à mon activité à partir de ma notification.

J'ai un service qui crée une notification. Lorsque l'utilisateur clique sur la notification, je souhaite ouvrir mon activité principale avec certains paramètres spéciaux. Par exemple, un identifiant d'article, afin que mon activité puisse se charger et présenter une vue de détail d'élément spéciale. Plus précisément, je télécharge un fichier, et lorsque le fichier est téléchargé, je veux que la notification ait l'intention que lorsque vous cliquez dessus, elle ouvre mon activité dans un mode spécial. J'ai essayé d'utiliser putExtrasur mon intention, mais ne peux pas sembler l'extraire, donc je pense que je le fais mal.

Code de mon service qui crée la notification:

        // construct the Notification object.
     final Notification notif = new Notification(R.drawable.icon, tickerText, System.currentTimeMillis());


    final RemoteViews contentView = new RemoteViews(context.getPackageName(), R.layout.custom_notification_layout);
    contentView.setImageViewResource(R.id.image, R.drawable.icon);
    contentView.setTextViewText(R.id.text, tickerText);
    contentView.setProgressBar(R.id.progress,100,0, false);
    notif.contentView = contentView;        

    Intent notificationIntent = new Intent(context, Main.class);
    notificationIntent.putExtra("item_id", "1001"); // <-- HERE I PUT THE EXTRA VALUE
    PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
    notif.contentIntent = contentIntent;

    nm.notify(id, notif);

Code de mon activité qui tente d'extraire le paramètre supplémentaire de la notification:

 public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);


    Bundle extras = getIntent().getExtras();
    if(extras != null){
        Log.i( "dd","Extra:" + extras.getString("item_id") );
    }

Les extras sont toujours nuls et je ne reçois jamais rien dans mon journal.

Btw ... le onCreaten'est exécuté que lorsque mon activité démarre, si mon activité est déjà démarrée, je veux également collecter les extras et présenter mon activité en fonction de l'item_id que je reçois.

Des idées?

Vidar Vestnes
la source

Réponses:

241

Jetez un œil à ce guide ( création d'une notification ) et aux exemples ApiDemos "StatusBarNotifications" et "NotificationDisplay".

Pour gérer si l'activité est déjà en cours, vous disposez de deux méthodes:

  1. Ajoutez l' indicateur FLAG_ACTIVITY_SINGLE_TOP à l'intention lors du lancement de l'activité, puis dans le gestionnaire d'événements de la classe d'activité implémentez onNewIntent (intention d'intention) , de cette façon, vous pouvez accéder à la nouvelle intention qui a été appelée pour l'activité (ce qui n'est pas la même chose que d'appeler getIntent (), cela renverra toujours la première intention qui a lancé votre activité.

  2. Identique au numéro un, mais au lieu d'ajouter un indicateur à l'intention, vous devez ajouter "singleTop" dans votre activité AndroidManifest.xml.

Si vous utilisez des extras intentionnels, n'oubliez pas d'appeler PendingIntent.getActivity()avec l'indicateur PendingIntent.FLAG_UPDATE_CURRENT, sinon les mêmes extras seront réutilisés pour chaque notification.

Lucas S.
la source
95
et pour répondre à la question de l'utilisateur sur les extras étant nuls: vous devez appeler PendingIntent.getActivity()avec le drapeau PendingIntent.FLAG_UPDATE_CURRENT, sinon les mêmes extras seront réutilisés pour chaque notification.
Matthias
2
vous avez sauvé ma journée, mais pourquoi le transfert de données simples comme celle-ci est-il si compliqué dans Android
Illegal Argument
8
Si vous devez avoir des notifications différentes, assurez-vous d'utiliser des ID de demande différents lors de l'appel PendingIntent.getActivity()en plus de définir FLAG_ACTIVITY_SINGLE_TOPsur Intentet FLAG_UPDATE_CURRENTsur PendingIntent. Voir stackoverflow.com/questions/7370324/…
schnatterer
101

J'ai rencontré le même problème que mon application affiche des notifications de message. Lorsqu'il y a plusieurs notifications et en cliquant sur chaque notification, il affiche ce détail de notification dans une activité de message de vue. J'ai résolu le problème des mêmes paramètres supplémentaires reçus en vue d'intention de message.

Voici le code qui a corrigé cela. Code de création de l'intention de notification.

 Intent notificationIntent = new Intent(getApplicationContext(), viewmessage.class);
    notificationIntent.putExtra("NotificationMessage", notificationMessage);
    notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pendingNotificationIntent = PendingIntent.getActivity(getApplicationContext(),notificationIndex,notificationIntent,PendingIntent.FLAG_UPDATE_CURRENT);
    notification.flags |= Notification.FLAG_AUTO_CANCEL;
    notification.setLatestEventInfo(getApplicationContext(), notificationTitle, notificationMessage, pendingNotificationIntent);

Code pour afficher l'activité des messages.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    onNewIntent(getIntent());
}

@Override
public void onNewIntent(Intent intent){
    Bundle extras = intent.getExtras();
    if(extras != null){
        if(extras.containsKey("NotificationMessage"))
        {
            setContentView(R.layout.viewmain);
            // extract the extra-data in the Notification
            String msg = extras.getString("NotificationMessage");
            txtView = (TextView) findViewById(R.id.txtMessage);
            txtView.setText(msg);
        }
    }


}
Muhammad Yousaf Sulahria
la source
29

Peut-être un peu tard, mais: au lieu de ça:

public void onNewIntent(Intent intent){
    Bundle extras = intent.getExtras();
    Log.i( "dbg","onNewIntent");

    if(extras != null){
        Log.i( "dbg", "Extra6 bool: "+ extras.containsKey("net.dbg.android.fjol"));
        Log.i( "dbg", "Extra6 val : "+ extras.getString("net.dbg.android.fjol"));

    }
    mTabsController.setActiveTab(TabsController.TAB_DOWNLOADS);
}

Utilisez ceci:

Bundle extras = getIntent().getExtras();
if(extras !=null) {
    String value = extras.getString("keyName");
}
pinaise
la source
20
Peut-être en retard pour l'OP, mais il n'est jamais en retard pour les autres sur Internet :)
espinchi
19

Rencontrez le même problème ici. Je le résout en utilisant un code de demande différent, utilise le même identifiant que la notification, lors de la création de PendingIntent. mais je ne sais toujours pas pourquoi cela devrait être fait.

PendingIntent contentIntent = PendingIntent.getActivity(context, **id**, notificationIntent, 0);
notif.contentIntent = contentIntent;
nm.notify(**id**, notif);
jamchen
la source
14

Après avoir lu des listes de diffusion et d'autres forums, j'ai trouvé que l'astuce semble ajouter des données uniques à l'intention.

comme ça:

   Intent notificationIntent = new Intent(Main.this, Main.class);
   notificationIntent.putExtra("sport_id", "sport"+id);
   notificationIntent.putExtra("game_url", "gameURL"+id);

   notificationIntent.setData((Uri.parse("foobar://"+SystemClock.elapsedRealtime()))); 

Je ne comprends pas pourquoi cela doit être fait, cela a quelque chose à voir avec l'intention ne peut être identifié que par ses extras ...

Vidar Vestnes
la source
8
Anroid réutilise les intentions, l'action d'intention et le code de demande le rendent unique, mais pas les données supplémentaires. Vous devez donc définir un identifiant de demande unique ou utiliser différentes actions d'intention.
Bachi
10

J'ai tout essayé mais rien n'a fonctionné.

a finalement trouvé la solution suivante.

1- dans le manifeste ajouter pour l'activité android: launchMode = "singleTop"

2- tout en faisant l'intention en attente, procédez comme suit, utilisez bundle au lieu d'utiliser directement intention.putString () ou intent.putInt ()

                    Intent notificationIntent = new Intent(getApplicationContext(), CourseActivity.class);

                    Bundle bundle = new Bundle();
                    bundle.putString(Constants.EXAM_ID,String.valueOf(lectureDownloadStatus.getExamId()));
                    bundle.putInt(Constants.COURSE_ID,(int)lectureDownloadStatus.getCourseId());
                    bundle.putString(Constants.IMAGE_URL,lectureDownloadStatus.getImageUrl());

                    notificationIntent.putExtras(bundle);

                    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
                            Intent.FLAG_ACTIVITY_SINGLE_TOP);
                    PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(),
                            new Random().nextInt(), notificationIntent,
                            PendingIntent.FLAG_UPDATE_CURRENT); 
Dheeraj Sachan
la source
3
Ça marche pour moi. Doit utiliser une valeur requestCode et un indicateur PendingIntent.FLAG_UPDATE_CURRENT différents.
phuongle
4

AndroidManifest.xml

Inclure launchMode = "singleTop"

<activity android:name=".MessagesDetailsActivity"
        android:launchMode="singleTop"
        android:excludeFromRecents="true"
        />

SMSReceiver.java

Définissez les indicateurs pour l'intention et le PendingIntent

Intent intent = new Intent(context, MessagesDetailsActivity.class);
    intent.putExtra("smsMsg", smsObject.getMsg());
    intent.putExtra("smsAddress", smsObject.getAddress());
    intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);

    PendingIntent contentIntent = PendingIntent.getActivity(context, notification_id, intent, PendingIntent.FLAG_UPDATE_CURRENT);

MessageDetailsActivity.java

onResume () - est appelé à chaque fois, chargez les extras.

Intent intent = getIntent();
    String extraAddress = intent.getStringExtra("smsAddress");
    String extraBody = intent.getStringExtra("smsMsg");

J'espère que cela aide, il était basé sur d'autres réponses ici sur stackoverflow, mais c'est la plus mise à jour qui a fonctionné pour moi.

Miguel Jesus
la source
3

C'est facile, c'est ma solution en utilisant des objets!

Mon POJO

public class Person implements Serializable{

    private String name;
    private int age;

    //get & set

}

Notification de méthode

  Person person = new Person();
  person.setName("david hackro");
  person.setAge(10);

    Intent notificationIntent = new Intent(this, Person.class);
    notificationIntent.putExtra("person",person);
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.notification_icon)
                .setAutoCancel(true)
                .setColor(getResources().getColor(R.color.ColorTipografiaAdeudos))
                .setPriority(2)
                .setLargeIcon(bm)
                .setTicker(fotomulta.getTitle())
                .setContentText(fotomulta.getMessage())
                .setContentIntent(PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT))
                .setWhen(System.currentTimeMillis())
                .setContentTitle(fotomulta.getTicketText())
                .setDefaults(Notification.DEFAULT_ALL);

Nouvelle activité

 private Person person;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_notification_push);
    person = (Person) getIntent().getSerializableExtra("person");
}

Bonne chance!!

David Hackro
la source
3

Après avoir fait quelques recherches, j'ai obtenu la solution du guide du développeur Android

PendingIntent contentIntent ;
Intent intent = new Intent(this,TestActivity.class);
intent.putExtra("extra","Test");
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);

stackBuilder.addParentStack(ArticleDetailedActivity.class);

contentIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);

Pour obtenir une valeur supplémentaire d'intention dans la classe d'activité de test, vous devez écrire le code suivant:

 Intent intent = getIntent();
 String extra = intent.getStringExtra("extra") ;
mohit
la source
3
À quoi ça sert stackBuilder?
AlexioVay
1

Dans votre implémentation de notification, utilisez un code comme celui-ci:

NotificationCompat.Builder nBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
...
Intent intent = new Intent(this, ExampleActivity.class);
intent.putExtra("EXTRA_KEY", "value");

PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
nBuilder.setContentIntent(pendingIntent);
...

Pour obtenir des valeurs supplémentaires d'intention dans ExampleActivity, utilisez le code suivant:

...
Intent intent = getIntent();
if(intent!=null) {
    String extraKey = intent.getStringExtra("EXTRA_KEY");
}
...

NOTE TRÈS IMPORTANTE: la méthode Intent :: putExtra () est une méthode surchargée. Pour obtenir la clé supplémentaire, vous devez utiliser la méthode Intent :: get [Type] Extra () .

Remarque: NOTIFICATION_ID et NOTIFICATION_CHANNEL_ID sont des constantes déclarées dans ExampleActivity

Carlos Espinoza
la source
1

Bonjour, je peux aussi dire que j'ai essayé tout ce qui est mentionné dans ces articles et quelques autres d'ailleurs. Le problème n ° 1 pour moi était que la nouvelle intention avait toujours un paquet nul. Mon problème était de trop me concentrer sur les détails de "ai-je inclus .ce ou .that". Ma solution était de prendre du recul par rapport aux détails et d'examiner la structure globale de la notification. Quand j'ai fait cela, j'ai réussi à placer les éléments clés du code dans la séquence correcte. Donc, si vous rencontrez des problèmes similaires, vérifiez:

1. Intent notificationIntent = new Intent(MainActivity.this, NotificationActivity.class);

2a. Bundle bundle = new Bundle();

// J'aime mieux spécifier le type de données. par exemple bundle.putInt

2b. notificationIntent.putExtras(bundle);
3. PendingIntent contentIntent = PendingIntent.getActivity(MainActivity.this, WIZARD_NOTIFICATION_ID, notificationIntent,
                    PendingIntent.FLAG_UPDATE_CURRENT);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
4. NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
5.          NotificationCompat.Builder nBuilder =
                    new NotificationCompat.Builder(this)
                            .setSmallIcon(R.drawable.ic_notify)
                            .setContentTitle(title)
                            .setContentText(content)
                            .setContentIntent(contentIntent)
                            .setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE)
                            .setAutoCancel(false)//false is standard. true == automatically removes the notification when the user taps it.
                            .setColor(getResources().getColor(R.color.colorPrimary))
                            .setCategory(Notification.CATEGORY_REMINDER)
                            .setPriority(Notification.PRIORITY_HIGH)
                            .setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
            notificationManager.notify(WIZARD_NOTIFICATION_ID, nBuilder.build());

Avec cette séquence, j'obtiens un bundle valide.

Peter Suter
la source
0

Si tu utilises

android:taskAffinity="myApp.widget.notify.activity"
android:excludeFromRecents="true"

dans votre fichier AndroidManifest.xml pour l'activité à lancer, vous devez utiliser ce qui suit dans votre intention:

Intent notificationClick = new Intent(context, NotifyActivity.class);
    Bundle bdl = new Bundle();
    bdl.putSerializable(NotifyActivity.Bundle_myItem, myItem);
    notificationClick.putExtras(bdl);
    notificationClick.setData(Uri.parse(notificationClick.toUri(Intent.URI_INTENT_SCHEME) + myItem.getId()));
    notificationClick.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);  // schließt tasks der app und startet einen seperaten neuen

    TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
    stackBuilder.addParentStack(NotifyActivity.class);
    stackBuilder.addNextIntent(notificationClick);

    PendingIntent notificationPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
    mBuilder.setContentIntent(notificationPendingIntent);

L'important est de définir des données uniques, par exemple en utilisant un identifiant unique comme:

notificationClick.setData(Uri.parse(notificationClick.toUri(Intent.URI_INTENT_SCHEME) + myItem.getId()));
Profiteur
la source
0

Veuillez utiliser comme PendingIntent tout en affichant la notification, elle sera résolue.

PendingIntent intention = PendingIntent.getActivity (this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

Ajoutez PendingIntent.FLAG_UPDATE_CURRENT comme dernier champ.

M.Noman
la source