在Android通知中处理按钮

16

我在通知中添加了一个按钮

但是我不知道如何在点击按钮时调用函数。

我尝试了这样的方法https://code.google.com/p/languagepickerwidget/source/browse/trunk/trunk/src/org/gnvo/langpicker/LangPicker.java,因为它也使用RemoteViews对象,但是当我点击按钮时什么也没发生。

这就是我目前拥有的:

private void createNotification(){
    String ns = Context.NOTIFICATION_SERVICE;
    NotificationManager notificationManager = (NotificationManager) getSystemService(ns);

    Notification notification = new Notification(R.drawable.ic_launcher, null, System.currentTimeMillis());
    RemoteViews notificationView = new RemoteViews(getPackageName(), R.layout.notification_switch);

    //the intent that is started when the notification is clicked (works)
    Intent notificationIntent = new Intent(this, SettingsActivity.class);
    PendingIntent pendingNotificationIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

    notification.contentView = notificationView;
    notification.contentIntent = pendingNotificationIntent;
    notification.flags |= Notification.FLAG_NO_CLEAR;

    //this is the intent that is supposed to be called when the button is clicked
    Intent switchIntent = new Intent(this, switchButtonListener.class);
    PendingIntent pendingSwitchIntent = PendingIntent.getBroadcast(this, 0, switchIntent, 0);

    notificationView.setOnClickPendingIntent(R.id.buttonswitch, pendingSwitchIntent);

    notificationManager.notify(1, notification);
}

public static class switchButtonListener extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("TAG", "test");
    }

}

我可以使用按钮启动一个 Activity,但我没有成功调用一个简单的函数。最好的方法是什么?

编辑: 我发现我需要在 AndroidManifest.xml 中注册 "switchButtonListener"。

<receiver android:name="SettingsActivity$switchButtonListener" />

来源:Android Activity with no GUI

现在它可以工作了。


你应该将 EDIT 部分的内容发布为答案,这样如果有人正在寻找你的问题的答案,他们可以更容易地找到它。同时欢迎来到stackoverflow! :) - Jordan Richards
1
如果我没记错的话,当我尝试发布一个答案时,我收到了一条消息,说在6个小时内我不能回答自己的问题。 - A E
3个回答

33

我发现我需要在AndroidManifest.xml中注册"switchButtonListener"

<receiver android:name="SettingsActivity$switchButtonListener" />

来源: Android中没有GUI的Activity


后来我发现,我也可以使用如下代码来实现相同的功能,而不必修改清单文件。

switchButtonListener = new SwitchButtonListener();
registerReceiver(switchButtonListener, new IntentFilter(SWITCH_EVENT));

.

public class switchButtonListener extends BroadcastReceiver {
@Override
    public void onReceive(Context context, Intent intent) {
        Log.d("TAG", "test");
    }

}

.

Intent switchIntent = new Intent(LangService.SWITCH_EVENT);
PendingIntent pendingSwitchIntent = PendingIntent.getBroadcast(context, 0, switchIntent, 0);

notificationView.setOnClickPendingIntent(R.id.buttonswitch, pendingSwitchIntent);
注意,这样我可以声明switchButtonListener类而不使用静态属性(如果不使用静态属性,在先前的示例中会崩溃),从而给我带来更多的灵活性。别忘了稍后调用unregisterReceiver()。

0
在 Kotlin 中,您可以使用匿名类注册接收器。
const val STOP_ALARM_ACTION = "STOP_ALARM"

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        // ...
        registerReceiver(object : BroadcastReceiver() {
            override fun onReceive(p0: Context?, p1: Intent?) {
                stopAlarm();
            }
        }, IntentFilter(STOP_ALARM_ACTION))
    }
    private fun playAlarm() {
        ringtone.stop()
        val stopIntent = Intent(STOP_ALARM_ACTION)
        val stopPendingIntent = PendingIntent.getBroadcast(this, 0, stopIntent, 0)
        val notification = NotificationCompat.Builder(this, "Timer1_ALARM")
                // ...
                .addAction(android.R.drawable.ic_delete, "Stop", stopPendingIntent)
                .build()
        // ...
    }
    private fun stopAlarm() {
        ringtone.stop()
    }
}

0

我相信取消注册操作同样很重要,所以我写的方式如下:

val playButtonAction = register("play_button_action") {
    main.looper?.player?.asStarted { it.stop() }
}

所以你可以这样做:

override fun onDestroy() {
    super.onDestroy()
    unregister(playButtonAction)
}

使用:

fun Context.register(action: String, function: () -> void): BroadcastReceiver =
    register(IntentFilter(action)) { _, _ -> function() }

fun Context.register(intent: IntentFilter,
                     function: (Intent, BroadcastReceiver) -> void): BroadcastReceiver {
    val receiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) = function(intent, this)
    }
    registerReceiver(receiver, intent)
    return receiver
}

fun Context.unregister(receiver: BroadcastReceiver) {
    unregisterReceiver(receiver)
}

并且您可以使用playButtonAction:

val stopIntent = PendingIntent.getBroadcast(this, 0, Intent("play_button_action"),
            FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE);

这是我的完整服务类:

class LooperPlayNotificationService : Service() {

    companion object {
        val NOTIFICATIONS_CHANNEL = "${app.packageName} notifications"
    }

    override fun onBind(intent: Intent): IBinder? = null

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        super.onStartCommand(intent, flags, startId)
        start()
        return START_STICKY
    }

    override fun onCreate() {
        super.onCreate()
        start()
    }

    private val playButtonActionId = "play_button_action"
    private lateinit var playButtonAction: BroadcastReceiver
    private var started = false

    // https://dev59.com/NFnUa4cB1Zd3GeqPWgbQ
    // There's a bug in 2.3 (not sure if it was fixed yet) where when a Service is killed and restarted,
    // its onStartCommand() will NOT be called again. Instead you're going to have to do any setting up in onCreate()
    private fun start() {
        if (started) return
        started = true
        startForeground(647823876, createNotification())
        playButtonAction = register(playButtonActionId) {
            main.looper?.player?.asStarted { it.stop() }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        unregister(this.playButtonAction)
    }

private fun createNotification() = Builder(this, NOTIFICATIONS_CHANNEL)
    .setSmallIcon(outline_all_inclusive_24)
    .setContentIntent(getActivity(this, 0, Intent<InstrumentsActivity>(this),
        FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE))
    .setPriority(PRIORITY_DEFAULT)
    .setAutoCancel(false).setOngoing(true)
    .addAction(ic_stop_circle_black_24dp, "Stop",
        getBroadcast(this, 0, Intent(playButtonActionId),
            FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE))
    .setContentText(getString(R.string.app_name))
    .setContentText(main.looper?.preset?.item?.value?.title?.value).build()
}

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