Pregunta

I am new to Android and am working on building an app that tracks the users distance. It would only start tracking when the user taps a button, and stops when they tap again. There seems to be a large amount of confusion information and methods on how to do this, so I have I at least have a general idea of best practices.

public class BackgroundLocationService extends Service implements GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener, LocationListener {

    IBinder mBinder = new LocalBinder();

    private LocationClient mLocationClient;
    private LocationRequest mLocationRequest;
    private boolean mInProgress;

    //Milliseconds per second
  private static final int MILLISECONDS_PER_SECOND = 1000;
  // Update frequency in seconds
  private static final int UPDATE_INTERVAL_IN_SECONDS = 30;
  // Update frequency in milliseconds
  public static final long UPDATE_INTERVAL = MILLISECONDS_PER_SECOND * UPDATE_INTERVAL_IN_SECONDS;
  // The fastest update frequency, in seconds
  private static final int FASTEST_INTERVAL_IN_SECONDS = 30;
  // A fast frequency ceiling in milliseconds
  public static final long FASTEST_INTERVAL = MILLISECONDS_PER_SECOND * FASTEST_INTERVAL_IN_SECONDS;
  private static final int TWO_MINUTES = 1000 * 60 * 2;

  public Location previousBestLocation = null;

  private Boolean servicesAvailable = false;

  public class LocalBinder extends Binder {
    public BackgroundLocationService getServerInstance() {
        return BackgroundLocationService.this;
    }
  }

  @Override
    public void onCreate() {
      super.onCreate();

      mInProgress = false;
      mLocationRequest = LocationRequest.create();
      mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
      mLocationRequest.setInterval(UPDATE_INTERVAL);
      mLocationRequest.setFastestInterval(FASTEST_INTERVAL);

      // Check that Google Play Services are connected
      servicesAvailable = servicesConnected();

      // Create the client
      mLocationClient = new LocationClient(this, this, this);

  }//end

  private boolean servicesConnected() {

      // Check that Google Play services is available
      int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);

      // If Google Play services is available
      if (ConnectionResult.SUCCESS == resultCode) {
          return true;
      } else {
          return false;
      }

  }//end

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

      super.onStartCommand(intent, flags, startId);

      if(!servicesAvailable || mLocationClient.isConnected() || mInProgress)
        return START_STICKY;

      setUpLocationClientIfNeeded();
      if(!mLocationClient.isConnected() || !mLocationClient.isConnecting() && !mInProgress) {
            mInProgress = true;
            mLocationClient.connect();
      }

      return START_STICKY;
  }//end


  private void setUpLocationClientIfNeeded() {
    if (mLocationClient == null) 
          mLocationClient = new LocationClient(this, this, this);
  }


  @Override
  public void onLocationChanged(Location location) {

      String msg = Double.toString(location.getLatitude()) + "," +Double.toString(location.getLongitude());
      Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();

  }//end

  @Override
  public IBinder onBind(Intent intent) {
    return mBinder;
  }

  public String getTime() {
    SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    return mDateFormat.format(new Date());
  }


  @Override
  public void onDestroy(){
      // Turn off the request flag
      mInProgress = false;
      if(servicesAvailable && mLocationClient != null) {
            mLocationClient.removeLocationUpdates(this);
            // Destroy the current location client
            mLocationClient = null;
      }
      // Display the connection status
      Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
      super.onDestroy();  
  }

  /*
   * Called by Location Services when the request to connect the
   * client finishes successfully. At this point, you can
   * request the current location or start periodic updates
   */
  @Override
  public void onConnected(Bundle bundle) {

      // Request location updates using static settings
      mLocationClient.requestLocationUpdates(mLocationRequest, this);

  }

  /*
   * Called by Location Services if the connection to the
   * location client drops because of an error.
   */
  @Override
  public void onDisconnected() {
      // Turn off the request flag
      mInProgress = false;
      // Destroy the current location client
      mLocationClient = null;
      // Display the connection status
      Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();

  }

  /*
   * Called by Location Services if the attempt to
   * Location Services fails.
   */
  @Override
  public void onConnectionFailed(ConnectionResult connectionResult) {
    mInProgress = false;

      /*
       * Google Play services can resolve some errors it detects.
       * If the error has a resolution, try sending an Intent to
       * start a Google Play services activity that can resolve
       * error.
       */
      if (connectionResult.hasResolution()) {

      // If no resolution is available, display an error dialog
      } else {

      }
  }

}

So onto my questions:

  • From my main Activity how do I start my service? How do I stop it?
  • How can my Activity class know when my Service receives Location updates so that I can update the UI?
  • Do I even need a BroadcastReceiver?
  • Does anything need to go into my Manifest?
¿Fue útil?

Solución

Lets take your questions in order:

  1. http://www.androidhive.info/2012/07/android-gps-location-manager-tutorial/
  2. onLocationChanged(Location location)
  3. no, goto 1
  4. Yes, again, goto 1

Edit: Reporting back to MainActivity

In you MainActivity add an interface like this:

public class MainActivity implements NewLocationsListener {

    public interface NewLocationsListener {

        public void onNewLocation(Location location);
    }

    private GPSTracker gps;

    ...

    // when your button is clicked or where ever you want to start gps
    gps = new GPSTracker(this, this);

    ...

    // and get Locations in onNewLocation
    public void onNewLocation(Location location) {
        // location reported back from gps 
    }

    // if you want gps to stop after exiting your app
    @Override
    protected void onPause() {
        if (gps != null) {
            gps.stopUsingGPS();
        }
        super.onPause();
    }

}

And add to the GPSTracker:

private NewLocationsListener mListener;

public GPSTracker(Context context, NewLocationsListener listener) {
    this.mContext = context;
    this.mListener = listener;
    getLocation();
}


@Override
public void onLocationChanged(Location location) {
    // report back to MainActivity
    mListener.onNewLocation(location);
    canGetLocation = true;
}

Edit2: An example of how to handle exit re-enter and orientation changes:

Since you, as you say, are new to Android, I thought I might as well add this.

public class StrategyActivity extends Activity {

    public static final String TAG = "StrategyActivity";

    protected GPSTracker gps;

    private Button startButton;
    private boolean isStarted = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        startButton = (Button) findViewById(R.id.start_button);

        if (savedInstanceState != null) {
            isStarted = savedInstanceState.getBoolean("isStarted");
        }
    }


    @Override
    protected void onResume() {
        if (isStarted) {
            startStrategy();
        }
        updateOnOffButton();
        super.onResume();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putBoolean("isStarted", isStarted);
        super.onSaveInstanceState(outState);
    }

    @Override
    public void onBackPressed() {
        if (isStarted) {
            stopStrategy();
        }
        super.onBackPressed();
    }

    @Override
    protected void onPause() {
        if (isStarted) {
            killStrategy();
        }
        super.onPause();
    }

    @Override
    protected void onDestroy() {
        killStrategy();
        super.onDestroy();
    }

    public void startStopClicked(View view) {
        if (isStarted) {
            stopStrategy();
        } else {
            startStrategy();
        }
    }

    private void updateOnOffButton() {
        if (isStarted) {
            startButton.setText("Stop");
        } else {
            startButton.setText("Start");
        }
    }


    protected void killStrategy() {
        if (gps != null) {
            gps.stopUsingGPS();
        }
    }

    protected void startStrategy() {
        isStarted = true;
        gps = new GPSTracker(this);
        updateOnOffButton();
        Toast.makeText(this, "Started", Toast.LENGTH_LONG).show();
    }

    protected void stopStrategy() {
        isStarted = false;
        killStrategy();
        updateOnOffButton();
        Toast.makeText(this, "Stopped", Toast.LENGTH_LONG).show();
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top