我有一个位置跟踪应用程序。我有一个前台服务,当应用程序进入后台时,它将继续获取位置。那部分工作正常。如果输出位置,则可以看到不同的点和正确的时间戳。
在后台,我需要将该数据发布到API端点。我的GPSHeartbeat
类是单例,它公开了一个让我更新Singletons位置属性的函数。
在前台时,一切正常。在后台运行时,位置已更新,但单身人士在 之前 中拥有最后一个位置。
我的APICommunicator
正按其间隔在后台触发,只是位置不正确。
这里是广播接收器,负责收听前景服务的位置更改。
这在后台和前景均能正常工作。成功获取更新的位置。
private void onNewLocation(Location location)
{
Log.i(TAG, "onNewLocationRec'd: " + location);
mLocation = location;
// Notify anyone listening for broadcasts about the new location.
Intent intent = new Intent(ACTION_BROADCAST);
intent.putExtra(EXTRA_LOCATION, location);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
// Update notification content if running as a foreground service.
if (serviceIsRunningInForeground(this)) {
mNotificationManager.notify(NOTIFICATION_ID, getNotification());
}
}
BroadcastReceiver
是称为HomeActivity
的Activity的内部类。这将从服务获得正确的位置。如果输出日志,则与服务广播的日志相同。
public class HomeActivity extends AppCompatActivity
{
private GPSHeartbeat mGPSHeartbeat;
private GPSReceiver myReceiver;
private LocationUpdatesService mService = null;
private boolean mBound = false;
private final ServiceConnection mServiceConnection = new ServiceConnection()
{
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
LocationUpdatesService.LocalBinder binder = (LocationUpdatesService.LocalBinder) service;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name)
{
mService = null;
mBound = false;
}
};
private void GPSBeginRequestingUpdates()
{
//Wait 5 seconds to spin up
(new Handler()).postDelayed(this::StartGPSUpdates, 5000);
}
private void StartGPSUpdates()
{
mService.requestLocationUpdates();
}
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
myReceiver = new GPSReceiver();
setContentView(R.layout.activity_home);
mGPSHeartbeat = GPSHeartbeat.instance(getApplicationContext()).setInterval(6);
}
@Override
protected void onStart()
{
super.onStart();
bindService(new Intent(getApplicationContext(), LocationUpdatesService.class), mServiceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop()
{
if (mBound) {
unbindService(mServiceConnection);
mBound = false;
}
super.onStop();
}
@Override
protected void onResume()
{
super.onResume();
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(myReceiver, new IntentFilter(LocationUpdatesService.ACTION_BROADCAST));
GPSBeginRequestingUpdates();
}
@Override
protected void onPause()
{
LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(myReceiver);
super.onPause();
}
private class GPSReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
Location location = intent.getParcelableExtra(LocationUpdatesService.EXTRA_LOCATION);
if (location != null) {
Log.i(TAG, "\nonReceived New Location: " + GPSUtils.getLocationText(location));
GPSHeartbeat.instance(context.getApplicationContext()).SetLocation(location);
}
}
}
}
单身汉。 SetLocation()确实会收到正确的位置。仅在我的POST请求期间,APICommunicator
使用GPSHeartbeat
的旧位置。即使它刚刚更新。
如何确保我更新到正确的位置?
public class GPSHeartbeat extends Service {
private static String TAG = "GPSHeartbeat";
private static volatile GPSHeartbeat _instance;
private final WeakReference<Context> mContextRef;
private Boolean isRunning = false;
private int mInterval;
private Location mLocation;
private Handler mHandler;
private ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
private Future mLongRunningTaskFuture;
private Runnable mStatusChecker = new Runnable()
{
@Override
public void run()
{
try {
tick(); //this function can change value of mInterval.
}
finally {
if (isRunning()) {
// 100% guarantee that this always happens, even if your update method throws an exception
mHandler.postDelayed(mStatusChecker, mInterval);
}
}
}
};
private GPSHeartbeat(Context context)
{
mContextRef = new WeakReference<>(context.getApplicationContext());
}
public static GPSHeartbeat instance(Context context)
{
if (_instance == null) {
_instance = new GPSHeartbeat(context);
} else {
if (!context.equals(_instance.mContextRef.get())) {
_instance = null;
_instance = new GPSHeartbeat(context);
}
}
return _instance;
}
public void SetLocation(Location loc)
{
Log.i(TAG, "setLocation(): " + loc);
this.mLocation = loc;
}
public GPSHeartbeat setInterval(int interval)
{
this.mInterval = interval * 1000;
return this;
}
public void start()
{
if (isRunning()) return;
mHandler = new Handler();
mLongRunningTaskFuture = mExecutorService.submit(mStatusChecker);
mStatusChecker.run();
isRunning = true;
}
public void stop()
{
if (mHandler != null) {
mHandler.removeCallbacks(mStatusChecker);
}
if (mLongRunningTaskFuture != null) {
//kill the task:
try {
mLongRunningTaskFuture.cancel(true);
mLongRunningTaskFuture = null;
mHandler = null;
}
catch (Exception e) {
Log.e(TAG, "Unable to cancel task: " + e.getLocalizedMessage());
}
}
isRunning = false;
}
public Location currentLocation()
{
return mLocation;
}
public boolean isRunning()
{
return isRunning;
}
private void tick()
{
// Fire off the APICommuncator.Post() method
}
@Nullable
@Override
public IBinder onBind(Intent intent)
{
return null;
}
}
APICommuncator
public class APICommuncator
{
private static String TAG = "APICommuncator";
private static volatile APICommuncator _instance;
private final WeakReference<Context> mContextRef;
private GPSHeartbeat _gpsHeartbeat;
private APICommuncator(Context context)
{
mContextRef = new WeakReference<>(context.getApplicationContext());
_gpsHeartbeat = GPSHeartbeat.instance(context.getApplicationContext());
}
public static APICommuncator i(Context context)
{
if (_instance == null) {
_instance = new APICommuncator(context);
} else {
if (!context.equals(_instance.mContextRef.get())) {
_instance = null;
_instance = new APICommuncator(context);
}
}
return _instance;
}
public void Post(){
// Do the background thing and grab
// getLocationNode() which gets the OLD location before it went to the background.
}
private JSONObject getLocationNode()
{
Location location = _gpsHeartbeat.currentLocation();
if (location == null) {
return null;
}
JSONObject node = null;
try {
node = new JSONObject();
node.put("Latitude", String.valueOf(location.getLatitude()));
node.put("Longitude", String.valueOf(location.getLongitude()));
node.put("HAccuracy", String.valueOf(location.getAccuracy()));
node.put("VAccuracy", String.valueOf(location.getAccuracy()));
node.put("Altitude", String.valueOf(location.getAltitude()));
node.put("Speed", String.valueOf(location.getSpeed() * 2.237));
node.put("Heading", String.valueOf(location.getBearing()));
node.put("Timestamp", String.valueOf((location.getTime() / 1000)));
}
catch (JSONException | NullPointerException e) {
e.printStackTrace();
}
return node;
}
}
在清单中:
<service
android:name=".gpsheartbeat.GPSHeartbeat"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" />
<service
android:name=".gpsheartbeat.LocationUpdatesService"
android:enabled="true"
android:exported="true"
android:foregroundServiceType="location" />
答案 0 :(得分:0)
实际上,我看不到您正在使用前台服务。在应用程序变为后台后不久,不会终止前台服务。另外,与API的通信应在前台服务范围内,因为活动可能会被系统杀死。