Como enviar parâmetros de um clique de notificação para uma atividade?

206

Posso encontrar uma maneira de enviar parâmetros para minha atividade a partir da minha notificação.

Eu tenho um serviço que cria uma notificação. Quando o usuário clica na notificação, quero abrir minha atividade principal com alguns parâmetros especiais. Por exemplo, um ID de item, para que minha atividade possa carregar e apresentar uma exibição de detalhes de itens especiais. Mais especificamente, estou baixando um arquivo e, quando o arquivo é baixado, quero que a notificação tenha a intenção de que, quando clicada, abra minha atividade em um modo especial. Eu tentei usar putExtraminha intenção, mas não consigo extrair, então acho que estou fazendo errado.

Código do meu serviço que cria a notificação:

        // 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);

Código da minha atividade que tenta buscar o parâmetro extra da notificação:

 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") );
    }

Os extras são sempre nulos e eu nunca coloco nada no meu log.

Btw ... onCreatesó é executado quando minha atividade é iniciada, se minha atividade já foi iniciada, também quero coletar os extras e apresentar minha atividade de acordo com o item_id que recebo.

Alguma ideia?

Vidar Vestnes
fonte

Respostas:

241

Dê uma olhada neste guia ( criando uma notificação ) e em exemplos do ApiDemos "StatusBarNotifications" e "NotificationDisplay".

Para gerenciar se a atividade já está em execução, você tem duas maneiras:

  1. Adicione o sinalizador FLAG_ACTIVITY_SINGLE_TOP ao Intent ao iniciar a atividade e, em seguida, na classe de atividade, implemente o manipulador de eventos onNewIntent (Intent intent) , para que você possa acessar o novo intent que foi chamado para a atividade (que não é o mesmo que chamar getIntent (), isso sempre retornará o primeiro Intent que lançou sua atividade.

  2. Igual ao número um, mas em vez de adicionar um sinalizador ao Intent, você deve adicionar "singleTop" em sua atividade AndroidManifest.xml.

Se você usar extras de intenção, lembre-se de ligar PendingIntent.getActivity()com a bandeira PendingIntent.FLAG_UPDATE_CURRENT, caso contrário, os mesmos extras serão reutilizados para cada notificação.

Lucas S.
fonte
95
e para responder à pergunta do usuário sobre extras serem nulos: você precisa ligar PendingIntent.getActivity()com o sinalizador PendingIntent.FLAG_UPDATE_CURRENT, caso contrário, os mesmos extras serão reutilizados para todas as notificações.
Matthias
2
u salvou meu dia, mas por que é a transferência de dados simples como isto tão complicado no android
Argumento Ilegal
8
Se você tiver notificações diferentes, use IDs de solicitação diferentes ao ligar PendingIntent.getActivity(), além de definir FLAG_ACTIVITY_SINGLE_TOPno Intente FLAG_UPDATE_CURRENTno PendingIntent. Veja stackoverflow.com/questions/7370324/…
schnatterer
101

Eu tive o problema semelhante: meu aplicativo exibe notificações de mensagens. Quando há várias notificações e, ao clicar em cada notificação, ele exibe os detalhes da notificação em uma atividade de exibição de mensagem. Eu resolvi o problema dos mesmos parâmetros extras que estão sendo recebidos na intenção da mensagem de exibição.

Aqui está o código que corrigiu isso. Código para criar a notificação Intenção.

 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);

Código para visualizar a Atividade da Mensagem.

@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
fonte
29

Talvez um pouco tarde, mas: em vez disso:

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);
}

Usa isto:

Bundle extras = getIntent().getExtras();
if(extras !=null) {
    String value = extras.getString("keyName");
}
pinaise
fonte
20
Talvez seja tarde para o OP, mas nunca é tarde para os outros na Internet :)
espinchi
19

Encontre o mesmo problema aqui. Eu resolvo isso usando um código de solicitação diferente, use o mesmo ID da notificação, ao criar PendingIntent. mas ainda não sei por que isso deve ser feito.

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

Depois de ler algumas listas de e-mail e outros fóruns, descobri que o truque parece adicionar alguns dados exclusivos à intenção.

como isso:

   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()))); 

Eu não entendo por que isso precisa ser feito, ele tem algo a ver com a intenção e não pode ser identificado apenas por seus extras ...

Vidar Vestnes
fonte
8
O Anroid reutiliza intenções, a ação de intenção e o código de solicitação o tornam único, mas não os dados extras. Portanto, você precisa definir um ID de solicitação exclusivo ou usar ações de intenção diferentes.
Bachi
10

Eu tentei de tudo, mas nada funcionou.

eventualmente veio com a seguinte solução.

1- no manifesto adicionar para a atividade android: launchMode = "singleTop"

2- Ao fazer a intenção pendente, faça o seguinte, use bundle em vez de usar diretamente intent.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
fonte
3
Funciona para mim. É necessário usar o valor requestCode diferente e o sinalizador PendingIntent.FLAG_UPDATE_CURRENT.
Phuongle
4

AndroidManifest.xml

Inclua launchMode = "singleTop"

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

SMSReceiver.java

Defina os sinalizadores para Intent e 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 () - é chamado sempre, carrega os extras.

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

Espero que ajude, foi baseado em outras respostas aqui no stackoverflow, mas este é o mais atualizado que funcionou para mim.

Miguel Jesus
fonte
3

É fácil, esta é a minha solução usando objetos!

My POJO

public class Person implements Serializable{

    private String name;
    private int age;

    //get & set

}

Notificação de método

  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);

Nova atividade

 private Person person;

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

Boa sorte!!

David Hackro
fonte
3

Depois de fazer algumas pesquisas, obtive uma solução no guia do desenvolvedor do 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);

Para obter um valor extra de Intenção na classe Atividade de Teste, você precisa escrever o seguinte código:

 Intent intent = getIntent();
 String extra = intent.getStringExtra("extra") ;
mohit
fonte
3
Para que serve stackBuilder?
precisa saber é o seguinte
1

Na sua implementação de notificação, use um código como este:

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);
...

Para obter valores extras de intenção no ExampleActivity, use o seguinte código:

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

NOTA MUITO IMPORTANTE: o método Intent :: putExtra () é um método Sobrecarregado. Para obter a chave extra, você precisa usar o método Intent :: get [Type] Extra () .

Nota: NOTIFICATION_ID e NOTIFICATION_CHANNEL_ID são constantes declaradas em ExampleActivity

Carlos Espinoza
fonte
1

Bom dia, eu também posso dizer que tentei tudo o que é mencionado nessas postagens e mais algumas de outros lugares. O problema número 1 para mim foi que o novo Intent sempre teve um pacote nulo. Meu problema foi focar demais nos detalhes de "eu incluí. Ou isso". Minha solução foi dar um passo atrás nos detalhes e examinar a estrutura geral da notificação. Quando fiz isso, consegui colocar as partes principais do código na sequência correta. Portanto, se você estiver tendo problemas semelhantes, verifique:

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

2a. Bundle bundle = new Bundle();

// Gosto de especificar o tipo de dados muito melhor. por exemplo, 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());

Com esta sequência , recebo um pacote válido.

Peter Suter
fonte
0

Se você usar

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

no arquivo AndroidManifest.xml para o lançamento da atividade, você deve usar o seguinte em sua intenção:

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);

Importante é definir dados exclusivos, por exemplo, usando um ID exclusivo como:

notificationClick.setData(Uri.parse(notificationClick.toUri(Intent.URI_INTENT_SCHEME) + myItem.getId()));
Scrounger
fonte
0

para uso de serviços PendingIntent.FLAG_UPDATE_CURRENT

para mim trabalho.

Ali Bagheri
fonte
0

Use como PendingIntent ao mostrar a notificação, pois ela será resolvida.

PendingIntent intent = PendingIntent.getActivity (este, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

Adicione PendingIntent.FLAG_UPDATE_CURRENT como último campo.

M.Noman
fonte