PendingIntent, ilk bildirim için doğru, geri kalanı için yanlış çalışıyor


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

Bu işlev birden çok kez çağrılacaktır. Her birinin notificationtıklandığında testActivity'yi başlatmasını istiyorum. Ne yazık ki, yalnızca ilk bildirim testActivity'yi başlatır. Geri kalanına tıklamak, bildirim penceresinin küçülmesine neden olur.

Ekstra bilgi: Fonksiyon displayNotification(), adı verilen bir sınıftadır UploadManager. Contextgeçirilir UploadManagergelen activitybu örnekler. İşlev displayNotification(), yine bir AsyncTask.

Düzenleme 1: String yanıtını Intent intentbir 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);

Bu büyük bir fark yaratıyor çünkü bildirim oluşturulduğunda String yanıtının ne olduğunu yansıtmak için ekstra "yanıta" ihtiyacım var. Bunun yerine, PendingIntent.FLAG_UPDATE_CURRENTekstra "yanıt" kullanımı, son çağrıdaki String yanıtının ne olduğunu yansıtır displayNotification().

Bunun neden dokümantasyonu okuyarak olduğunu biliyorum FLAG_UPDATE_CURRENT. Ancak, şu anda bunun üstesinden nasıl gelineceğinden emin değilim.

Yanıtlar:


126

Kullanmayın Intent.FLAG_ACTIVITY_NEW_TASKPendingIntent.getActivity, kullanım için FLAG_ONE_SHOT yerine


Yorumlardan kopyalandı:

Ardından, Niyet üzerinde bazı kukla eylemler ayarlayın, aksi takdirde ekstralar atlanır. Örneğin

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

Bu bayrak aslında aynı nedenden dolayı çalışmadı, sanırım fazlalıklarım doğru çalışmıyor (Düzenleme 1'ime bakın).

32
Ardından Niyet üzerinde bazı kukla eylemler ayarlayın, aksi takdirde ekstralar atılır. Örneğin intent.setAction ("foo")
ognian

20
Mükemmel. İşe yaradı. Mbauer'in önerdiği FLAG_UPDATE_CURRENT kullanımı ile bağlantılı olarak ayarladım (Long.toString (System.currentTimeMillis ())). FLAG_ONE_SHOT kullanımı bildirimi yalnızca bir kez tıklamama izin verdi (bu mantıklı). Çok teşekkürler Ognian.

5
"Öyleyse, Niyette bazı kukla eylemler ayarlayın, aksi takdirde ekstralar atılır" - bu bir yerde belgelenmiş mi?
Mr_and_Mrs_D

SetAction mekanizması benim için çalıştı. Belgelendiği kadar emin değilim, ancak Android için kaynak android.googlesource.com adresinde mevcuttur ;-)
Norman H

62

Boğuşuyordu RemoteViewsve birkaç farklı Intentsher biri için Buttonüzerinde HomeScreenWidget. Bunlar eklendiğinde çalıştı:

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

+1 Harika Teşekkürler. İntent.setAction () eklemenin neden işe yaramasına neden olduğuna dair bir fikriniz var mı?
AjOnFire

setAction çalışıyor ama ya gerçekten eylemlerimi başka bir şeye ayarlamam gerekirse? Çerçeve neden bu kadar hatalı?
LyteSpeed

2
Sadece Android SDK (... geliştiricilere kadar sezgisel nasıl seviyorum: ♥ ️ BTW nedenine açıklama için aşağıdaki @ObjectiveTruth cevabı okundusetAction
Aviel Brüt

1
Garip bir davranış oluyordu, setAction yöntemi olmadan çağrı amacı ekstraları hata ayıklama sırasında çalışacaktı, ancak hata ayıklama yapılmadığında amaç ekstraları her zaman ilk çağrıda geçirilen ilk ekstralar ile aynı olacaktı. Hata ayıklama sırasında, onCreate uygulamasının uygulamadan çıkarken her zaman çağrıldığını, ancak hata ayıklamadan onCreate'in çağrılmadığını, yalnızca onStart çağrıldığını gördüm. SetAction yöntemini çağırmak sorunu çözdü, sanırım sadece ekstra değer değiştiyse amaçların 'farklı' olmamasıyla ilgili bir şey.
MaxJ

@clu Zaten kullandığım setActioniçin yapabilecekleriniz addCategory. eylem, veri, tip, sınıf ve kategorilerin eşitliğini kontrol etmek için PendingIntentkullanır Intent.filterEquals. developer.android.com/reference/android/content/…
iamreptar

44

Eylemi Ayarla Bunu benim için çözdü. Durumla ilgili anlayışım şu:


Her birine bir PendingIntent eklenmiş birden çok widget'ım var. Ne zaman biri güncellendiğinde hepsi güncellenir. Bayraklar, tamamen aynı olan PendingIntents ile ne olduğunu açıklamak için oradadır.

FLAG_UPDATE_CURRENT açıklaması şimdi çok daha iyi okuyor:

Yaptığınız aynı PendingIntent zaten mevcutsa, tüm eskileri yaptığınız yeni PendingIntent'e güncelleyin.

Tam olarak aynı tanım, ekstralar HARİÇ tüm PendingIntent'e bakar. Bu nedenle, her amaç için farklı ekstralarınız olsa bile (benim için appWidgetId'yi ekliyordum) sonra android için bunlar aynı.

.SetAction'ın bazı benzersiz benzersiz dizelerle eklenmesi, işletim sistemine söyler. Bunlar tamamen farklıdır ve hiçbir şeyi güncellemez. Sonunda, istediğim gibi çalışan, her Widget'ın kendi yapılandırma Amacının eklendiği uygulamam burada:

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

GÜNCELLEME


Yayınlarla çalışmanız durumunda daha da iyi bir çözüm. Benzersiz PendingIntents, benzersiz istek kodlarıyla da tanımlanır. İşte benim çözümüm:

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

1
Güzel Temiz Çözüm
Varun Garg

1
Benim için benzersiz bir kimliğe ve beklemedeki niyet için PendingIntent.FLAG_ONE_SHOT'a sahip olmak ve amaç üzerinde setAction çalıştı.
Kaustuv

niyet değişikliği için ekstra değişiklikleri düşünmemesi biraz garip, ancak doğru gibi görünüyor: /
zeroDivider

20

Cevapları görüyorum ama açıklama yok. Ayrıca yanıtların hiçbiri olası tüm çözümleri ele almıyor, bu yüzden bunu netleştirmeye çalışacağım.

Dokümantasyon:

Aynı anda aktif olan birden fazla farklı PendingIntent nesnesine gerçekten ihtiyacınız varsa (örneğin, her ikisi de aynı anda gösterilen iki bildirim olarak kullanmak gibi), onları farklı PendingIntents. Bu, Intent.filterEquals tarafından değerlendirilen herhangi bir Intent özniteliği veya getActivity (Context, int, Intent, int), getActivities (Context, int, Intent [], int), getBroadcast (Context, int , Intent, int) veya getService (Context, int, Intent, int).

Sorunun nedeni:

Bekleyen 2 niyetle 2 bildirim oluşturursunuz. Bekleyen her niyet bir amaç ile ilişkilendirilir:

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

Ancak, bu 2 amaç eşittir, bu nedenle 2. bildiriminiz geldiğinde ilk amacı başlatacaktır.

Çözüm:

Bekleyen hiçbir niyetin hiçbir zaman eşit olmaması için her bir amacı benzersiz kılmalısınız. Amaçları nasıl benzersiz kılarsınız? Eklediğiniz figüranlarla değil putExtra(). Ekstralar farklı olsa bile, niyetler yine de eşit olabilir. Her bir amacı benzersiz kılmak için, amaç eylemi veya verileri, türü, sınıfı veya kategorisi veya istek kodu için benzersiz bir değer ayarlamanız gerekir: (bunlardan herhangi biri işe yarayacaktır)

  • aksiyon: intent.setAction(...)
  • veri: intent.setData(...)
  • türü: intent.setType(...)
  • sınıf: intent.setClass(...)
  • kategori: intent.addCategory(...)
  • istek kodu: PendingIntent.getActivity(context, YOUR_UNIQUE_CODE, intent, Intent.FLAG_ONE_SHOT);

Not : Benzersiz bir istek kodu ayarlamak zor olabilir çünkü bir tamsayıya ihtiyaç duyarsınız, System.currentTimeMillis()uzun döndürür, bu da bazı rakamların kaldırılacağı anlamına gelir. Bu nedenle ya kategoriye ya da eyleme gitmenizi ve benzersiz bir dize ayarlamanızı öneririm .


Her bildirim için benzersiz bir kimlik (yine de iptal edilebilirlik için gereklidir) ve işlem başına özel bir kategori (aynı bildirimde asla aynı türden birden fazla eylem olmayacak) kullanarak sonuçta benim için işe yarayan şey buydu.
MandisaW

Evet, her amaç için de benzersiz bir kategori kullanıyorum, harika çalışıyor.
steliosf

Aynı problem var. aynı anda iki bildirim tetiklendi. ikinci bildirimi tıkladığımda hiçbir şey olmadı. bu setAction (Long.toString (System.currentTimeMillis ())) ayarlandıktan sonra; . çekicilik gibi çalışıyor. güzel açıklama için teşekkürler @MScott
Anantha Babu

13

Aynı sorunu yaşadım ve bayrağı şu şekilde değiştirerek düzeltebildim:

PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

Sorunu sizin için düzelten şeyi göndermek üzere zaman ayırdığınız için çok teşekkür ederiz. Niyete fazladan bir şey ilettiğimi söylemeyi unuttum. Bu, sorunu biraz daha karmaşık hale getirir. Düzenlememi Kontrol Et 1.

9

Belgelerin dediği gibi benzersiz istek kodu kullanın:

Aynı anda aktif olan birden fazla farklı PendingIntent nesnesine gerçekten ihtiyacınız varsa (örneğin, her ikisi de aynı anda gösterilen iki bildirim olarak kullanmak gibi), onları farklı PendingIntents. Bu, Intent.filterEquals tarafından değerlendirilen herhangi bir Intent özniteliği veya getActivity (Context, int, Intent, int), getActivities (Context, int, Intent [], int), getBroadcast (Context, int , Intent, int) veya getService (Context, int, Intent, int).


1
Tek doğru ve doğru cevap budur. Arıyordum çünkü aynı şeyi göndermek istedim. :-)
Sevastyan Savanyuk

7

FWIW, ben daha şanslı oldu PendingIntent.FLAG_CANCEL_CURRENTkıyasla PendingIntent.FLAG_UPDATE_CURRENT.


Buna tamamen katılıyorum. Eskisini iptal edip yeni bir tane oluşturabilirsek, niyetleri gereksiz ekstralarla doldurmaya gerek yoktur. Bazen hiçbir şey değişmediğinde faydasız olabileceği doğrudur, ancak şimdi soru "hafızadan tasarruf etmek veya zamandan tasarruf etmek".
zeroDivider

4

Aynı sorunu yaşadım ve aşağıdaki adımlarla düzelttim

1) Niyet için herhangi bir bayrağı temizleyin

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

2) aşağıdaki koda göre intent.setAction ekleyin

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

3) Pendingintent için aşağıdaki kodu girin

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

Seninle çalışmayı umuyorum


1
Herhangi biri bu cevaba neden olumsuz oy verildiğini açıklamak ister. Bu benim için çalıştı. Bunun yasal bir cevap olup olmadığını bilmiyorum, ancak bu çözüm mükemmel bir çözüm. En azından benim için.
Sandeep R

Benim için de çalıştı! Teşekkürler!
Andres

2
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);

PendingIntent'te iki int parametresi vardır, ikincisi ve sonuncusu. İkincisi "istek kodu" ve tek numara olmalıdır (örneğin bildiriminizin kimliği), aksi takdirde (örneğinizde sıfıra eşitse, her zaman üzerine yazılacaktır).


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

0

verileri ekstra doğru bir şekilde göndermek için, beklemede olarak bildirim kimliğini şu şekilde göndermelisiniz: PendingIntent pendingIntent = PendingIntent.getActivity (context, (int) System.currentTimeMillis () , intent, PendingIntent.FLAG_UPDATE_CURRENT);


0

Aynı sorunu yaşıyorum ve düzeltmek için PendingIntent.html.FLAG_UPDATE_CURRENT'i kullanıyorum .

Kaynak kodunu kontrol ettim. Gelen ActivityManagerService.java , temel yöntem olarak aşağıdaki gibidir. Bayrak PendingIntent.FLAG_UPDATE_CURRENT olduğunda ve updateCurrent doğru olduğunda. Bazı ekstralar yenileriyle değiştirilecek ve değiştirilen bir PendingIntent alacağız.

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


-5

Aynı sorunu yaşadım ve bayrağı şu şekilde değiştirerek düzeltebildim:

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

    }

4
Sorulan bir soruyla ilgisi yok.
Paul Turchenko

Bu soruyla nasıl ilişkili olduğunu netleştirmemiz gerekiyor.
Norman H
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.