PendingIntent ทำงานได้อย่างถูกต้องสำหรับการแจ้งเตือนครั้งแรก แต่ส่วนที่เหลือไม่ถูกต้อง


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

ฟังก์ชันนี้จะถูกเรียกใช้หลายครั้ง ฉันต้องการให้แต่ละคนnotificationเปิด testActivity เมื่อคลิก น่าเสียดายที่มีเพียงการแจ้งเตือนครั้งแรกเท่านั้นที่เปิดตัว testActivity การคลิกที่ส่วนที่เหลือทำให้หน้าต่างการแจ้งเตือนย่อเล็กสุด

ข้อมูลเสริม: ฟังก์ชั่นที่อยู่ในระดับที่เรียกว่า displayNotification() ถูกส่งผ่านเข้ามาจากอินสแตนซ์นั้น ฟังก์ชันถูกเรียกหลายครั้งจากฟังก์ชันเช่นเดียวกับใน UploadManager ที่ทำงานในไฟล์.UploadManagerContextUploadManageractivitydisplayNotification()AsyncTask

แก้ไข 1: ฉันลืมที่จะพูดถึงว่าฉันกำลังส่งการตอบกลับของสตริงIntent intentเป็น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);

สิ่งนี้สร้างความแตกต่างอย่างมากเพราะฉันต้องการ "การตอบกลับ" พิเศษเพื่อแสดงถึงการตอบสนองของสตริงเมื่อสร้างการแจ้งเตือน แทนที่จะใช้PendingIntent.FLAG_UPDATE_CURRENTการพิเศษ "ตอบสนอง" สะท้อนให้เห็นถึงสิ่งที่ตอบสนอง String displayNotification()อยู่ในสายสุดท้ายที่จะ

FLAG_UPDATE_CURRENTฉันรู้ว่าทำไมนี้มาจากการอ่านเอกสารบน อย่างไรก็ตามฉันไม่แน่ใจว่าจะแก้ไขอย่างไรในขณะนี้

คำตอบ:


126

อย่าใช้Intent.FLAG_ACTIVITY_NEW_TASKสำหรับ PendingIntent.getActivity ให้ใช้FLAG_ONE_SHOTแทน


คัดลอกจากความคิดเห็น:

จากนั้นตั้งค่าการดำเนินการหลอกๆใน Intent มิฉะนั้นจะถูกทิ้ง ตัวอย่างเช่น

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

การตั้งค่าสถานะนี้ใช้ไม่ได้จริงด้วยเหตุผลเดียวกันฉันคิดว่าส่วนเสริมของฉันทำงานไม่ถูกต้อง (ตรวจสอบแก้ไข 1 ของฉัน)

32
จากนั้นตั้งค่าการดำเนินการหลอกๆใน Intent มิฉะนั้นจะถูกทิ้ง ตัวอย่างเช่น Intent.setAction ("foo")
ognian

20
ยอดเยี่ยม. ที่ได้ผล ฉัน setAction (Long.toString (System.currentTimeMillis ())) ร่วมกับการใช้ FLAG_UPDATE_CURRENT ที่ mbauer แนะนำ การใช้ FLAG_ONE_SHOT อนุญาตให้ฉันคลิกการแจ้งเตือนเพียงครั้งเดียวเท่านั้น (ซึ่งสมเหตุสมผล) ขอบคุณมาก ognian

5
"จากนั้นตั้งค่าการดำเนินการหลอกๆใน Intent มิฉะนั้นจะหลุด" - เอกสารนี้มีบันทึกไว้ที่ไหน
Mr_and_Mrs_D

กลไก setAction ใช้ได้ผลสำหรับฉัน เท่าที่บันทึกไว้ไม่แน่ใจ แต่ source สำหรับ Android มีอยู่ที่android.googlesource.com ;-)
Norman H

62

กำลังต่อสู้กับRemoteViewsและอีกหลายที่แตกต่างกันIntentsสำหรับแต่ละButtonบนHomeScreenWidget ทำงานเมื่อเพิ่มสิ่งเหล่านี้:

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 ขอบคุณครับ มีความคิดว่าทำไมการเพิ่ม Intent.setAction () ถึงได้ผล?
AjOnFire

setAction ใช้งานได้จริง แต่ถ้าฉันต้องตั้งค่า Intent Action เป็นอย่างอื่นล่ะ ทำไมกรอบจึงมีปัญหา?
LyteSpeed

2
ฉันชอบที่ Android SDK ใช้งานง่ายสำหรับนักพัฒนา ... (: ♥️ BTW อ่านคำตอบของ @ObjectiveTruth ด้านล่างสำหรับคำอธิบายเกี่ยวกับเหตุผลของsetAction
Aviel Gross

1
ได้รับพฤติกรรมแปลก ๆ โดยไม่มีการเรียกใช้ Intent Extras เมธอด setAction จะใช้งานได้ในขณะที่การดีบัก แต่เมื่อไม่ดีบักเจตนาพิเศษจะเหมือนกับค่าบริการพิเศษเริ่มต้นที่ส่งผ่านในการโทรครั้งแรก ฉันพบว่าในขณะที่การดีบัก onCreate จะถูกเรียกใช้เสมอเมื่อออกจากแอป แต่ในขณะที่ไม่ได้ทำการดีบักก็ไม่ได้เรียก onCreate มีเพียง onStart เท่านั้น การเรียกเมธอด setAction สามารถแก้ไขปัญหาได้ฉันเดาว่าเป็นสิ่งที่เกี่ยวข้องกับการที่ Intent ไม่ 'แตกต่าง' หากมีการเปลี่ยนแปลงเฉพาะค่าพิเศษเท่านั้น
MaxJ

@clu ตั้งแต่ฉันใช้สิ่งที่คุณสามารถทำได้คือsetAction ใช้เพื่อตรวจสอบความเท่าเทียมกันของการกระทำข้อมูลประเภทคลาสและประเภท developer.android.com/reference/android/content/…addCategoryPendingIntentIntent.filterEquals
iamreptar

44

Set Action แก้ไขปัญหานี้ให้ฉัน นี่คือความเข้าใจของฉันเกี่ยวกับสถานการณ์:


ฉันมีหลายวิดเจ็ตที่มี PendingIntent แนบกับแต่ละวิดเจ็ต เมื่อใดก็ตามที่มีการอัปเดตพวกเขาทั้งหมดได้รับการอัปเดต ธงมีไว้เพื่ออธิบายสิ่งที่เกิดขึ้นกับ PendingIntents ที่เหมือนกันทุกประการ

คำอธิบาย FLAG_UPDATE_CURRENT อ่านดีขึ้นมากในขณะนี้:

หาก PendingIntent เดียวกันกับที่คุณทำอยู่แล้วให้อัปเดตรายการเก่าทั้งหมดเป็น PendingIntent ใหม่ที่คุณกำลังทำ

คำจำกัดความของรูปลักษณ์ที่เหมือนกันทุกประการที่ PendingIntent ทั้งหมดยกเว้นส่วนเสริม ดังนั้นแม้ว่าคุณจะมีความพิเศษที่แตกต่างกันในแต่ละเจตนา (สำหรับฉันฉันกำลังเพิ่ม appWidgetId) ไปยัง Android พวกมันก็เหมือนกัน

การเพิ่ม. setAction ด้วยสตริงที่ไม่ซ้ำกันหลอกบอกระบบปฏิบัติการ สิ่งเหล่านี้แตกต่างกันอย่างสิ้นเชิงและไม่อัปเดตอะไรเลย ในท้ายที่สุดนี่คือการใช้งานของฉันซึ่งทำงานได้ตามที่ฉันต้องการโดยที่แต่ละวิดเจ็ตจะมี 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);

อัปเดต


ทางออกที่ดียิ่งขึ้นในกรณีที่คุณกำลังทำงานกับการออกอากาศ PendingIntents ที่ไม่ซ้ำยังกำหนดโดยรหัสคำขอที่ไม่ซ้ำกัน นี่คือวิธีแก้ปัญหาของฉัน:

//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
Nice Clean Solution
Varun Garg

1
สำหรับฉันมี id ที่ไม่ซ้ำกันและ PendingIntent.FLAG_ONE_SHOT สำหรับความตั้งใจที่รอดำเนินการพร้อมกับ setAction เกี่ยวกับความตั้งใจทำงานได้
Kaustuv

เป็นเรื่องแปลกเล็กน้อยที่ไม่ได้พิจารณาการเปลี่ยนแปลงพิเศษสำหรับการเปลี่ยนแปลงเจตนา แต่ดูเหมือนว่าจะเป็นจริง: /
zeroDivider

20

ฉันเห็นคำตอบ แต่ไม่มีคำอธิบาย ยังไม่มีคำตอบใดที่กล่าวถึงวิธีแก้ปัญหาที่เป็นไปได้ทั้งหมดดังนั้นฉันจะพยายามทำให้ชัดเจน

เอกสารประกอบ:

หากคุณต้องการใช้งานออบเจ็กต์ PendingIntent ที่แตกต่างกันหลายรายการพร้อมกันอย่างแท้จริง (เช่นใช้เป็นการแจ้งเตือนสองรายการที่แสดงพร้อมกัน) คุณจะต้องตรวจสอบให้แน่ใจว่ามีบางอย่างที่แตกต่างกันเกี่ยวกับวัตถุเหล่านี้เพื่อเชื่อมโยงกับวัตถุอื่น PendingIntents นี่อาจเป็นแอตทริบิวต์ Intent ใด ๆ ที่พิจารณาโดย Intent.filterEquals หรือจำนวนเต็มรหัสคำขอที่แตกต่างกันที่จัดหาให้กับ getActivity (Context, int, Intent, int), getActivities (Context, int, Intent [], int), getBroadcast (Context, int , Intent, int) หรือ getService (Context, int, Intent, int)

สาเหตุของปัญหา:

คุณสร้างการแจ้งเตือน 2 รายการโดยมี 2 Intent ที่รอดำเนินการ ความตั้งใจที่รอดำเนินการแต่ละรายการเกี่ยวข้องกับเจตนา:

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

อย่างไรก็ตาม 2 เจตนานี้เท่ากันดังนั้นเมื่อการแจ้งเตือนครั้งที่ 2 ของคุณมาถึงมันจะเริ่มเจตนาแรก

วิธีการแก้:

คุณต้องทำให้แต่ละเจตนาไม่ซ้ำกันเพื่อไม่ให้เจตนาที่รอดำเนินการมีค่าเท่ากัน คุณทำให้ความตั้งใจไม่เหมือนใครได้อย่างไร putExtra()โดยไม่ได้รับความพิเศษที่คุณใส่ด้วย แม้ว่าความพิเศษจะแตกต่างกัน แต่ความตั้งใจก็ยังคงเท่ากัน ในการทำให้แต่ละเจตนาไม่ซ้ำกันคุณต้องตั้งค่าที่ไม่ซ้ำกันให้กับการกระทำตามความตั้งใจหรือข้อมูลหรือประเภทหรือคลาสหรือหมวดหมู่หรือรหัสคำขอ: (อย่างใดอย่างหนึ่งจะใช้ได้)

  • หนังบู๊: intent.setAction(...)
  • ข้อมูล: intent.setData(...)
  • ชนิด: intent.setType(...)
  • ชั้น: intent.setClass(...)
  • ประเภท: intent.addCategory(...)
  • ต้องการรหัส: PendingIntent.getActivity(context, YOUR_UNIQUE_CODE, intent, Intent.FLAG_ONE_SHOT);

หมายเหตุ : การตั้งรหัสคำขอที่ไม่ซ้ำกันอาจเป็นเรื่องยุ่งยากเนื่องจากคุณต้องใช้ int ในขณะที่System.currentTimeMillis()ส่งกลับค่ายาวซึ่งหมายความว่าตัวเลขบางตัวจะถูกลบออก ดังนั้นฉันขอแนะนำให้ใช้หมวดหมู่หรือการดำเนินการและตั้งค่าสตริงเฉพาะ


นี่คือสิ่งที่ใช้ได้ผลสำหรับฉันในที่สุดโดยใช้ ID ที่ไม่ซ้ำกันสำหรับการแจ้งเตือนแต่ละรายการ (จำเป็นสำหรับการยกเลิก) และหมวดหมู่ที่กำหนดเองต่อการกระทำ (จะไม่มีการดำเนินการประเภทเดียวกันหลายรายการในการแจ้งเตือนเดียวกัน)
MandisaW

ใช่ฉันใช้หมวดหมู่ที่ไม่ซ้ำกันสำหรับแต่ละความตั้งใจเช่นกันมันใช้งานได้ดี
steliosf

มีปัญหาเดียวกัน การแจ้งเตือนสองรายการถูกเรียกใช้ในเวลาเดียวกัน เมื่อฉันคลิกการแจ้งเตือนครั้งที่สองไม่มีอะไรเกิดขึ้น หลังจากตั้งค่า setAction นี้แล้ว (Long.toString (System.currentTimeMillis ())); . มันใช้งานได้เหมือนมีเสน่ห์ ขอบคุณสำหรับคำอธิบายที่ดี @MScott
Anantha Babu

13

ฉันมีปัญหาเดียวกันและสามารถแก้ไขได้โดยเปลี่ยนแฟล็กเป็น:

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

ขอบคุณมากที่สละเวลาโพสต์สิ่งที่ช่วยแก้ปัญหาให้คุณได้ ฉันลืมที่จะพูดถึงว่าฉันกำลังส่งข้อมูลเพิ่มเติมเข้าสู่เจตจำนง ซึ่งทำให้ปัญหาซับซ้อนขึ้นเล็กน้อย ตรวจสอบการแก้ไขของฉัน 1.

9

ตามเอกสารระบุว่าให้ใช้รหัสคำขอเฉพาะ:

หากคุณต้องการใช้งานออบเจ็กต์ PendingIntent ที่แตกต่างกันหลายรายการพร้อมกันอย่างแท้จริง (เช่นใช้เป็นการแจ้งเตือนสองรายการที่แสดงพร้อมกัน) คุณจะต้องตรวจสอบให้แน่ใจว่ามีบางอย่างที่แตกต่างกันเกี่ยวกับวัตถุเหล่านี้เพื่อเชื่อมโยงกับวัตถุอื่น PendingIntents นี่อาจเป็นแอตทริบิวต์ Intent ใด ๆ ที่พิจารณาโดย Intent.filterEquals หรือจำนวนเต็มรหัสคำขอที่แตกต่างกันที่จัดหาให้กับ getActivity (Context, int, Intent, int), getActivities (Context, int, Intent [], int), getBroadcast (Context, int , Intent, int) หรือ getService (Context, int, Intent, int)


1
นี่เป็นคำตอบที่แท้จริงและตรงประเด็นเท่านั้น กำลังมองหามันทำให้ฉันต้องการโพสต์สิ่งเดียวกัน :-)
Sevastyan Savanyuk

7

FWIW ผมมีโชคดีขึ้นด้วยกว่าด้วยPendingIntent.FLAG_CANCEL_CURRENTPendingIntent.FLAG_UPDATE_CURRENT


ฉันเห็นด้วยอย่างยิ่งกับเรื่องนี้ ไม่จำเป็นต้องเติม Intent ด้วยความพิเศษที่ไร้ประโยชน์หากเราสามารถยกเลิกอันเก่าแล้วสร้างใหม่ได้ จริงอยู่ที่บางครั้งมันอาจจะไร้ประโยชน์หากไม่มีอะไรเปลี่ยนแปลง แต่ตอนนี้คำถามคือ "เพื่อบันทึกความทรงจำหรือเพื่อประหยัดเวลา"
zeroDivider

4

ฉันมีปัญหาเดียวกันและฉันแก้ไขตามขั้นตอนด้านล่าง

1) ล้างธงสำหรับเจตนา

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

2) แทรกเจตนา setAction ตามรหัสด้านล่าง

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

3) สำหรับ Pendingintent ให้ใส่รหัสด้านล่าง

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

ฉันหวังว่าจะได้ร่วมงานกับคุณ


1
ใครก็ได้สนใจที่จะอธิบายว่าทำไมคำตอบนี้จึงถูกลดลง สิ่งนี้ได้ผลสำหรับฉัน ฉันไม่รู้ว่านี่เป็นคำตอบที่ถูกต้องหรือไม่ แต่โซลูชันนี้เป็นโซลูชันที่สมบูรณ์แบบ อย่างน้อยที่สุดสำหรับฉัน
Sandeep R

ทำงานให้ฉันด้วย! ขอบคุณ!
Andres

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

ใน PendingIntent คือพารามิเตอร์ int สองพารามิเตอร์ตัวที่สองและพารามิเตอร์สุดท้าย อันที่สองคือ "รหัสคำขอ" และต้องเป็นหมายเลขเดียว (เช่น id ของการแจ้งเตือนของคุณ) มิฉะนั้นถ้า (ตามตัวอย่างของคุณมีค่าเท่ากับศูนย์จะถูกเขียนทับเสมอ)


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

ในการส่งข้อมูลพิเศษอย่างถูกต้องคุณควรส่งโดยมีเจตนารอดำเนินการรหัสการแจ้งเตือนเช่นนี้ PendingIntent pendingIntent = PendingIntent.getActivity (บริบท(int) System.currentTimeMillis () , ความตั้งใจ, PendingIntent.FLAG_UPDATE_CURRENT);


0

ฉันมีปัญหาเดียวกันและใช้PendingIntent.html.FLAG_UPDATE_CURRENTเพื่อแก้ไข

ฉันได้ตรวจสอบซอร์สโค้ดแล้ว ใน ActivityManagerService.javaวิธีการสำคัญมีดังนี้ เมื่อแฟล็กเป็น PendingIntent.FLAG_UPDATE_CURRENT และ updateCurrent เป็นจริง สิ่งพิเศษบางอย่างจะถูกแทนที่ด้วยสิ่งใหม่และเราจะได้รับการแทนที่ PendingIntent

    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

ฉันมีปัญหาเดียวกันและสามารถแก้ไขได้โดยเปลี่ยนแฟล็กเป็น:

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
ไม่มีส่วนเกี่ยวข้องกับคำถามที่ถาม
Paul Turchenko

ต้องชี้แจงว่าเกี่ยวข้องกับคำถามนี้อย่างไร
Norman H
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.