【发布时间】: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