服务中的广播接收器在服务停止后仍在广播

时间:2017-12-27 07:24:00

标签: java android

我正在创建一个跟踪用户位置的应用,并根据他们行进的距离,他们的整体速度和他们花费的时间来更新它们。当用户点按StartTracking中的MainActivity.java按钮时,会启动MapsActivity.javaMapsActivity.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);
    }


}

2 个答案:

答案 0 :(得分:1)

覆盖onDestroy()子类中的Service。在该方法中,您可以在固定延迟计时器上调用Timer.cancel()。 (您需要将该计时器的引用保留为TrackingService.java中的字段。)

答案 1 :(得分:0)

我认为问题是您在使用 locationManager.requestLocationUpdates 时不会调用 locationManager.removeUpdates 。 所以尝试添加

  

locationManager.removeUpdates(本);

到TrackingService类的onUnbind方法