我正在创建一个跟踪用户位置的应用,并根据他们行进的距离,他们的整体速度和他们花费的时间来更新它们。当用户点按StartTracking
中的MainActivity.java
按钮时,会启动MapsActivity.java
。 MapsActivity.java
包含地图片段和显示信息的TextView。位置跟踪在服务TrackingService.java
中完成,因此即使应用程序在后台运行,位置仍在更新中。
为了发送距离,时间和速度,我在服务中使用广播接收器。触发onLocationChanged()
时广播距离。为了广播时间和速度,我使用了timer.schedule()
。当我点击StopTracking
中的MapsActivity.java
按钮时,服务应该停止,活动被销毁,用户应该返回MainActivity.java
。
我的问题是,当我点按StopTracking Button
时,上述所有情况都会发生,但timer.schedule()
中的广播仍会继续广播。因此,当我在StartTracking
中再次点击MainActivity
时,TextViews的速度和时间会在旧值和较新值之间切换。相关的课程如下,我删除了冗余代码,使其更具可读性。
完全披露:这是针对学校作业的。我假设完美的GPS条件,没有连接损失。分配需要使用BroadCastReciever和Service。
MapsActivity.java
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
private GoogleMap mMap;
private Intent intent;
private TrackingService trackingService;
private BroadcastReceiver receiver;
private ArrayList<Location> coordinates;
private TextView distanceTV, timeTV, speedTV;
private Button stopTrackingButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
coordinates = new ArrayList<Location>();
distanceTV = (TextView) findViewById(R.id.distanceTextView);
timeTV = (TextView) findViewById(R.id.timeTextView);
speedTV = (TextView) findViewById(R.id.speedTextView);
IntentFilter filter = new IntentFilter();
filter.addAction("locationChanged");
filter.addAction("timeChanged");
filter.addAction("speedChanged");
stopTrackingListener();
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("locationChanged"))
{
Bundle bundle = intent.getExtras();
coordinates = bundle.getParcelableArrayList("COORDINATES");
float distance = bundle.getFloat("DISTANCE");
distanceTV.setText("Distance: " + Float.toString((float) Math.round(distance *100f) / 100f) + "m");
Log.d("test", "onReceive location");
redrawLine();
}
else if (intent.getAction().equals("timeChanged"))
{
Bundle bundle = intent.getExtras();
long time = bundle.getLong("TIME");
float hours = (float) (((time/1000) / 60) / 60);
float mins = (float) (((time/1000) / 60) % 60);
float secs = (float) ((time/1000) %60);
timeTV.setText(String.format("Time: %.0fh: %.0fm: %.0fs", hours, mins, secs));
}
else if (intent.getAction().equals("speedChanged"))
{
Bundle bundle = intent.getExtras();
float speed = bundle.getFloat("SPEED");
speedTV.setText("Avg Speed: " + Float.toString (Math.round(speed *100f) / 100f) + "m/s");
}
}
};
LocalBroadcastManager.getInstance(this).registerReceiver(receiver, filter);
}
private ServiceConnection trackerConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
TrackingService.TrackingBinder binder = (TrackingService.TrackingBinder)iBinder;
trackingService = binder.getService();
Log.d("test", "Service is Connected");
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.d("test", "Service Disconnected");
}
};
//Start the service as soon as activity starts
@Override
protected void onStart()
{
super.onStart();
if(intent == null)
{
intent = new Intent(getBaseContext(), TrackingService.class);
bindService(intent, trackerConnection, Context.BIND_AUTO_CREATE);
startService(intent);
Log.d("test", "Service Started");
}
}
//Unbind and destroy service when app is destroyed
@Override
protected void onDestroy()
{
unbindService(trackerConnection);
getBaseContext().stopService(intent);
Log.d("test", "Service Destroyed");
super.onDestroy();
}
//Listens for user tapping on "Stop tracking..." button.
public void stopTrackingListener()
{
stopTrackingButton = (Button)findViewById(R.id.stopTrackingButton);
stopTrackingButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view)
{
Log.d("test", "Stopped tracking...");
getBaseContext().stopService(intent);
trackingService = null;
Intent i =new Intent (MapsActivity.this, MainActivity.class);
startActivity(i);
finish();
}
});
}
}
TrackingService.java
public class TrackingService extends Service implements LocationListener{
private final IBinder trackingBind = new TrackingBinder();
private ArrayList<Location> points;
LocationManager locationManager;
StopWatch timer;
public void onCreate()
{
super.onCreate();
points = new ArrayList<Location>();
timer = new StopWatch();
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
requestLocation();
updateTimeAndSpeed();
}
private void requestLocation() {
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
locationManager.requestLocationUpdates(locationManager.GPS_PROVIDER, 1000, 1, this);
timer.start();
}
@Override
public IBinder onBind(Intent intent) {
return trackingBind;
}
@Override
public boolean onUnbind(Intent intent)
{
timer.stop();
Log.d("test2", "Service onUnbind");
return false;
}
@Override
public void onLocationChanged(Location location) {
points.add(location);
broadcastCurrentLocation();
}
public class TrackingBinder extends Binder
{
TrackingService getService()
{
return TrackingService.this;
}
}
public void updateTimeAndSpeed()
{
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
broadcastElapsedTime();
broadcastAverageSpeed();
Log.d("test2", "Broadcasting...");
}
}, 0, 1000);
}
public void broadcastElapsedTime()
{
Intent intent = new Intent ("timeChanged");
intent.putExtra("TIME", getTime());
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
public void broadcastCurrentLocation()
{
Intent intent = new Intent ("locationChanged");
intent.putParcelableArrayListExtra("COORDINATES", points);
intent.putExtra("DISTANCE", calculateDistance());
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
public void broadcastAverageSpeed()
{
Intent intent = new Intent ("speedChanged");
intent.putExtra("SPEED", getSpeed());
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
public float calculateDistance()
{
float distance = 0;
if(null != points && (!points.isEmpty()))
{
for(int i = 1; i < points.size(); i++)
{
Location currLoc = new Location(points.get(i));
Location lastLoc = new Location(points.get(i-1));
distance += lastLoc.distanceTo(currLoc);
}
}
return distance;
}
public long getTime()
{
return timer.getElapsedTime();
}
public float getSpeed()
{
float distance = calculateDistance();
long time = getTime();
float timeAsSeconds = (float) (time/1000);
return (distance / timeAsSeconds);
}
}
答案 0 :(得分:1)
覆盖onDestroy()
子类中的Service
。在该方法中,您可以在固定延迟计时器上调用Timer.cancel()
。 (您需要将该计时器的引用保留为TrackingService.java
中的字段。)
答案 1 :(得分:0)
我认为问题是您在使用 locationManager.requestLocationUpdates 时不会调用 locationManager.removeUpdates 。 所以尝试添加
locationManager.removeUpdates(本);
到TrackingService类的onUnbind方法