【问题标题】:How to send data to Firebase continuously avoiding Doze and App Standby如何连续向 Firebase 发送数据,避免 Doze 和 App Standby
【发布时间】:2020-08-24 07:53:42
【问题描述】:

我开发了这个应用程序,它需要在用户按下按钮时向 Firestore 发送数据,并在用户停止它时结束(通过按下另一个按钮)。即使用户正在做其他事情,或者即使用户让手机处于待机状态数小时,也必须发送数据(因此我需要避免打瞌睡和应用待机)。

我使用了一项服务来实现这一点,但似乎只有一件事以错误的方式工作。

服务

public class MyService extends Service {

    public static final String CHANNEL_ID = "ForegroundServiceChannel";

    // vars declaration

    private Date date = null;

    // get every X seconds 
    public static final long DEFAULT_SYNC_INTERVAL = 60000;

    private Runnable runnableService = new Runnable() {
        @Override
        public void run() {

            class GetDataTask extends AsyncTask<String, Void, List<Data>> {

                @Override
                protected void onPreExecute() {
                    super.onPreExecute();
                    if(getPositionData.isCancelled()){
                        return;
                    }
                }

                @SuppressLint({"MissingPermission", "HardwareIds"})
                @Override
                protected List<Data> doInBackground(String... v) {

                    // skipping get Timestamp code
                    

                    // skipping get position code
                    
                        myPos = new Data(position.getId(), latitude, longitude, timestamp);

                        // Insert data into Firebase
                        documentReference = firebaseFirestore.collection("data").document();
                        Map<String, Object> data = new HashMap<>();
                        data.put("lat", myPos.getLat());
                        data.put("date", myPos.getDate().toString());
                        documentReference.set(data).addOnSuccessListener(new OnSuccessListener<Void>() {
                            @Override
                            public void onSuccess(Void aVoid) {
                                Log.i("data", "data added.\n");
                            }
                        });

                        Toast.makeText(DataPollService.this, "" +
                                "ID: " + myPos.getImei()
                                        + " Latitude: " + myPos.getLat()
                                        + " Longitude " + myPos.getLng()
                                        + " Date: " + myPos.getDate()
                                , Toast.LENGTH_SHORT).show();
                                    }
                                }
                            }, Looper.getMainLooper());

                    positionsList.add(myPos);
                    return positionsList;
                }

                protected void onPostExecute(List<Data> result) {
                    Position.getInstance().setPositions(result);
                }
            }


            // RUN TASK
            getPositionData = new GetDataTask();
            getPositionData.execute(position.getId());

            handler.postDelayed(runnableService, DEFAULT_SYNC_INTERVAL);
        }
    };

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        String input = intent.getStringExtra("inputExtra");
        createNotificationChannel();
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,
                0, notificationIntent, 0);
        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("Foreground Service")
                .setContentText(input)
                .setSmallIcon(R.drawable.ksurf)
                .setContentIntent(pendingIntent)
                .build();
        startForeground(1, notification);

        handler = new Handler();
        handler.post(runnableService);

        return START_NOT_STICKY;
    }

    // onBind
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
        Log.d("show", "onDestroy");
        handler.removeCallbacks(runnableService);
        stopSelf();
    }

    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel serviceChannel = new NotificationChannel(
                    CHANNEL_ID,
                    "Foreground Service Channel",
                    NotificationManager.IMPORTANCE_DEFAULT
            );
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(serviceChannel);
        }
    }

}

在 MainActivity 中像这样启动服务:

Intent serviceIntent = new Intent(this, MyService.class);
serviceIntent.putExtra("inputExtra", "run");
ContextCompat.startForegroundService(this, serviceIntent);

如果我不使用手机并让应用在后台发送数据,则数据不会发送到 Firebase,直到我再次打开应用。服务没有停止,我只需要打开应用程序就可以将数据发送到 Firebase! 我阅读了有关 Firebase Cloud Messaging 的信息,但我不明白我是否需要它们来实现我的目的。我做错了什么?

【问题讨论】:

  • 如果上面的链接没有帮助,请详细说明您希望您的应用程序如何工作以及您的应用程序正在做什么阻止您实现这一目标。谢谢!
  • @sllopis 不,我在发布之前已经看过上面的这个链接,但它没有帮助。我希望我的应用程序做的是:1)用户按下开始按钮,从那一刻起,我从 GPS 获取他的位置 2)无论如何,这个位置每 2 秒存储到 Firebase 中,即使用户没有使用手机 2 小时 3) 当用户按下停止按钮时,服务停止,数据不再存储。就是这样。
  • 该用户的手机在这段时间内是否应该处于离线状态?如果是这样,请注意当您的设备处于离线状态时,可能不支持某些操作。这个documentation 解释了一些关于这个特性的信息。您的观察是准确的,Android 应用在连接到 Firebase 数据库时将保持其本地版本,一旦您的应用重新上线,该数据库将与当前服务器状态同步。
  • @sllopis 不,用户的手机可以在线!要理解我的意思,请考虑例如Telegram 的消息系统。如果您不使用电话,无论如何都会通知您有新消息。我也想这样做;即使用户不使用手机,他的位置也必须存储在 Firebase 中

标签: java android firebase google-cloud-firestore android-service


【解决方案1】:

即使用户正在做其他事情,或者即使用户让手机处于待机状态数小时,也必须发送数据(因此我需要避免打盹和应用待机)。

一般来说,让您的应用在打盹或应用待机模式下运行进程并不是一个好主意。 Android documentation 甚至指出网络访问被暂停;因此,您的进程可能无法保证可靠运行或终止于可能具有更高优先级的其他应用程序。

问题是,如果我在 1 小时内不使用应用程序(因此手机处于待机状态),则只有在我再次打开应用程序时才会添加 firebase 上的数据。就像它们被保存在缓存中并在再次打开应用时发送到数据库一样。

根据documentation“Cloud Firestore 支持离线数据持久化。此功能会缓存您的应用正在积极使用的 Cloud Firestore 数据的副本,以便您的应用可以在设备离线时访问数据. 您可以写入、读取、侦听和查询缓存的数据。当设备恢复在线时,Cloud Firestore 会将您的应用所做的任何本地更改同步到 Cloud Firestore 后端。”

服务没有停止,我只需要打开应用程序就可以将数据发送到firebase!我阅读了有关 Firebase 云消息传递的信息,但我不知道是否需要它们来实现我的目的。

当您的客户端应用程序进入空闲模式时,recommended solution 会使用 Firebase Cloud Messaging 从您的服务器 ping 您的应用程序。当您需要向后端服务器发送实时下游消息或只是通知您的客户端应用程序有新数据可供同步(这可能是您正在寻找的数据)时,此功能非常有用。

您可以参考以上文档了解更多详情。

【讨论】:

  • 我尝试使用 Firebase Cloud Messaging 并且我的应用程序接收它们,但我不明白如何设置让我的应用程序自动接收通知.. 我实现它们的方式需要我继续使用 Firebase控制台并多次发送消息
  • 这条关于针对您的特定用例实施 Firebase 云消息传递的评论可能需要 StackOverflow 中提出一个全新的问题。我建议您遵循上面提供的文档,并请进一步详细说明未按您预期的方式工作的地方,以及您的实现示例代码。
【解决方案2】:

在每个平台或语言中,都有不同的方式连接到 Firebase,所以,请更多关于平台的信息可以帮助 ??, 但你可以检查这个链接也许他可以帮助你 -> link

【讨论】:

  • 我的问题不在于连接到 Firebase。我可以连接到 Firebase,甚至可以将数据添加到 Firestore,直到我的应用仍然打开。问题是,如果我在 1 小时内不使用应用程序(因此手机处于待机状态),则只有在我再次打开应用程序时才会添加 firebase 上的数据。就像它们被保存在缓存中并在再次打开应用时发送到数据库一样。
猜你喜欢
  • 2016-08-22
  • 2020-05-25
  • 2016-06-24
  • 2018-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 1970-01-01
相关资源
最近更新 更多