【问题标题】:Restart scheduled notifications (that require Firebase data) after device reboot设备重启后重启预定通知(需要 Firebase 数据)
【发布时间】:2018-10-05 10:14:29
【问题描述】:

我的应用目前会在特定时间(由用户选择)安排任务通知。任务的标题和提醒日期保存在 Firebase 实时数据库中。

关键是,当设备重新启动时,所有这些都会丢失。所以需要重新启动过去安排的所有相关通知。

因此,我有一个可以获取 BOOT_COMPLETED 意图的 BroadcastReceiver。 但是,我无法访问 Firebase DB,因为当前没有用户登录 - 而且我也无法启动 Firebase 身份验证(无法识别 startActivityForResult 并且导入它会导致更多错误)。我认为这是因为 BroadcastReceiver 不是一个活动。

我想知道是否有办法解决这个问题。 我目前尝试设置一个意图来启动 MainActivity(用户通过身份验证的地方),然后执行我的相关任务,但是没有奏效。

我想知道是否有办法解决这个问题,获取经过身份验证的用户(或在设备重启时对其进行身份验证),然后从 Firebase 获取数据。

AlarmReceiver 代码(扩展 BroadcastReceiver) - 有点乱,但它有助于获取上下文。

public class AlarmReceiver extends BroadcastReceiver  {

private ChildEventListener mChildEventListener;
private FirebaseDatabase mFirebaseDatabase;
private DatabaseReference mTaskDatabaseReference;
private FirebaseAuth mFirebaseAuth;
private FirebaseAuth.AuthStateListener mAuthStateListener;
private int i;

@Override
public void onReceive(final Context context, Intent intent) {
    mFirebaseDatabase = FirebaseDatabase.getInstance();
    mFirebaseAuth = FirebaseAuth.getInstance();

    if (intent.getAction() != null && context != null) {
        if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
            TaskInfoFragment.showReminderNotification(context, MainActivity.class, "hoooo",1000);
            onSignedOutCleanup(context);
            mTaskDatabaseReference=mFirebaseDatabase.getReference().child("users").child(MainActivity.getCurrentUserId());
            attachDatabaseReadListener(context);
            //TODO - HANDLE DEVICE REBOOT

        }
    }


    //Trigger the notification
    Bundle extras = intent.getExtras();
    String taskTitle = "Error, no task title!";
    int taskIntId=-1;
    if (extras != null) {
        taskTitle = extras.getString("taskTitle");
        taskIntId=extras.getInt("taskIntId");
    }

    TaskInfoFragment.showReminderNotification(context, MainActivity.class, taskTitle,taskIntId);

}

private void attachDatabaseReadListener(final Context context) {
      i=0;

        mChildEventListener = new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                i++;
                TaskList task = dataSnapshot.getValue(TaskList.class);
                TaskInfoFragment.showReminderNotification(context, MainActivity.class, task.getTitle(),i);
                Log.d("here is another task","title: "+task.getTitle());
            }
            public void onChildChanged(DataSnapshot dataSnapshot, String s) {}
            public void onChildRemoved(DataSnapshot dataSnapshot) {
            }
            public void onChildMoved(DataSnapshot dataSnapshot, String s) {}
            public void onCancelled(DatabaseError databaseError) {}
        };

        mTaskDatabaseReference.addChildEventListener(mChildEventListener);

}

private void onSignedInInitialize(final String userId,Context context) {

    //Get reference for the task list for the logged in user and attach the database listener
    mTaskDatabaseReference=mFirebaseDatabase.getReference().child("users").child(userId);
    attachDatabaseReadListener(context);

}

private void onSignedOutCleanup(Context context) {
    Intent taskIntent = new Intent(context,MainActivity.class);

    // Send the intent to launch a new activity
    context.startActivity(taskIntent);
}

private void detachDatabaseReadListener() {
    if (mChildEventListener != null) {
        mTaskDatabaseReference.removeEventListener(mChildEventListener);
        mChildEventListener = null;
    }
}

【问题讨论】:

  • 签出this
  • 你能拿到设备令牌吗?如果是,那么也许您可以使用设备令牌将 http post 请求发送到云功能以发出重启信号。然后服务器将data only 消息发送到应用程序以重新安排警报。您甚至可以将设备令牌存储在您的应用设置包中,以避免接收器中的火力。
  • @AlexMamo James Poag 我已经研究了这些问题,似乎将 userId 保存在 SharedPreferences 中是解决手头问题的最简单的方法,因为这些通知是特定于用户的,目前正在获取用户已登录(或以前未注销的登录)证明就足够了。谢谢你们!

标签: android firebase firebase-realtime-database android-notifications android-broadcastreceiver


【解决方案1】:

如果您想在用户登录之前显示这些通知,那么显然它们并不意味着与用户相关联。我会将它们与另一个值相关联,可能是一个标识设备的值。 James 评论的InstanceIdToken 可能是一个很好的解决方案,因为它可以识别特定设备上的特定应用程序。

但也请务必查看 Firebase Cloud Messaging,它允许您在设备启动后立即向设备发送通知。由于 FCM 消息由 Google Play 服务中的接收器处理,因此与尝试从您自己的接收器中的远程数据库加载它们相比,这通常是传递此类消息的更可靠的方式。

并非巧合:FCM 依赖于实例 ID 令牌来识别设备/应用程序来传递消息。

【讨论】:

  • 感谢弗兰克的提示!我研究了 Firebase Cloud Messaging,它看起来真的很有帮助,但它似乎与公告类型通知更相关。我正在开发的应用程序是一个简单的待办事项列表,使用户能够选择特定任务并安排提醒。如果我理解正确,FCM 不允许的东西。但出于本次讨论的目的,将 Firebase userId 保存在 SharedPreferences 中就可以了。
  • 正确。这听起来更像是本地警报。在这种情况下,我建议为 Firebase 实时数据库启用磁盘持久性,这样您就可以在不连接服务器的情况下加载数据。对于有登录用户,我不知道如何解决这个问题。也许将警报列表保留在持久存储中?
  • 是的,我确实启用了磁盘持久性,但事实证明它非常有用。让登录用户的解决方法是使用 SharedPreferences。每次对用户进行身份验证(为了从数据库访问他的特定数据)时,他的用户 ID 都会被保存。所以当设备重启时,可以恢复特定于他的警报。
  • 酷。这听起来确实像我希望的那样。我实际上不确定onAuthStateChanged 是否会在BroadcastReceiver 中触发。绝对值得一试。
【解决方案2】:

总之,我使用 SharedPreferences 保存了当前登录的用户。 (之所以有效,是因为通知与用户相关,因此我们可以放心地假设最后登录的用户是相关用户)。

然后我更改了我的 Firebase 数据库树,以允许我使用当前登录的用户 ID 访问任务。多一点编码和错误修复就可以了。

感谢大家的帮助!

【讨论】:

    猜你喜欢
    • 2015-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-06
    • 1970-01-01
    • 1970-01-01
    • 2023-01-04
    相关资源
    最近更新 更多