我必须定期更新用户位置。为此,我创建了一个简单服务,标志设置为START_STICKY。
我正在使用GooglePlayServices
LocationClient
来定期更新地址。
我通过HomeScreen Activity启动此服务。
以下是此服务的代码
import android.app.Service;
import android.content.Intent;
import android.location.Location;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.location.LocationClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
public class GpsLocationUpdatingService extends Service implements
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener,
LocationListener {
private static final String TAG = "GpsLocationUpdatingService";
public static final int GOOGLE_PLAY_SERVICE_NOT_AVAILABLE = 1;
public static final int CONN_FAILED_HAS_RESOLUTION = 2;
public static final int SHOW_GENERAL_LOCATION_DETECT_PROB_DIALOG = 3;
// Milliseconds per second
private static final int MILLISECONDS_PER_SECOND = 1000;
// Update frequency in seconds
public static final int UPDATE_INTERVAL_IN_SECONDS = 5;
// Update frequency in milliseconds
private 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 = 1;
// A fast frequency ceiling in milliseconds
private static final long FASTEST_INTERVAL =
MILLISECONDS_PER_SECOND * FASTEST_INTERVAL_IN_SECONDS;
private LocationClient mLocationClient = null;
private LocationRequest mLocationRequest = null;
private Messenger messenger;
@Override
public void onCreate() {
super.onCreate();
mLocationClient = new LocationClient(this, this, this);
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Set the update interval to 5 seconds
mLocationRequest.setInterval(UPDATE_INTERVAL);
// Set the fastest update interval to 1 second
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
messenger = (Messenger) intent.getExtras().get(MainActivity.INTENT_MESSENGER_EXTRA);
if(servicesConnected()) {
mLocationClient.connect();
}
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onConnected(Bundle arg0) {
Toast.makeText(this, "Connected", Toast.LENGTH_SHORT).show();
mLocationClient.requestLocationUpdates(mLocationRequest, this);
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
if (connectionResult.hasResolution()) {
sendMessageObject(CONN_FAILED_HAS_RESOLUTION, connectionResult.getErrorCode());
} else {
sendMessageObject(SHOW_GENERAL_LOCATION_DETECT_PROB_DIALOG, 100);
}
}
@Override
public void onDisconnected() {
Toast.makeText(this, "Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
}
@Override
public void onLocationChanged(Location location) {
String msg = "Updated Location: " +
Double.toString(location.getLatitude()) + "," +
Double.toString(location.getLongitude());
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
// Method used to check if GPS tracking
// Google Play Service is available or not
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) {
// In debug mode, log the status
Log.d(TAG, "Google Play services is available.");
// Continue
return true;
// Google Play services was not available for some reason
} else {
// Get the error code
int errorCode = resultCode;
// Send message to activity with error code.
// To show the dialog accordingly
sendMessageObject(GOOGLE_PLAY_SERVICE_NOT_AVAILABLE, errorCode);
// Stop service
return false;
}
}
// Send message to handler activity
private void sendMessageObject(int errorType, int errorCode) {
Message msg = Message.obtain();
Bundle bundle = new Bundle();
bundle.putInt("errortype", errorType);
bundle.putInt("errorcode", errorCode);
msg.setData(bundle);
try {
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
stopSelf();
}
}
从代码中你可以看到for handle:
我正在将一个消息对象传递给activity(HomeActivity)以处理所有异常。
但不保证在发生异常时活动(HomeActvity)可见。
所以我在这里问你如何在简单后台服务中使用LocationClient
时正确处理所有异常。
编辑:添加MainActivity代码
这是我的MainActivity代码
public class MainActivity extends FragmentActivity {
private static final String TAG = "MainActivity";
public static final String INTENT_MESSENGER_EXTRA = "messenger";
private static final int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
private static Activity activity;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
activity = this;
// Start background Location detecting web-service
Intent intent = new Intent(this, GpsLocationUpdatingService.class);
intent.putExtra(INTENT_MESSENGER_EXTRA, new Messenger(handler1));
startService(intent);
}
@Override
protected void onStart() {
super.onStart();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public static Activity getActvity() {
return activity;
}
// Define a DialogFragment that displays the error dialog
public static class ErrorDialogFragment extends DialogFragment {
// Global field to contain the error dialog
private Dialog mDialog;
// Default constructor. Sets the dialog field to null
public ErrorDialogFragment() {
super();
mDialog = null;
}
// Set the dialog to display
public void setDialog(Dialog dialog) {
mDialog = dialog;
}
// Return a Dialog to the DialogFragment.
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return mDialog;
}
}
// Method calls when returning back after updating Google Play Services
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Decide what to do based on the original request code
switch (requestCode) {
case CONNECTION_FAILURE_RESOLUTION_REQUEST:
/*
* If the result code is Activity.RESULT_OK, try
* to connect again
*/
switch (resultCode) {
case Activity.RESULT_OK :
/*
* Try the request again
*/
break;
}
}
}
Handler handler1 = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Bundle reply = msg.getData();
int errorType = reply.getInt("errortype");
int errorCode;
switch (errorType) {
case GpsLocationUpdatingService.GOOGLE_PLAY_SERVICE_NOT_AVAILABLE:
// Show install google play services dialog
errorCode = reply.getInt("errorcode");
showInstallPlayServiceDialog(errorCode);
break;
case GpsLocationUpdatingService.CONN_FAILED_HAS_RESOLUTION:
// Check resolution error code and act accordingly
errorCode = reply.getInt("errorcode");
getResoltuinAndShowDialog(errorCode);
break;
case GpsLocationUpdatingService.SHOW_GENERAL_LOCATION_DETECT_PROB_DIALOG:
// Show general dialog of problem
// detecting location
showGeneralDialog();
break;
default:
break;
}
return false;
}
});
private void showInstallPlayServiceDialog(int errorCode) {
Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
errorCode,
activity,
CONNECTION_FAILURE_RESOLUTION_REQUEST);
// If Google Play services can provide an error dialog
if (errorDialog != null) {
// Create a new DialogFragment for the error dialog
ErrorDialogFragment errorFragment =
new ErrorDialogFragment();
// Set the dialog in the DialogFragment
errorFragment.setDialog(errorDialog);
// Show the error dialog in the DialogFragment
errorFragment.show(getSupportFragmentManager(), "Location Updates");
} else {
// Show general dialog of problem
// detecting location
showGeneralDialog();
}
}
private void getResoltuinAndShowDialog(int errorCode) {
PendingIntent pendingIntent = PendingIntent.getActivity(getActvity(),
CONNECTION_FAILURE_RESOLUTION_REQUEST,
new Intent(this, MainActivity.class),
PendingIntent.FLAG_UPDATE_CURRENT);
ConnectionResult connResult = new ConnectionResult(errorCode, pendingIntent);
try {
connResult.startResolutionForResult(MainActivity.getActvity(), CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (SendIntentException e) {
e.printStackTrace();
Log.d(TAG, "Get resoltuion and show dialog exception");
}
}
private void showGeneralDialog() {
Toast.makeText(getActvity(), "Show general dialog is called", Toast.LENGTH_SHORT).show();
}
}