Понимание того, как Service, LocationListener и BroadcastReceiver работают, чтобы получить местоположение в фоновом режиме
Я новичок в Android
и я работаю над созданием приложения, которое отслеживает расстояние пользователя. Отслеживание начнется только тогда, когда пользователь нажмет кнопку, и остановится, когда они снова нажмут. Похоже, существует большое количество информации и методов о путанице, как это сделать, поэтому у меня, по крайней мере, есть общее представление о лучших практиках.
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 {
}
}
}
Итак, на мои вопросы:
- С моей главной
Activity
как мне начать обслуживание? Как мне это остановить? - Как может мой
Activity
класс знаю, когда мойService
получаетLocation
обновления, чтобы я мог обновить пользовательский интерфейс? - Нужно ли мне вообще
BroadcastReceiver
? - Что-нибудь нужно, чтобы пойти в мой
Manifest
?
1 ответ
Решение
Давайте ответим на ваши вопросы по порядку:
- http://www.androidhive.info/2012/07/android-gps-location-manager-tutorial/
- onLocationChanged (Местоположение)
- нет, переход к 1
- Да, опять Goto 1
Изменить: Отчетность обратно в MainActivity
В MainActivity добавьте такой интерфейс:
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();
}
}
И добавьте в 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: пример того, как обрабатывать выход, повторный ввод и изменение ориентации:
Поскольку, как вы говорите, вы новичок в Android, я подумал, что я мог бы добавить это.
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();
}
}