【问题标题】:FCM Push Notification with Action Button Not Working带有操作按钮的 FCM 推送通知不起作用
【发布时间】:2019-05-28 10:10:32
【问题描述】:

我开发了一个 Android 应用程序,用户可以在其中接收地震信息。如果用户的设备的位置靠近地震位置,则通知将有 2 个按钮来确认他们是否安全或从发生的地震中撤离。当用户按下通知中的 2 个按钮中的 1 个(安全或撤离)时,我陷入了一个进程。

这是我的代码:

MyFirebaseInstanceService.java

private void showNotification(String title, String body) {
    NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    String NOTIFICATION_CHANNEL_ID = "com.example.yohan.notifgempafcm";

    Intent amanIntent = setIntent(body, "SAFE");
    Intent evakuasiIntent = setIntent(body, "EVACUATED");

    PendingIntent pendingIntentAman = PendingIntent.getBroadcast(this, 0, amanIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    PendingIntent pendingIntentEvakuasi = PendingIntent.getActivity(this, 1, evakuasiIntent, PendingIntent.FLAG_UPDATE_CURRENT);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "Notification",
                NotificationManager.IMPORTANCE_DEFAULT);
        notificationChannel.enableLights(true);
        notificationChannel.setDescription("Info Gempa");
        notificationChannel.setLightColor(Color.BLUE);
        if (title.contains("WASPADA GEMPA")) {
            notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
        }
        notificationManager.createNotificationChannel(notificationChannel);
    }

    NotificationCompat.Action actAman = new NotificationCompat.Action.Builder(android.R.drawable.ic_secure, "AMAN", pendingIntentAman).build();
    NotificationCompat.Action actEvakuasi = new NotificationCompat.Action.Builder(android.R.drawable.ic_partial_secure, "EVAKUASI", pendingIntentEvakuasi).build();

    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
    notificationBuilder.setAutoCancel(true)
            .setSmallIcon(R.drawable.ic_notification)
            .setContentTitle(title)
            .setContentText(body)
            .setContentInfo("Info");
    if (title.contains("WASPADA GEMPA")) {
        notificationBuilder.addAction(actAman);
        notificationBuilder.addAction(actEvakuasi);
    }
    final Notification notification = notificationBuilder.build();
    notificationManager.notify(11111, notification);
}

public Intent setIntent(String body, String status){
    Intent intent = new Intent(this, NotificationActionReceiver.class);
    intent.putExtra("tanggal", (body.split(" ")[2] + " " + body.split(" ")[3]));
    intent.putExtra("token", token);
    intent.putExtra("status", status);
    return intent;
}

NotificationActionReceiver.java

public class NotificationActionReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String tanggal = intent.getStringExtra("tanggal");
        String token = intent.getStringExtra("token");
        String status = intent.getStringExtra("status");
        konfirmasi(context, tanggal, token, status);
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.cancel(11111);
    }

    public void konfirmasi(final Context context, String tanggal, String token, String status){
        HashMap<String, String> data = pushData(tanggal, token, status);
        PostResponseAsyncTask konfirm = new PostResponseAsyncTask(context, data, new AsyncResponse() {
            @Override
            public void processFinish(String s) {
                if (s.equals("UPDATED")){
                    Toast.makeText(context, "Konfirmasi berhasil disimpan", Toast.LENGTH_SHORT).show();
                }
            }
        });
        konfirm.execute(LoginActivity.URL + "notifikasi/changeStatus");
    }

    public HashMap<String, String> pushData(String tanggal, String token, String status){
        HashMap<String, String> data = new HashMap<>();
        data.put("datetime", tanggal);
        data.put("token", token);
        data.put("konfirmasi", status);
        return data;
    }
}

我希望(示例)如果用户在通知中按下SAFE 按钮,它将确保用户的确认状态从NOTIFIED(默认)到数据库服务器中的SAFE,依此类推。但它返回一个错误:

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.yohan.notifgempafcm, PID: 3821
    java.lang.RuntimeException: Unable to start receiver com.example.yohan.notifgempafcm.NotificationActionReceiver: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
        at android.app.ActivityThread.handleReceiver(ActivityThread.java:2621)
        at android.app.ActivityThread.access$1700(ActivityThread.java:153)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1382)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5293)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
     Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
        at android.view.ViewRootImpl.setView(ViewRootImpl.java:569)
        at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:282)
        at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:85)
        at android.app.Dialog.show(Dialog.java:298)
        at com.kosalgeek.genasync12.PostResponseAsyncTask.onPreExecute(PostResponseAsyncTask.java:151)
        at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:591)
        at android.os.AsyncTask.execute(AsyncTask.java:539)
        at com.example.yohan.notifgempafcm.NotificationActionReceiver.konfirmasi(NotificationActionReceiver.java:36)
        at com.example.yohan.notifgempafcm.NotificationActionReceiver.onReceive(NotificationActionReceiver.java:21)
        at android.app.ActivityThread.handleReceiver(ActivityThread.java:2614)
        at android.app.ActivityThread.access$1700(ActivityThread.java:153) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1382) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:135) 
        at android.app.ActivityThread.main(ActivityThread.java:5293) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at java.lang.reflect.Method.invoke(Method.java:372) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698) 

有什么办法吗?

【问题讨论】:

    标签: android firebase firebase-cloud-messaging


    【解决方案1】:

    在这种情况下容易出错的代码是

      Toast.makeText(context, "Konfirmasi berhasil disimpan", Toast.LENGTH_SHORT).show();
    

    BroadcastReceiver 最多允许运行 10 秒。如果您在它之后访问上下文,它将是无效的(这是您的情况)。此外,如果这是当时 Process 中唯一的东西,那么这个 Process 将被杀死,它不会关心你的 API 是否被调用。所以你不应该直接在#onReceive() 内部进行长时间运行的操作。
    Documentation

    要使用您的代码解决此问题,您可以使用goAsync()。这将在从该函数返回后保持广播活动。使用前请阅读#goAsync().

    Here is an example of goAsync().

    的文档 要做到这一点更优雅,您可以启动一个IntentService,它会自动处理后台线程中的 API 调用。

    【讨论】:

    • 我只是更改了 NotificationActionReceiver.java 中现在扩展 Activity 的代码。它工作得很好,只需一个,确认状态将保存到数据库而不打开意图。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-18
    • 2020-10-14
    • 1970-01-01
    • 1970-01-01
    • 2020-06-30
    • 2021-10-22
    • 1970-01-01
    相关资源
    最近更新 更多