安卓通知带有按钮

19

我想制作一个带有2个按钮的通知:

  • 一个按钮可以让我返回到Activity
  • 另一个按钮可以关闭通知

有没有人知道如何捕获按钮的点击事件(请记住,Activity已被暂停)?


说实话,我不喜欢你的努力背后的想法,或者我不理解它。在安卓中,普通的通知右侧有一个X,如果你点击它们,你会被重定向到活动页面。 - user61664
我们教他们并向他们展示Android开发者指南 ;) - Martin Marconcini
6个回答

44

我很高兴能够发布它!经过整夜的工作,我找到了一些东西。所以,让我们开始吧!

1. 为你的通知创建一个xml布局文件。

2. 使用Notification.Builder创建通知。在添加所有你想要的内容(图标、声音等)之后,执行以下操作:

        //R.layout.notification_layout is from step 1

        RemoteViews contentView=new RemoteViews(ctx.getPackageName(), R.layout.notification_layout);

        setListeners(contentView);//look at step 3

        notification.contentView = contentView;

3. 创建一个名为setListeners的方法。在这个方法内部,你需要编写以下内容:

    //HelperActivity will be shown at step 4

    Intent radio=new Intent(ctx, packagename.youractivity.class);  
    radio.putExtra("AN_ACTION", "do");//if necessary

    PendingIntent pRadio = PendingIntent.getActivity(ctx, 0, radio, 0);
    //R.id.radio is a button from the layout which is created at step 2  view.setOnClickPendingIntent(R.id.radio, pRadio); 

    //Follows exactly my code!
    Intent volume=new Intent(ctx, tsapalos11598712.bill3050.shortcuts.helper.HelperActivity.class);
    volume.putExtra("DO", "volume");</p>

    //HERE is the whole trick. Look at pVolume. I used 1 instead of 0.
    PendingIntent pVolume = PendingIntent.getActivity(ctx, 1, volume, 0);
    view.setOnClickPendingIntent(R.id.volume, pVolume);

4. 对于我的需求,我使用了一个HelperActivity来响应意图。但对于你来说,我认为这并不是必要的。

如果你想要完整的源代码,你可以从我的git仓库浏览或下载。该代码仅供个人使用,所以不要期望看到有很多注释的漂亮代码。 https://github.com/BILLyTheLiTTle/AndroidProject_Shortcuts

以上回答了从不同按钮捕捉事件的问题。

关于取消通知,我把你引导到这里:

如何在Android中清除通知

只需要记住在第一次调用通知时使用你解析的id即可。


8
这在ICS 4.0.4上运行得非常出色!您应该考虑正确格式化您的答案,以便其他用户可以仔细查看您的答案。 - Vikram Gupta
8
你是正确的。我一开始就应该这样做。希望现在更好了。因为你的评论,我添加了下载源代码的链接。从现在开始,所有读者都应该感谢你而不是我。祝你度过一个美好的年末和最快乐的新年。 - LiTTle
1
太好了!新年快乐!! - Vikram Gupta

5

这里有一个完整的例子供您参考

    //Add this code to onCreate or some onclick Buttton
    NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext());
    long when = System.currentTimeMillis();
    builder.setSmallIcon(R.drawable.ic_notification);
    Intent notificationIntent = new Intent(getApplicationContext(), notificationActivity.class).putExtra("notification", "1");
    PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 1, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    builder.setContentIntent(contentIntent);
    Notification notification = builder.getNotification();
    notification.when = when;

    RemoteViews remoteViews = new RemoteViews(getApplicationContext().getPackageName(), R.layout.notification_view);
    remoteViews.setTextViewText(R.id.tvName, "New Name");
    listener(remoteViews,getApplicationContext());


    notification.contentView = remoteViews;
    notification.flags |= Notification.FLAG_AUTO_CANCEL;
    manager.notify(1, notification);

然后您可以定义监听器方法:

    public void listener(RemoteViews remoteViews, Context context) {
    // you have to make intetns for each action (your Buttons)
    Intent intent = new Intent("Accept");
    Intent intent2 = new Intent("Reject");

    PendingIntent pendingIntent = PendingIntent.getBroadcast(context,1,intent,0);
    PendingIntent pendingIntent2 = PendingIntent.getBroadcast(context,1,intent2,0);

    // add actions here !
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction("Accept");
    intentFilter.addAction("Reject");


    BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if(intent.getAction().equals("Accept")){
                Toast.makeText(context, "Accepted !!", Toast.LENGTH_SHORT).show();
            } else if(intent.getAction().equals("Reject")) {
                Toast.makeText(context, "Rejected !!", Toast.LENGTH_SHORT).show();
            }
        }
    };

    context.registerReceiver(receiver,intentFilter);
    remoteViews.setOnClickPendingIntent(R.id.ivRequest,pendingIntent);
    remoteViews.setOnClickPendingIntent(R.id.ivReject,pendingIntent2);

}

这里是notification_view布局,可以自定义您的通知。

    <?xml version="1.0" encoding="utf-8"?>
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="16dp">

<TextView
    android:id="@+id/textView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerVertical="true"
    android:text="Request from "
    />

<TextView
    android:id="@+id/tvName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerVertical="true"
    android:layout_marginStart="15dp"
    android:layout_toRightOf="@id/textView"
    android:text="Amin"
    />

<ImageView
    android:id="@+id/ivRequest"
    android:layout_width="30dp"
    android:layout_height="30dp"
    android:layout_alignParentEnd="true"
    android:layout_centerVertical="true"
    android:src="@drawable/notification"
    />

<ImageView
    android:id="@+id/ivReject"
    android:layout_width="30dp"
    android:layout_height="30dp"
    android:layout_marginEnd="10dp"
    android:layout_toLeftOf="@id/ivRequest"
    android:layout_centerVertical="true"
    android:src="@drawable/trash"
    />

  </RelativeLayout>

1
这个例子可以通过复制和粘贴来实现它所声称的功能(在添加可绘制对象后)。然而,builder.setCustomContentView(remoteViews);notification.contentView = remoteViews;更好,并且由于已经过时,builder.build()builder.getNotification()更好(你需要稍微调整一下代码以适应这些变化)。 - Gary99
是的,我从我的SimpleProject中复制了这段代码,谢谢你更新 :) - Amin

4

对于ICS系统,这个问题很容易回答,因为所需的行为反映了默认通知:您可以通过向右滑动关闭通知,并且您可以使用PendingIntent定义用户按下通知时要发送到哪个activity

// The PendingIntent to launch our activity if the user selects this
// notification.  Note the use of FLAG_CANCEL_CURRENT so that, if there
// is already an active matching pending intent, cancel it and replace
// it with the new array of Intents.
PendingIntent contentIntent = PendingIntent.getActivities(this, 0,
        makeMessageIntentStack(this, from, message), PendingIntent.FLAG_CANCEL_CURRENT);

以下代码源自 http://developer.android.com/guide/topics/ui/notifiers/notifications.html


谢谢你的回答,尽管它不是我问的问题。我想做的是一个带有2个按钮的通知(已经有了布局),但是我在捕捉onClick事件时遇到了问题,我希望其中一个关闭活动(ACTIVITY),另一个执行通知的默认操作。 - doronsl

3

如果您想将特定意图分配给按钮:

views.setOnClickPendingIntent(R.id.your_button_id, pendingIntent);

我猜你只需要在按钮点击时发送一个意图,所以你需要避免设置主要的通知意图。

notification.contentIntent = yourPendingIntent;

否则(如果您像往常一样设置“notification.contentIntent = pendingIntent;”),两个意图都将被调用,这可能不是您想要或用户期望的。
如果您仍然希望按下通知的其他部分调用通用意图(或任何其他意图),则可以使用上面介绍的每个视图分配一个意图的方法。不要忘记设置。
android:clickable="true"

您可以跟踪任何您想要通过onClick()追踪的视图。

您可以通过它们在调用它们的活动中的extras来跟踪这些意图。 如果 您正在调用主/启动器活动,那么您将在此处跟踪它们(因为它来自此方法的javadoc):

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    Bundle data = intent.getExtras();

    if (data != null && data.containsKey(YOUR_INTENT_KEY_SOURCE_CONSTANT)) {
       // process your notification intent
    }

    // go on with smth else
}

3

您可以通过在Notification.Builder中设置操作并为每个操作定义PendingIntent,来简单地在您的Notification中添加操作按钮。

以下是示例代码:

    NotificationCompat.Builder mBuilder =
                new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.notification_icon)
                .setContentTitle("My notification")
                .setContentText("Hello World!")
       .addAction(R.drawable.action_posetive,"posetive",PendingIntent.getActivity(0,intent,0))
.addAction(R.drawable.action_clear,"clear",PendingIntent.getActivity(0,intent,0));
        NotificationManager mNotificationManager =
            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        mNotificationManager.notify(0, mBuilder.build());

0

对我来说,这个工作得非常好。 我将写下整个示例。 这是用于创建通知的

public void createNotification2(String aMessage) {
    final int NOTIFY_ID = 11;
    String name = getString(R.string.app_name);
    String id = getString(R.string.app_name); // The user-visible name of the channel.
    String description = getString(R.string.app_name); // The user-visible description of the channel.
    NotificationCompat.Builder builder;
    if (notifManager == null) {
        notifManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
    }
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        int importance = NotificationManager.IMPORTANCE_HIGH;
        NotificationChannel mChannel = notifManager.getNotificationChannel(id);
        if (mChannel == null) {
            mChannel = new NotificationChannel(id, name, importance);
            mChannel.setDescription(description);
            mChannel.enableVibration(true);
            mChannel.setLightColor(getColor(R.color.colorPrimaryDark));
            mChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
            notifManager.createNotificationChannel(mChannel);
        }
    } else {

    }
    Intent Off_broadcastIntent = new Intent(this, Database_Update.class);
    Off_broadcastIntent.setAction("on");
    Off_broadcastIntent.putExtra("toastMessage", "1");
    PendingIntent Off_actionIntent = PendingIntent.getService(this, 0, Off_broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT);

    Intent on_broadcastIntent = new Intent(this, Database_Update.class);
    on_broadcastIntent.setAction("off");
    on_broadcastIntent.putExtra("toastMessage", "0");
    PendingIntent on_actionIntent = PendingIntent.getService(this, 0, on_broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT);

    Intent cancel_broadcastIntent = new Intent(this, Database_Update.class);
    cancel_broadcastIntent.setAction("cancel");
    cancel_broadcastIntent.putExtra("toastMessage", "close");
    PendingIntent cancel_actionIntent = PendingIntent.getService(this, 0, cancel_broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT);

    Intent content_intent = new Intent(this, Status_Page.class);
    content_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, content_intent, PendingIntent.FLAG_UPDATE_CURRENT);


    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, id)
            .setSmallIcon(android.R.drawable.ic_popup_reminder)
            .setContentTitle(name)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setContentIntent(pendingIntent)
            .setAutoCancel(false)
            .setVibrate(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400})
            .addAction(R.drawable.block, "ON", Off_actionIntent)
            .addAction(R.drawable.notification, "OFF", on_actionIntent)
            .addAction(R.drawable.clear, "CLOSE", cancel_actionIntent);
    Notification notification = mBuilder.build();
    notification.flags = Notification.FLAG_NO_CLEAR|Notification.FLAG_ONGOING_EVENT;
    notifManager.notify(11, notification);
}

在 Android 清单文件中

<service android:name=".Database_Update"></service>

这是服务类

public class Database_Update extends Service {
String result="";

Realm realm;
BlockList blockList;
@Override
public void onCreate() {
    try {
        RealmConfiguration config = new RealmConfiguration.Builder()
                .name("notification.realm")
                .schemaVersion(1)
                .deleteRealmIfMigrationNeeded()
                .build();
        realm = Realm.getInstance(config);

    } catch (Exception e) {

        Log.d("Error Line Number", Log.getStackTraceString(e));
    }
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    //Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
    Log.d("SERVICE","SERVICE CHECKING");
    result=intent.getStringExtra("toastMessage");
    Log.d("SERVICE",result);
    if (realm!=null){
        Log.d("SERVICE","realm working");
    }else {
        Log.d("SERVICE","Realm not working");
    }
    blockList=realm.where(BlockList.class).equalTo("package_name", "BLOCK_ALL").findFirst();
    try {
        Log.d("SERVICE",blockList.getStatus());
    } catch (Exception e) {
        Log.d("Error Line Number", Log.getStackTraceString(e));
    }
    realm.beginTransaction();
    if (result.equals("1")){
        if (blockList==null){
            BlockList blockList_new=realm.createObject(BlockList.class);
            blockList_new.setPackage_name("BLOCK_ALL");
            blockList_new.setStatus("yes");
        }else {
            blockList.setStatus("yes");
        }
        Log.d("SERVICE","BLOCKING NOTIFICATION");
        Toast.makeText(this, "BLOCKING", Toast.LENGTH_SHORT).show();
    }else if (result.equals("0")){
        if (blockList==null){
            BlockList blockList_new=realm.createObject(BlockList.class);
            blockList_new.setPackage_name("BLOCK_ALL");
            blockList_new.setStatus("no");
        }else {
            blockList.setStatus("no");
        }
        Log.d("SERVICE","ALLOW NOTIFICATION");
        Toast.makeText(this, "ALLOW NOTIFICATION", Toast.LENGTH_SHORT).show();
    }else if (result.equals("close")){
        NotificationManager manager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
        manager.cancel(11);
        Log.d("SERVICE","REMOVING");
        Toast.makeText(this, "CLOSED", Toast.LENGTH_SHORT).show();
    }
    realm.commitTransaction();
    return START_STICKY;
}

@Override
public IBinder onBind(Intent intent) {
    // We don't provide binding, so return null
    return null;
}

@Override
public void onDestroy() {
    if (realm!=null){
        realm.close();
    }
    Toast.makeText(this, "REMOVING", Toast.LENGTH_SHORT).show();
}
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接