PendingIntent hoạt động chính xác cho thông báo đầu tiên nhưng không chính xác cho phần còn lại


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

Hàm này sẽ được gọi nhiều lần. Tôi muốn mỗi người notificationkhởi chạy testActivity khi được nhấp. Thật không may, chỉ có thông báo đầu tiên khởi chạy testActivity. Nhấp vào phần còn lại sẽ thu nhỏ cửa sổ thông báo.

Thông tin bổ sung: Hàm displayNotification()nằm trong một lớp được gọi UploadManager. Contextđược chuyển vào UploadManagertừ activitykhởi tạo đó. Hàm displayNotification()được gọi nhiều lần từ một hàm, cũng trong UploadManager, đang chạy trong AsyncTask.

Chỉnh sửa 1: Tôi quên đề cập rằng tôi đang chuyển phản hồi Chuỗi thành Intent intentmột 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);

Điều này tạo ra sự khác biệt lớn vì tôi cần thêm "phản hồi" để phản ánh phản hồi Chuỗi là gì khi thông báo được tạo. Thay vào đó, bằng cách sử dụng PendingIntent.FLAG_UPDATE_CURRENT, "phản hồi" bổ sung phản ánh phản hồi của Chuỗi trong lần gọi cuối cùng displayNotification().

Tôi biết tại sao điều này là từ việc đọc tài liệu trên FLAG_UPDATE_CURRENT. Tuy nhiên, tôi không chắc chắn làm thế nào để làm việc xung quanh nó vào lúc này.

Câu trả lời:


125

Không sử dụng Intent.FLAG_ACTIVITY_NEW_TASKcho PendingIntent.getActivity, hãy sử dụng FLAG_ONE_SHOT để thay thế


Được sao chép từ nhận xét:

Sau đó, thiết lập một số hành động giả trên Intent, nếu không các tính năng bổ sung sẽ bị loại bỏ. Ví dụ

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

Cờ này thực sự cũng không hoạt động vì cùng một lý do, tôi nghĩ rằng phần bổ sung của tôi không hoạt động chính xác (kiểm tra Chỉnh sửa 1 của tôi).

32
Sau đó, thiết lập một số hành động giả trên Intent, nếu không các tính năng bổ sung sẽ bị loại bỏ. Ví dụ: Intent.setAction ("foo")
ognian

20
Thông minh. Điều đó đã hiệu quả. Tôi setAction (Long.toString (System.currentTimeMillis ())) kết hợp với việc sử dụng FLAG_UPDATE_CURRENT mà mbauer đã đề xuất. Việc sử dụng FLAG_ONE_SHOT chỉ cho phép tôi nhấp vào thông báo một lần (điều này có ý nghĩa). Cảm ơn rất nhiều ognian.

5
"Sau đó, thiết lập một số hành động giả trên Intent, nếu không các tính năng bổ sung sẽ bị loại bỏ" - điều này có được ghi lại ở đâu đó không?
Mr_and_Mrs_D

Cơ chế setAction đã làm việc cho tôi. Theo như tài liệu, không chắc chắn, nhưng nguồn cho Android có sẵn tại android.googlesource.com ;-)
Norman H

62

Đang vật lộn với RemoteViewsvà một số khác nhau Intentscho mỗi loại Buttontrên HomeScreenWidget. Hoạt động khi được thêm những thứ này:

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 Cảm ơn tuyệt vời. Bất kỳ ý tưởng nào tại sao việc thêm ý định.setAction () làm cho nó hoạt động?
AjOnFire

setAction hoạt động nhưng điều gì sẽ xảy ra nếu tôi thực sự phải đặt ý định Action của mình thành một thứ khác? Tại sao khuôn khổ quá nhiều lỗi?
b.lit

2
Tôi chỉ thích cách Android SDK rất trực quan đối với các nhà phát triển ... (: ♥ ️ BTW đọc câu trả lời @ObjectiveTruth bên dưới để biết giải thích về lý dosetAction
Aviel Gross

1
Đang nhận được hành vi lạ, không có phần bổ sung ý định cuộc gọi phương thức setAction sẽ hoạt động trong khi gỡ lỗi, nhưng khi không gỡ lỗi, phần bổ sung ý định sẽ luôn giống như phần bổ sung ban đầu được chuyển trong lần gọi đầu tiên. Tôi thấy rằng trong khi gỡ lỗi, onCreate luôn được gọi khi điều hướng ra khỏi ứng dụng nhưng trong khi không gỡ lỗi, onCreate không được gọi, chỉ onStart. Việc gọi phương thức setAction đã giải quyết được vấn đề, tôi đoán đó là điều cần làm với các ý định không 'khác' nếu chỉ giá trị phần bổ sung thay đổi.
MaxJ

@clu Vì tôi đã sử dụng setAction, những gì bạn có thể làm là addCategory. PendingIntentsử dụng Intent.filterEqualsđể kiểm tra sự bình đẳng của hành động, dữ liệu, kiểu, lớp và các danh mục. developer.android.com/reference/android/content/…
iamreptar,

43

Đặt hành động đã giải quyết điều này cho tôi. Đây là hiểu biết của tôi về tình huống:


Tôi có nhiều tiện ích con có PendingIntent được đính kèm vào mỗi tiện ích con. Bất cứ khi nào một người được cập nhật, tất cả đều được cập nhật. Các cờ ở đó để mô tả những gì xảy ra với PendingIntents hoàn toàn giống nhau.

Mô tả FLAG_UPDATE_CURRENT hiện đọc tốt hơn nhiều:

Nếu PendingIntent tương tự mà bạn đang tạo đã tồn tại, thì hãy cập nhật tất cả những cái cũ thành PendingIntent mới mà bạn đang tạo.

Định nghĩa của chính xác giống nhau xem xét toàn bộ PendingIntent NGOẠI TRỪ các phần bổ sung. Vì vậy, ngay cả khi bạn có các tính năng bổ sung khác nhau trên mỗi ý định (đối với tôi, tôi đã thêm appWidgetId) thì đối với android, chúng đều giống nhau.

Thêm .setAction với một số chuỗi duy nhất giả sẽ cho hệ điều hành biết. Đây là những thứ hoàn toàn khác nhau và không cập nhật bất cứ điều gì. Cuối cùng, đây là cách triển khai của tôi hoạt động như tôi muốn, trong đó mỗi Widget có Intent cấu hình riêng được đính kèm:

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

CẬP NHẬT


Giải pháp thậm chí còn tốt hơn trong trường hợp bạn đang làm việc với các chương trình phát sóng. Các PendingIntents duy nhất cũng được xác định bởi các mã yêu cầu duy nhất. Đây là giải pháp của tôi:

//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
Giải pháp sạch đẹp
Varun Garg

1
Đối với tôi có id duy nhất và PendingIntent.FLAG_ONE_SHOT cho ý định đang chờ xử lý, cùng với setAction trên ý định đã hoạt động.
Kaustuv

hơi lạ là nó không xem xét các thay đổi bổ sung cho thay đổi mục đích, nhưng có vẻ là đúng: /
zeroDivider 24/09/18

20

Tôi thấy câu trả lời nhưng không có lời giải thích. Ngoài ra, không có câu trả lời nào đề cập đến tất cả các giải pháp khả thi, vì vậy tôi sẽ cố gắng làm rõ điều đó.

Tài liệu:

Nếu bạn thực sự cần nhiều đối tượng PendingIntent riêng biệt hoạt động cùng một lúc (chẳng hạn như để sử dụng làm hai thông báo được hiển thị cùng một lúc), thì bạn sẽ cần đảm bảo có điều gì đó khác biệt về chúng để liên kết chúng với các Đang chờ xử lý. Đây có thể là bất kỳ thuộc tính Intent nào được Intent.filterEquals xem xét hoặc các số nguyên mã yêu cầu khác nhau được cung cấp cho getActivity (Context, int, Intent, int), getActive (Context, int, Intent [], int), getBroadcast (Context, int , Intent, int) hoặc getService (Context, int, Intent, int).

Nguyên nhân của vấn đề:

Bạn tạo 2 thông báo với 2 ý định đang chờ xử lý. Mỗi ý định đang chờ xử lý được liên kết với một ý định:

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

Tuy nhiên, 2 ý định này ngang nhau, do đó khi thông báo thứ 2 của bạn đến, nó sẽ khởi chạy ý định đầu tiên.

Giải pháp:

Bạn phải làm cho mỗi ý định là duy nhất, để không có ý định đang chờ xử lý nào giống nhau. Làm thế nào để bạn làm cho ý định độc đáo? Không phải bởi các tính năng bổ sung mà bạn đặt với putExtra(). Ngay cả khi các tính năng bổ sung khác nhau, ý định vẫn có thể bằng nhau. Để làm cho mỗi ý định là duy nhất, bạn phải đặt một giá trị duy nhất cho hành động ý định hoặc dữ liệu, hoặc loại, hoặc lớp hoặc danh mục hoặc mã yêu cầu: (bất kỳ giá trị nào trong số đó sẽ hoạt động)

  • hoạt động: intent.setAction(...)
  • dữ liệu: intent.setData(...)
  • kiểu: intent.setType(...)
  • lớp học: intent.setClass(...)
  • thể loại: intent.addCategory(...)
  • mã yêu cầu: PendingIntent.getActivity(context, YOUR_UNIQUE_CODE, intent, Intent.FLAG_ONE_SHOT);

Lưu ý : Đặt một mã yêu cầu duy nhất có thể khó vì bạn cần một số nguyên, trong khi System.currentTimeMillis()trả về dài, có nghĩa là một số chữ số sẽ bị xóa. Do đó, tôi khuyên bạn nên đi với danh mục hoặc hành động và đặt một chuỗi duy nhất.


Đây là những gì cuối cùng đã làm việc cho tôi, sử dụng một ID duy nhất cho mỗi thông báo (dù sao cũng cần cho khả năng hủy) và danh mục tùy chỉnh cho mỗi hành động (sẽ không bao giờ có nhiều hành động cùng loại trên cùng một thông báo).
MandisaW

Đúng vậy, tôi cũng đang sử dụng một danh mục duy nhất cho từng ý định, nó hoạt động rất tốt.
steliosf

Có cùng một vấn đề. hai thông báo được kích hoạt cùng một lúc. khi tôi nhấp vào thông báo thứ hai không có gì xảy ra. sau khi thiết lập this setAction (Long.toString (System.currentTimeMillis ())); . nó hoạt động như một sự quyến rũ. nhờ cho đẹp giải thích @MScott
Anantha Babu

13

Tôi gặp sự cố tương tự và có thể khắc phục bằng cách thay đổi cờ thành:

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

Cảm ơn bạn rất nhiều vì đã dành thời gian để đăng những gì đã khắc phục sự cố cho bạn. Tôi quên đề cập rằng tôi đang chuyển một phần bổ sung vào Intent. Điều này làm cho vấn đề phức tạp hơn một chút. Kiểm tra của tôi Sửa 1.

9

Như tài liệu đã nói, hãy sử dụng mã yêu cầu duy nhất:

Nếu bạn thực sự cần nhiều đối tượng PendingIntent riêng biệt hoạt động cùng một lúc (chẳng hạn như để sử dụng làm hai thông báo được hiển thị cùng một lúc), thì bạn sẽ cần đảm bảo có điều gì đó khác biệt về chúng để liên kết chúng với các Đang chờ xử lý. Đây có thể là bất kỳ thuộc tính Intent nào được Intent.filterEquals xem xét hoặc các số nguyên mã yêu cầu khác nhau được cung cấp cho getActivity (Context, int, Intent, int), getActictivity (Context, int, Intent [], int), getBroadcast (Context, int , Intent, int) hoặc getService (Context, int, Intent, int).


1
Đây là câu trả lời đúng và đúng duy nhất. Đang tìm kiếm nó, vì tôi muốn đăng điều tương tự. :-)
Sevastyan Savanyuk

7

Fwiw, tôi đã gặp may mắn PendingIntent.FLAG_CANCEL_CURRENThơn với PendingIntent.FLAG_UPDATE_CURRENT.


Tôi hoàn toàn đồng ý với điều này. Không cần phải lấp đầy các ý định bằng các tính năng bổ sung vô ích nếu chúng ta có thể làm cho nó hủy bỏ ý định cũ và sau đó tạo một ý định mới. Đúng là đôi khi nó có thể vô dụng nếu không có gì thay đổi, nhưng bây giờ câu hỏi là "để tiết kiệm bộ nhớ hoặc để tiết kiệm thời gian".
zeroDivider

4

Tôi đã gặp sự cố tương tự và tôi đã khắc phục nó bằng các bước dưới đây

1) Xóa bất kỳ cờ nào cho mục đích

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

2) chèn Intent.setAction bằng đoạn mã dưới đây

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

3) đối với Pendingintent, hãy chèn mã bên dưới

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

Tôi hy vọng được làm việc với bạn


1
Bất kỳ ai quan tâm để giải thích tại sao câu trả lời này đã bị từ chối. Điều này đã làm việc cho tôi. Tôi không biết đây có phải là câu trả lời hợp pháp hay không, nhưng giải pháp này là giải pháp hoàn hảo. Ít nhất đối với tôi.
Sandeep R

Cũng làm việc cho tôi! Cảm ơn!
Andres

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

Trong PendingIntent là hai tham số int, tham số thứ hai và tham số cuối cùng. Thứ hai là "mã yêu cầu" và nó phải là số unicue (ví dụ: id thông báo của bạn), nếu không (như trong ví dụ của bạn, nó bằng 0, nó sẽ luôn bị ghi đè).


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

để gửi dữ liệu một cách chính xác hơn, bạn nên gửi id thông báo với mục đích đang chờ xử lý như sau: PendingIntent pendingIntent = PendingIntent.getActivity (context, (int) System.currentTimeMillis () , Ý định, PendingIntent.FLAG_UPDATE_CURRENT);


0

Tôi gặp vấn đề tương tự và sử dụng PendingIntent.html.FLAG_UPDATE_CURRENT để khắc phục.

Tôi đã kiểm tra mã nguồn. Trong ActivityManagerService.java , phương thức chính như sau. Khi cờ là PendingIntent.FLAG_UPDATE_CURRENT và updateCurrent là true. Một số tính năng bổ sung sẽ được thay thế bằng mới và chúng tôi sẽ nhận được PendingIntent thay thế.

    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

Tôi gặp sự cố tương tự và có thể khắc phục bằng cách thay đổi cờ thành:

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
Nó không liên quan gì đến một câu hỏi được hỏi.
Paul Turchenko

Cần phải làm rõ nó liên quan như thế nào đến câu hỏi này.
Norman H
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.