PendingIntent berfungsi dengan benar untuk notifikasi pertama, tetapi tidak benar untuk notifikasi lainnya

88
  protected void displayNotification(String response) {
    Intent intent = new Intent(context, testActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);

    Notification notification = new Notification(R.drawable.icon, "Upload Started", System.currentTimeMillis());
    notification.setLatestEventInfo(context, "Upload", response, pendingIntent);

    nManager.notify((int)System.currentTimeMillis(), notification);
}

Fungsi ini akan dipanggil beberapa kali. Saya ingin masing-masing notificationmeluncurkan testActivity saat diklik. Sayangnya, hanya notifikasi pertama yang meluncurkan testActivity. Mengklik sisanya akan memperkecil jendela notifikasi.

Informasi tambahan: Fungsi displayNotification()dalam kelas yang disebut UploadManager. Contextditeruskan ke UploadManagerdari activityinstance itu. Fungsi displayNotification()dipanggil beberapa kali dari sebuah fungsi, juga di UploadManager, yang berjalan di file AsyncTask.

Sunting 1: Saya lupa menyebutkan bahwa saya meneruskan respons String ke Intent intentsebagai file extra.

  protected void displayNotification(String response) {
    Intent intent = new Intent(context, testActivity.class);
    intent.putExtra("response", response);
    PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

Ini membuat perbedaan besar karena saya memerlukan "respons" ekstra untuk mencerminkan respons String saat notifikasi dibuat. Sebaliknya, menggunakan PendingIntent.FLAG_UPDATE_CURRENT, "respons" ekstra mencerminkan ke mana respons String pada panggilan terakhir displayNotification().

Saya tahu mengapa ini berasal dari membaca dokumentasi di FLAG_UPDATE_CURRENT. Namun, saya tidak yakin bagaimana mengatasinya saat ini.

Kapil Rajput
sumber

Jawaban:

126

Jangan gunakan Intent.FLAG_ACTIVITY_NEW_TASKuntuk PendingIntent.getActivity, gunakan FLAG_ONE_SHOT sebagai gantinya


Disalin dari komentar:

Kemudian atur beberapa tindakan dummy pada Intent, jika tidak, ekstra akan dihapus. Sebagai contoh

intent.setAction(Long.toString(System.currentTimeMillis()))
ognian
sumber
Bendera ini sebenarnya juga tidak berfungsi karena alasan yang sama, menurut saya, bahwa ekstra saya tidak berfungsi dengan benar (periksa Edit 1 saya).
32
Kemudian setel beberapa tindakan dummy pada Intent, jika tidak, ekstra akan dihapus. Misalnya intent.setAction ("foo")
ognian
20
Luar biasa. Itu berhasil. Saya setAction (Long.toString (System.currentTimeMillis ())) sehubungan dengan menggunakan FLAG_UPDATE_CURRENT yang disarankan mbauer. Menggunakan FLAG_ONE_SHOT hanya memungkinkan saya mengeklik pemberitahuan sekali (yang masuk akal). Terima kasih banyak ognian.
5
"Kemudian atur beberapa tindakan dummy pada Intent, jika tidak, ekstra akan dibuang" - apakah ini didokumentasikan di suatu tempat?
Mr_and_Mrs_D
Mekanisme setAction berhasil untuk saya. Sejauh yang didokumentasikan, tidak yakin, tetapi sumber untuk Android tersedia di android.googlesource.com ;-)
Norman H
62

Sedang berjuang dengan RemoteViewsdan beberapa berbeda Intentsuntuk masing-masing Buttondi HomeScreenWidget. Berhasil saat ditambahkan ini:

1. intent.setAction(Long.toString(System.currentTimeMillis()));

2. PendingIntent.FLAG_UPDATE_CURRENT

        PackageManager pm = context.getPackageManager();

        Intent intent = new Intent(context, MyOwnActivity.class);
        intent.putExtra("foo_bar_extra_key", "foo_bar_extra_value");
        intent.setAction(Long.toString(System.currentTimeMillis()));
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
                intent, PendingIntent.FLAG_UPDATE_CURRENT);
        RemoteViews views = new RemoteViews(context.getPackageName(),
                R.layout.widget_layout);
        views.setOnClickPendingIntent(my_button_r_id_received_in_parameter, pendingIntent);
ViliusK
sumber
+1 Keren Terima kasih. Adakah ide mengapa menambahkan intent.setAction () membuatnya berhasil?
AjOnFire
setAction berfungsi tetapi bagaimana jika saya benar-benar harus menyetel Action maksud saya ke sesuatu yang lain? Mengapa frameworknya sangat bermasalah?
LyteSpeed
2
Saya suka bagaimana Android SDK begitu intuitif bagi pengembang ... (: ♥ ️ BTW baca @ObjectiveTruth jawaban di bawah untuk penjelasan tentang alasansetAction
Aviel Gross
1
Mendapatkan perilaku aneh, tanpa metode setAction memanggil ekstra maksud yang akan bekerja saat debugging, tapi ketika tidak men-debug ekstra maksud akan selalu sama dengan ekstra awal yang diteruskan pada panggilan pertama. Saya menemukan bahwa saat men-debug, onCreate selalu dipanggil saat menavigasi keluar dari aplikasi tetapi sementara tidak men-debug, onCreate tidak dipanggil, hanya onStart. Memanggil metode setAction menyelesaikan masalah, saya kira itu ada hubungannya dengan maksud yang tidak 'berbeda' jika hanya nilai ekstra yang berubah.
MaxJ
@clu Karena saya sudah menggunakan setAction, yang dapat Anda lakukan adalah addCategory. PendingIntentdigunakan Intent.filterEqualsuntuk memeriksa kesetaraan tindakan, data, jenis, kelas, dan kategori. developer.android.com/reference/android/content/…
iamreptar
44

Atur Tindakan Selesaikan ini untuk saya. Inilah pemahaman saya tentang situasinya:


Saya memiliki beberapa widget yang masing-masing memiliki PendingIntent. Setiap kali ada yang diperbarui, semuanya diperbarui. Bendera ada di sana untuk menjelaskan apa yang terjadi dengan PendingIntents yang persis sama.

FLAG_UPDATE_CURRENT deskripsi terbaca jauh lebih baik sekarang:

Jika PendingIntent yang sama yang Anda buat sudah ada, perbarui semua yang lama ke PendingIntent baru yang Anda buat.

Definisi yang persis sama melihat seluruh PendingIntent KECUALI ekstra. Jadi, meskipun Anda memiliki ekstra yang berbeda pada setiap maksud (bagi saya, saya menambahkan appWidgetId) lalu ke android, keduanya sama.

Menambahkan .setAction dengan beberapa string unik tiruan memberi tahu OS. Ini sama sekali berbeda dan tidak memperbarui apa pun. Pada akhirnya, inilah implementasi saya yang berfungsi seperti yang saya inginkan, di mana setiap Widget memiliki konfigurasi sendiri yang dilampirkan Intent:

Intent configureIntent = new Intent(context, ActivityPreferences.class);

configureIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);

configureIntent.setAction("dummy_unique_action_identifyer" + appWidgetId);

PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, configureIntent,
    PendingIntent.FLAG_UPDATE_CURRENT);

MEMPERBARUI


Solusi yang lebih baik jika Anda bekerja dengan siaran. Unique PendingIntents juga ditentukan oleh kode permintaan unik. Inilah solusi saya:

//Weee, magic number, just want it to be positive nextInt(int r) means between 0 and r
int dummyuniqueInt = new Random().nextInt(543254); 
PendingIntent pendingClearScreenIntent = PendingIntent.getBroadcast(context, 
    dummyuniqueInt, clearScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);
ObjectiveTruth
sumber
1
Solusi Bersih Yang Bagus
Varun Garg
1
Bagi saya memiliki id unik dan PendingIntent.FLAG_ONE_SHOT untuk maksud tertunda, bersama dengan setAction pada maksud bekerja.
Kaustuv
agak aneh bagaimana hal itu tidak mempertimbangkan perubahan ekstra untuk perubahan maksud, tetapi tampaknya benar: /
zeroDivider
20

Saya melihat jawaban tetapi tidak ada penjelasan. Juga tidak ada jawaban yang membahas semua solusi yang mungkin, jadi saya akan mencoba menjelaskannya.

Dokumentasi:

Jika Anda benar-benar membutuhkan beberapa objek PendingIntent berbeda yang aktif pada saat yang sama (seperti untuk digunakan sebagai dua notifikasi yang keduanya ditampilkan pada saat yang sama), maka Anda perlu memastikan ada sesuatu yang berbeda tentang mereka untuk mengaitkannya dengan yang berbeda. PendingIntents. Ini bisa berupa salah satu atribut Intent yang dipertimbangkan oleh Intent.filterEquals, atau integer kode permintaan berbeda yang disediakan untuk getActivity (Context, int, Intent, int), getActivities (Context, int, Intent [], int), getBroadcast (Context, int , Intent, int), atau getService (Context, int, Intent, int).

Penyebab masalah:

Anda membuat 2 notifikasi dengan 2 maksud tertunda. Setiap maksud yang tertunda dikaitkan dengan maksud:

Intent intent = new Intent(context, testActivity.class);

Namun, 2 maksud ini sama, oleh karena itu ketika pemberitahuan kedua Anda tiba, maksud pertama akan diluncurkan.

Larutan:

Anda harus membuat setiap maksud unik, sehingga tidak ada maksud tertunda yang akan sama. Bagaimana Anda membuat maksud menjadi unik? Bukan dengan ekstra yang Anda berikan putExtra(). Meskipun tambahannya berbeda, maksudnya mungkin masih sama. Untuk membuat setiap maksud unik, Anda harus menyetel nilai unik ke tindakan maksud, atau data, atau jenis, atau kelas, atau kategori, atau kode permintaan: (semua itu akan berfungsi)

  • tindakan: intent.setAction(...)
  • data: intent.setData(...)
  • Tipe: intent.setType(...)
  • kelas: intent.setClass(...)
  • kategori: intent.addCategory(...)
  • Kode permintaan: PendingIntent.getActivity(context, YOUR_UNIQUE_CODE, intent, Intent.FLAG_ONE_SHOT);

Catatan : Menetapkan kode permintaan unik mungkin rumit karena Anda memerlukan int, sementara System.currentTimeMillis()pengembaliannya panjang, yang berarti beberapa digit akan dihapus. Oleh karena itu saya akan merekomendasikan untuk memilih kategori atau tindakan dan menetapkan string unik.

steliosf.dll
sumber
Inilah yang akhirnya berhasil bagi saya, menggunakan ID unik untuk setiap pemberitahuan (tetap diperlukan untuk pembatalan) dan kategori khusus per tindakan (tidak akan pernah memiliki beberapa tindakan dengan jenis yang sama pada pemberitahuan yang sama).
MandisaW
Ya, saya juga menggunakan kategori unik untuk setiap maksud, itu berfungsi dengan baik.
steliosf
Punya masalah yang sama. dua pemberitahuan dipicu pada saat bersamaan. ketika saya mengklik pemberitahuan kedua tidak ada yang terjadi. setelah set ini setAction (Long.toString (System.currentTimeMillis ())); . itu bekerja seperti pesona. terima kasih atas penjelasan yang bagus @MScott
Anantha Babu
13

Saya memiliki masalah yang sama, dan dapat memperbaikinya dengan mengubah benderanya menjadi:

PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mbauer14
sumber
Terima kasih banyak telah meluangkan waktu untuk memposting apa yang memperbaiki masalah Anda. Saya lupa menyebutkan bahwa saya memberikan tambahan ke Intent. Ini membuat masalah menjadi sedikit lebih kompleks. Periksa Edit saya 1.
9

Seperti yang dikatakan dokumentasi, gunakan kode permintaan unik:

Jika Anda benar-benar membutuhkan beberapa objek PendingIntent berbeda yang aktif pada saat yang sama (seperti untuk digunakan sebagai dua notifikasi yang keduanya ditampilkan pada saat yang sama), maka Anda perlu memastikan ada sesuatu yang berbeda pada objek tersebut untuk mengaitkannya dengan yang berbeda. PendingIntents. Ini bisa berupa salah satu atribut Intent yang dipertimbangkan oleh Intent.filterEquals, atau integer kode permintaan berbeda yang diberikan ke getActivity (Context, int, Intent, int), getActivities (Context, int, Intent [], int), getBroadcast (Context, int , Intent, int), atau getService (Context, int, Intent, int).

Tomasz
sumber
1
Ini adalah satu-satunya jawaban yang benar dan tepat. Sedang mencarinya, karena saya ingin memposting hal yang sama. :-)
Sevastyan Savanyuk
7

Fwiw, saya lebih beruntung PendingIntent.FLAG_CANCEL_CURRENTdaripada dengan PendingIntent.FLAG_UPDATE_CURRENT.

Jon Shemitz
sumber
Saya sangat setuju dengan ini. Tidak perlu mengisi maksud dengan ekstra yang tidak berguna jika kita dapat membatalkan yang lama lalu membuat yang baru. Memang benar bahwa terkadang tidak ada gunanya jika tidak ada yang berubah, tetapi sekarang pertanyaannya adalah "menghemat memori atau menghemat waktu".
zeroDivider
4

Saya memiliki masalah yang sama dan saya memperbaikinya dengan langkah-langkah di bawah ini

1) Hapus semua bendera untuk maksud

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);

2) masukkan intent.setAction dengan kode di bawah ini

 intent.setAction(Long.toString(System.currentTimeMillis()));

3) untuk Pendingintent, masukkan kode di bawah ini

   PendingIntent Pintent = PendingIntent.getActivity(ctx,0, intent,PendingIntent.FLAG_UPDATE_CURRENT);

Saya berharap dapat bekerja sama dengan Anda

Waleed A. Elgalil
sumber
1
Ada yang peduli untuk menjelaskan mengapa jawaban ini tidak disukai. Ini berhasil untuk saya. Saya tidak tahu apakah ini jawaban yang sah, tetapi solusi ini adalah solusi yang tepat. Setidaknya untuk saya.
Sandeep R
Bekerja untuk saya juga! Terima kasih!
Andres
2
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);

Dalam PendingIntent ada dua parameter int, yang kedua dan yang terakhir. Yang kedua adalah "kode permintaan" dan itu harus berupa nomor unik (misalnya id pemberitahuan Anda), jika tidak (seperti dalam contoh Anda itu sama dengan nol, itu akan selalu ditimpa).

Dmytro Ubogyi
sumber
0
// Use pending Intent and  also use unique id for display notification....
// Get a PendingIntent containing the entire back stack
PendingIntent notificationPendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
NotificationManager mNotificationManager = (NotificationManager)  sqlitewraper.context.getSystemService(Context.NOTIFICATION_SERVICE);
// Issue the notification
mNotificationManager.notify(id, builder.build());
MIkka Marmik
sumber
0

untuk mengirim data ekstra dengan benar, Anda harus mengirim dengan maksud tertunda id pemberitahuan seperti ini: PendingIntent pendingIntent = PendingIntent.getActivity (konteks, (int) System.currentTimeMillis () , maksud, PendingIntent.FLAG_UPDATE_CURRENT);

Amal Kronz
sumber
0

Saya memiliki masalah yang sama, dan menggunakan PendingIntent.html.FLAG_UPDATE_CURRENT untuk memperbaikinya.

Saya telah memeriksa kode sumbernya. Di ActivityManagerService.java , metode kuncinya adalah sebagai berikut. Jika benderanya adalah PendingIntent.FLAG_UPDATE_CURRENT dan updateCurrent adalah true. Beberapa tambahan akan diganti dengan yang baru dan kami akan mendapatkan PendingIntent yang diganti.

    IIntentSender getIntentSenderLocked(int type, String packageName,
            int callingUid, int userId, IBinder token, String resultWho,
            int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
            Bundle bOptions) {

// ... omitted

        final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
        final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
        final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
        flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
                |PendingIntent.FLAG_UPDATE_CURRENT);

        PendingIntentRecord.Key key = new PendingIntentRecord.Key(
                type, packageName, activity, resultWho,
                requestCode, intents, resolvedTypes, flags, bOptions, userId);
        WeakReference<PendingIntentRecord> ref;
        ref = mIntentSenderRecords.get(key);
        PendingIntentRecord rec = ref != null ? ref.get() : null;
        if (rec != null) {
            if (!cancelCurrent) {
                if (updateCurrent) {
                    if (rec.key.requestIntent != null) {
                        rec.key.requestIntent.replaceExtras(intents != null ?
                                intents[intents.length - 1] : null);
                    }
                    if (intents != null) {
                        intents[intents.length-1] = rec.key.requestIntent;
                        rec.key.allIntents = intents;
                        rec.key.allResolvedTypes = resolvedTypes;
                    } else {
                        rec.key.allIntents = null;
                        rec.key.allResolvedTypes = null;
                    }
                }
                return rec;
            }
            rec.canceled = true;
            mIntentSenderRecords.remove(key);
        }

qin hao
sumber
-5

Saya memiliki masalah yang sama, dan dapat memperbaikinya dengan mengubah benderanya menjadi:

LayoutInflater factory = LayoutInflater.from(this);            
      final View textEntryView = factory.inflate(R.layout.appointment, null);
      AlertDialog.Builder bulider= new AlertDialog.Builder(PatientDetail.this);
      final AlertDialog alert=bulider.create();


        bulider.setTitle("Enter Date/Time");
        bulider.setView(textEntryView);
        bulider.setPositiveButton("Save", new DialogInterface.OnClickListener() {

                public void onClick(DialogInterface dialog, int which) {
                      EditText typeText=(EditText) textEntryView.findViewById(R.id.Editdate);
                      EditText input1 =(EditText) textEntryView.findViewById(R.id.Edittime);
                      getDateAndTime(typeText.getText().toString(),input1.getText().toString());
                }
            });
        bulider.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {

                public void onClick(DialogInterface dialog, int which) {
                    dialog.cancel();
                }
            });

        bulider.show();

    }
pengguna1917789
sumber
4
Ini tidak ada hubungannya dengan pertanyaan yang diajukan.
Paul Turchenko
Perlu klarifikasi bagaimana hubungannya dengan pertanyaan ini.
Norman H