アクションがクリックされた後に通知を却下する方法


142

APIレベル16(Jelly Bean)以降、通知にアクションを追加する可能性があります

builder.addAction(iconId, title, intent);

しかし、通知にアクションを追加し、そのアクションが押されると、通知が閉じられなくなります。通知自体をクリックしているときは、次のようにして閉じることができます。

notification.flags = Notification.FLAG_AUTO_CANCEL;

または

builder.setAutoCancel(true);

しかし、明らかに、これは通知に関連付けられたアクションとは何の関係もありません。

ヒントはありますか?または、これはまだAPIの一部ではありませんか?何も見つかりませんでした。

回答:


154

通知マネージャーでnotifyを呼び出したときに、IDを指定しました。これは、後でアクセスするために使用できる一意のIDです(これは通知マネージャーからのものです:

notify(int id, Notification notification)

キャンセルするには、次を呼び出します:

cancel(int id)

同じIDで。したがって、基本的には、IDを追跡する必要があるか、IDをPendingIntent内のインテントに追加するバンドルに入れる必要がありますか?


25
ありがとう、それで私の問題は解決しました。しかし、それでも少し複雑すぎると思います。アクションが押されたときに通知を自動的に閉じるAPIを提供するだけでなく、同じ目的を達成するためにインテントと通知IDを渡す必要があります。
endowzoner 2012

2
これが複雑であると思われる場合は、通知の更新(そのIDを追跡しないでください)や、表示されているかどうかを確認しないでください(APIが追跡しないため、追跡する必要があります)...: P
トラビス

2
@Daksh:基本的に、アクションが押されたときに開始される通知タグとIDをインテントに追加します。その追加情報を使用して、開始アクティビティで通知アクションによって開始されたかどうかを確認できます。
endowzoner

5
onCreate()からのコードサンプル:Bundle extras = getIntent()。getExtras(); if(extras!= null){String tag = extras.getString(NotificationReceiver.INTENT_EXTRA_NOTIFICATION_TAG); int id = extras.getInt(NotificationReceiver.INTENT_EXTRA_NOTIFICATION_ID); if(NotificationReceiver.NOTIFICATION_ID == id && NotificationReceiver.NOTIFICATION_TAG.equals(tag)){//アクティビティが通知アクションを介して開始された、却下//通知NotificationManagerマネージャ=(NotificationManager)getSystemService(Service.NOTIFICATION_SERVICE); manager.cancel(tag、id); }}
endowzoner 2012

1
新しいAPIでは、notify(文字列タグ、int id、通知通知)とそれに対応するcancel(文字列タグ、int id)
Malachiasz 2018年

64

Lollipopのヘッドアップディスプレイ通知を使用するときに、これが問題であることがわかりました。設計ガイドラインを見る。これが実装する完全な(ish)コードです。

これまでは、[閉じる]ボタンを使用することはそれほど重要ではありませんでしたが、今ではもっと重要です。

ヘッドアップ通知

通知の作成

int notificationId = new Random().nextInt(); // just use a counter in some util class...
PendingIntent dismissIntent = NotificationActivity.getDismissIntent(notificationId, context);

NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setPriority(NotificationCompat.PRIORITY_MAX) //HIGH, MAX, FULL_SCREEN and setDefaults(Notification.DEFAULT_ALL) will make it a Heads Up Display Style
        .setDefaults(Notification.DEFAULT_ALL) // also requires VIBRATE permission
        .setSmallIcon(R.drawable.ic_action_refresh) // Required!
        .setContentTitle("Message from test")
        .setContentText("message")
        .setAutoCancel(true)
        .addAction(R.drawable.ic_action_cancel, "Dismiss", dismissIntent)
        .addAction(R.drawable.ic_action_boom, "Action!", someOtherPendingIntent);

// Gets an instance of the NotificationManager service
NotificationManager notifyMgr = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

// Builds the notification and issues it.
notifyMgr.notify(notificationId, builder.build());

NotificationActivity

public class NotificationActivity extends Activity {

    public static final String NOTIFICATION_ID = "NOTIFICATION_ID";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        manager.cancel(getIntent().getIntExtra(NOTIFICATION_ID, -1));
        finish(); // since finish() is called in onCreate(), onDestroy() will be called immediately
    }

    public static PendingIntent getDismissIntent(int notificationId, Context context) {
        Intent intent = new Intent(context, NotificationActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        intent.putExtra(NOTIFICATION_ID, notificationId);
        PendingIntent dismissIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        return dismissIntent;
    }

}

AndroidManifest.xml(SystemUIがバックスタックにフォーカスしないようにするために必要な属性)

<activity
    android:name=".NotificationActivity"
    android:taskAffinity=""
    android:excludeFromRecents="true">
</activity>

1つのアプリケーションから複数の通知があり、通知は進行中の通知に設定されています。特定の通知でaddactionが実行されたときに通知をクリアしたい
プラサード

3
代わりにBroadcastReceiverを使用して通知を却下する方が効果的ではないでしょうか?ここではその番組の実装良い例ですが、それはさらに低減することができます。stackoverflow.com/a/19745745/793150
alice.harrison

1
エキストラセットがインテントとともに転送されることを除いて、ソリューションは機能します。それらはonCreateに転送されません。1つの方法は、静的変数を使用することです。インテントエキストラが転送されないのはなぜですか?
バスキ2016

getDismissIntentがNotificationActivityに配置された場合にのみ機能するのはなぜですか?PendingIntent作成コードが通知ビルダークラスに配置されている場合、Distent Intentは機能しません。私はこの問題に2時間費やしましたが、アクティビティで保留インテントを作成する必要がある理由を理解できません。なぜこれが事実であるか誰でも説明できますか?
Ray Li

getDismissIntent()は、NotificationActivityとの通信に使用する正しいインテントを構築する静的な「ヘルパー」関数です。そのため、これらは通常、アクティビティにバンドルされています。しかし、NOTIFICATION_IDとコンテキストを正しく設定するように注意している限り、この静的関数を通知ビルダークラスに配置できなかった理由はわかりません。
マイク

17

拡張通知でアクションボタンを使用する場合、追加のコードを記述する必要があり、制約が多いことがわかりました。

ユーザーがアクションボタンをクリックしたときに、手動で通知をキャンセルする必要があります。通知は、デフォルトのアクションでのみ自動的にキャンセルされます。

また、ボタンから放送受信機を起動しても、通知ドロワーは閉じません。

これらの問題に対処するために、新しいNotificationActivityを作成することになりました。UIのない​​この中間アクティビティは通知をキャンセルし、通知から開始したいアクティビティを開始します。

関連する投稿にサンプルコードを投稿しましたAndroid通知アクションをクリックしても通知ドロワーが閉じません


2
残念ながら、まだAPIに組み込まれていません...このようにするのはかなりハックです。しかし、それでも唯一の方法です。特に、URLの表示など、宛先インテントを制御できない場合はなおさらです。
ボグダンズラック

情報をありがとう、あなたは正しいです。ただし、中間のアクティビティではなくインテントサービスを使用します
Tim

7

あなたは、常にすることができますから(で、例えば作用によって呼び出されているものは何でもに縛ら活動のあなたがへの供給します)。cancel()NotificationonCreate()PendingIntentaddAction()


2
しかし、呼び出されたアクティビティで通知にアクセスするにはどうすればよいですか?
endowzoner 2012

@FleshWound:cancel()を呼び出しNotificationたときに使用したのIDを受け取りますnotify()Notificationオブジェクトは必要ありません。
CommonsWare 2012

setGroupが設定されていて、グループサマリー通知がある場合、@ CommonsWare cancel(id)は動作を停止しました。この場合、キャンセルは何らかの理由で何もしません。グループサマリーがなければ、キャンセルは正常に機能します
Kushan 2017

私の保留中の意図がACTION_VIEWあり、タイプがimage/jpeg(別のアプリと画像を共有するため)である場合、そのキャンセルはどのようにトリガーされるはずですか?IMO Androidは自動キャンセルする必要があります。Androidがそれを処理しないのはなぜですか?
誰かどこかの

@SomeoneSomewhere:「それでは、そのキャンセルはどのようにトリガーされるはずですか?」-できません。でサードパーティのアプリをNotificationポイントすることを妨げるものは何もありませPendingIntentんが、それが実際に機能するように設計されているわけではないため、このような問題が発生します。「IMO Androidは自動キャンセルする必要があります」-アクションでそのためのフラグを提供しているのを見たかもしれませんが、それはいつものことではありません。その場合、音楽プレーヤー通知のトラックをスキップすると、通知が閉じます。
CommonsWare

7

私の意見では、 BroadcastReceiverは、と通知をキャンセルするためのよりクリーンな方法です:

AndroidManifest.xmlで:

<receiver 
    android:name=.NotificationCancelReceiver" >
    <intent-filter android:priority="999" >
         <action android:name="com.example.cancel" />
    </intent-filter>
</receiver>

Javaファイル:

Intent cancel = new Intent("com.example.cancel");
PendingIntent cancelP = PendingIntent.getBroadcast(context, 0, cancel, PendingIntent.FLAG_CANCEL_CURRENT);

NotificationCompat.Action actions[] = new NotificationCompat.Action[1];

NotificationCancelReceiver

public class NotificationCancelReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //Cancel your ongoing Notification
    };
}

1
それが私がすることですが、onReceiveメソッドから通知ID(この例では0)をどのように取得しますか?追加されていないので、インテントにはありません。追加として追加しようとしましたが、実際の通知IDは作成アクティビティで追加として追加したものではないようです...:-/
Marco Zanetti

アクティビティの代わりにブロードキャストサービスを使用するこのアプローチは本当に気に入っています。
Christophe Moine 2017年

ただし、表示されている通知をすべて閉じるには、アディションで<intent.setAction(Integer.toString(notificationId));>を使用する必要がありました。
Christophe Moine 2017年

1
@MarcoZanettiでは、保留中のインテントに渡す通知IDを生成する必要があり、通知の送信時にnotifyメソッドにも渡す必要があります。その場合、ユーザーがアクションをクリックしてキャンセルすると、ブロードキャストレシーバーが呼び出され、エクストラから通知IDを取得できます。
レイハンター

@ChristopheMoineはidを入力intent.putExtra()して取得できますBroadcastReceiver
Vadim Kotov

5

新しいAPIでは、TAGを忘れないでください。

notify(String tag, int id, Notification notification)

それに応じて

cancel(String tag, int id) 

の代わりに:

cancel(int id)

https://developer.android.com/reference/android/app/NotificationManager


あなたは正しかった!がcancel()関数は2つの実装を有します。1つはタグ付き、もう1つはタグなしです。しかし、我々は提供する必要がありTAGます。これがcanceldocsの関数public void cancel(@Nullable String tag, int id)です。Android Qで最後にチェック
sud007

1

この行を入れてください:

 builder.setAutoCancel(true);

そして完全なコードは:

NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
    builder.setSmallIcon(android.R.drawable.ic_dialog_alert);
    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.co.in/"));
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
    builder.setContentIntent(pendingIntent);
    builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.misti_ic));
    builder.setContentTitle("Notifications Title");
    builder.setContentText("Your notification content here.");
    builder.setSubText("Tap to view the website.");
    Toast.makeText(getApplicationContext(), "The notification has been created!!", Toast.LENGTH_LONG).show();

    NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    builder.setAutoCancel(true);
    // Will display the notification in the notification bar
    notificationManager.notify(1, builder.build());

AutoCancelは、Android 9をターゲットにすると効果がないようです(Android 8.1をターゲットにするとうまくいきました)
Alix

ここでの違いはアクションのものです
誰か誰か

0

通知を削除するには、インテントが発生した後に次のコードを実行する必要があります。

NotificationManagerCompat.from(this).cancel(null, notificationId);

注意:notificationIdは、通知を実行するために渡されるIDと同じです


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.