I am using the periodic location updates and wanted to know which part should be put in service so that even when the app is closed it keeps running. Here is the code
public class MainActivity extends FragmentActivity implements LocationListener,
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener {
private LocationRequest mLocationRequest;
private LocationClient mLocationClient;
private TextView mLatLng;
private TextView mConnectionState;
private TextView mConnectionStatus;
SharedPreferences mPrefs;
SharedPreferences.Editor mEditor;
boolean mUpdatesRequested = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLatLng = (TextView) findViewById(R.id.lat_lng);
mConnectionState = (TextView) findViewById(R.id.text_connection_state);
mConnectionStatus = (TextView) findViewById(R.id.text_connection_status);
mLocationRequest = LocationRequest.create();
mLocationRequest
.setInterval(LocationUtils.UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest
.setFastestInterval(LocationUtils.FAST_INTERVAL_CEILING_IN_MILLISECONDS);
mUpdatesRequested = false;
mPrefs = getSharedPreferences(LocationUtils.SHARED_PREFERENCES,
Context.MODE_PRIVATE);
mEditor = mPrefs.edit();
mLocationClient = new LocationClient(this, this, this);
}
#Override
public void onStop() {
if (mLocationClient.isConnected()) {
stopPeriodicUpdates();
}
mLocationClient.disconnect();
super.onStop();
}
#Override
public void onPause() {
mEditor.putBoolean(LocationUtils.KEY_UPDATES_REQUESTED,
mUpdatesRequested);
mEditor.commit();
super.onPause();
}
#Override
public void onStart() {
super.onStart();
mLocationClient.connect();
}
#Override
public void onResume() {
super.onResume();
// If the app already has a setting for getting location updates, get it
if (mPrefs.contains(LocationUtils.KEY_UPDATES_REQUESTED)) {
mUpdatesRequested = mPrefs.getBoolean(
LocationUtils.KEY_UPDATES_REQUESTED, false);
// Otherwise, turn off location updates until requested
} else {
mEditor.putBoolean(LocationUtils.KEY_UPDATES_REQUESTED, false);
mEditor.commit();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {
// Choose what to do based on the request code
switch (requestCode) {
// If the request code matches the code sent in onConnectionFailed
case LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST:
switch (resultCode) {
// If Google Play services resolved the problem
case Activity.RESULT_OK:
// Log the result
Log.d(LocationUtils.APPTAG, getString(R.string.resolved));
// Display the result
mConnectionState.setText(R.string.connected);
mConnectionStatus.setText(R.string.resolved);
break;
// If any other result was returned by Google Play services
default:
// Log the result
Log.d(LocationUtils.APPTAG, getString(R.string.no_resolution));
// Display the result
mConnectionState.setText(R.string.disconnected);
mConnectionStatus.setText(R.string.no_resolution);
break;
}
// If any other request code was received
default:
// Report that this Activity received an unknown requestCode
Log.d(LocationUtils.APPTAG,
getString(R.string.unknown_activity_request_code,
requestCode));
break;
}
}
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(LocationUtils.APPTAG,
getString(R.string.play_services_available));
// Continue
return true;
// Google Play services was not available for some reason
} else {
// Display an error dialog
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(resultCode,
this, 0);
if (dialog != null) {
ErrorDialogFragment errorFragment = new ErrorDialogFragment();
errorFragment.setDialog(dialog);
errorFragment.show(getFragmentManager(), LocationUtils.APPTAG);
}
return false;
}
}
public void getLocation(View v) {
if (servicesConnected()) {
Location currentLocation = mLocationClient.getLastLocation();
mLatLng.setText(LocationUtils.getLatLng(this, currentLocation));
}
}
public void startUpdates(View v) {
mUpdatesRequested = true;
if (servicesConnected()) {
startPeriodicUpdates();
}
}
public void stopUpdates(View v) {
mUpdatesRequested = false;
if (servicesConnected()) {
stopPeriodicUpdates();
}
}
#Override
public void onConnected(Bundle bundle) {
mConnectionStatus.setText(R.string.connected);
if (mUpdatesRequested) {
startPeriodicUpdates();
}
}
#Override
public void onDisconnected() {
mConnectionStatus.setText(R.string.disconnected);
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
/*
* 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()) {
try {
// Start an Activity that tries to resolve the error
connectionResult.startResolutionForResult(this,
LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST);
/*
* Thrown if Google Play services canceled the original
* PendingIntent
*/
} catch (IntentSender.SendIntentException e) {
// Log the error
e.printStackTrace();
}
} else {
// If no resolution is available, display a dialog to the user with
// the error.
showErrorDialog(connectionResult.getErrorCode());
}
}
#Override
public void onLocationChanged(Location location) {
mConnectionStatus.setText(R.string.location_updated);
mLatLng.setText(LocationUtils.getLatLng(this, location));
}
private void startPeriodicUpdates() {
mLocationClient.requestLocationUpdates(mLocationRequest, this);
mConnectionState.setText(R.string.location_requested);
}
private void stopPeriodicUpdates() {
mLocationClient.removeLocationUpdates(this);
mConnectionState.setText(R.string.location_updates_stopped);
}
private void showErrorDialog(int errorCode) {
Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(errorCode,
this, LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST);
if (errorDialog != null) {
ErrorDialogFragment errorFragment = new ErrorDialogFragment();
errorFragment.setDialog(errorDialog);
errorFragment.show(getFragmentManager(), LocationUtils.APPTAG);
}
}
public static class ErrorDialogFragment extends DialogFragment {
private Dialog mDialog;
public ErrorDialogFragment() {
super();
mDialog = null;
}
public void setDialog(Dialog dialog) {
mDialog = dialog;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return mDialog;
}
}
}
#Override
public void onLocationChanged(Location location) {
}
is the callback which is called when the location changes. So, this should be put in your service so that it is able to receive the updates.
Related
I have an app which obtains the users location and sends it to my Firebase Database which has a list of locations closest to the user. The location radius has been set to less than 50km(50000m). if there are no locations within that radius, I want an alert dialog to appear saying that there are no locations available. The locations will be updated as the app runs. The alert dialog should be shown every time the user tries to access the locations within the set radius. Can someone help me out on how to go about doing it? Any help will be greatly appreciated.
LActivity
public class LActivity extends AppCompatActivity implements
LocationListener,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private static final String TAG = "Location1";
private static final long INTERVAL = 1000 * 10;
private static final long FASTEST_INTERVAL = 1000 * 5;
;
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
public Location mCurrentLocation;
String mLastUpdateTime;
ViewPager viewPager;
ProgressDialog progressdialog;
protected void createLocationRequest() {
mLocationRequest = LocationRequest.create();
mLocationRequest.setInterval(INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
progressdialog = new ProgressDialog(this);
progressdialog.setMessage("Pending");
Runnable progressRunnable = new Runnable() {
#Override
public void run() {
progressdialog.cancel();
}
};
Handler pdcanceller = new Handler();
pdcanceller.postDelayed(progressRunnable,1500);
progressdialog.show();
createLocationRequest();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
setContentView(R.layout.activity_rape_location);
viewPager = (ViewPager) findViewById(R.id.viewpagerL);
viewPager.setAdapter(new RapeLocationPageAdapter(getSupportFragmentManager(),
LActivity.this));
}
public void getLocation(View view) {
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 501);
} else {
mGoogleApiClient.connect();
}
progressdialog.show();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 501) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mGoogleApiClient.connect();
} else {
Toast.makeText(this, "Location permission denied. Please grant location permission to the app.", Toast.LENGTH_SHORT).show();
}
}
}
#Override
public void onStart() {
super.onStart();
Log.d(TAG, "onStart fired ..............");
mGoogleApiClient.connect();
progressdialog.show();
}
#Override
public void onStop() {
super.onStop();
Log.d(TAG, "onStop fired ..............");
mGoogleApiClient.disconnect();
}
#Override
public void onConnected(#Nullable Bundle bundle) {
startLocationUpdates();
}
protected void startLocationUpdates() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)!= PackageManager.PERMISSION_GRANTED)
{
final AlertDialog builder = new AlertDialog.Builder(this).create();
builder.setMessage("Location has not been granted");
builder.setButton(AlertDialog.BUTTON_POSITIVE, "Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
builder.dismiss();
}
});
builder.show();
return;
}
PendingResult<Status> pendingResult = LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this);
Log.d(TAG, "Location update started ..............: ");
progressdialog.show();
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
final AlertDialog builder = new AlertDialog.Builder(this).create();
builder.setMessage("If there are no locations near you, please contact the local police for immediate attention");
builder.setButton(AlertDialog.BUTTON_POSITIVE, "Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
builder.dismiss();
}
});
builder.show();
}
#Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
RapeLocation rapeLocation = (RapeLocation) getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.viewpagerRape + ":" + viewPager.getCurrentItem());
rapeLocation.update(mCurrentLocation);
}
}
LActivityMain
public class LActivityMain extends Fragment {
RecyclerView recyclerView;
LocationsAdapter locationsAdapter;
ArrayList<LocationModel> locationModelArrayList = new ArrayList<LocationModel>();
ArrayList<LocationModel> filteredlocationModelArrayList = new ArrayList<LocationModel>();
protected DatabaseReference mDatabase;
LActivityMain locationActivityfin;
Button bnt1;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.activity_locationmain, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
locationActivityfin = (LActivityMain) getActivity();
mDatabase = FirebaseDatabase.getInstance().getReference();
recyclerView = view.findViewById(R.id.rvLocations);
bnt1 = view.findViewById(R.id.locdone);
bnt1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
getActivity().onBackPressed();
}
});
locationsAdapter = new LocationsAdapter(getActivity(), new OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
LatLng latLng = new LatLng(filteredlocationModelArrayList.get(position).getLatitude(),
filteredlocationModelArrayList.get(position).getLongitude());
String url = "http://maps.google.com/maps?saddr=" + locationActivityfin.mCurrentLocation.getLatitude() + "," + locationActivityfin.mCurrentLocation.getLongitude() + "&daddr=" + latLng.latitude + "," + latLng.longitude + "&mode=driving";
Intent intent = new Intent(android.content.Intent.ACTION_VIEW,
Uri.parse(url));
PackageManager packageManager = getActivity().getPackageManager();
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent);
} else {
if (getView() != null)
Snackbar.make(getView(), "Make sure Google Maps is installed to use this feature", Snackbar.LENGTH_LONG).show();
}
}
}, filteredlocationModelArrayList);
getDataFromServer();
//textView.setText(getArguments().getDouble("latitude") + ", " + getArguments().getDouble("longitude"));
}
public void update(Location location) {
// Toast.makeText(getActivity(), "updated", Toast.LENGTH_SHORT).show();
filteredlocationModelArrayList.clear();
for (LocationModel locationModel : locationModelArrayList) {
Location location1 = new Location("Loc");
location1.setLatitude(locationModel.getLatitude());
location1.setLongitude(locationModel.getLongitude());
if (location1.distanceTo(location) <= 50000 && filteredlocationModelArrayList.size() < 30) {
double distance = (double) (location1.distanceTo(location) / 1000);
try {
distance = round(distance, 2);
} catch (Exception e) {
}
locationModel.setDistance(distance);
filteredlocationModelArrayList.add(locationModel);
}
locationsAdapter.update(filteredlocationModelArrayList);
}
}
public double round(double value, int places) {
if (places <= 0) throw new IllegalArgumentException();
BigDecimal bd = new BigDecimal(value);
bd = bd.setScale(places, RoundingMode.HALF_UP);
return bd.doubleValue();
}
void getDataFromServer() {
mDatabase.child("ali").child("location221").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot dataChild : dataSnapshot.getChildren()) {
LocationModel locationModel = dataChild.getValue(LocationModel.class);
locationModelArrayList.add(locationModel);
}
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setAdapter(locationsAdapter);
if (locationActivityRape.mCurrentLocation != null) {
update(locationActivityRape.mCurrentLocation);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
Assuming you have figured out how to tell that some resource is within some distance from the app, the next question is do you want this to update the app over its entire lifecycle or just at startup or resume.
For the former, as part of your app initialization you start up a timed task of some sort. You want this code to be off the UI thread, and it probably needs to use the network to do its job. The idea is that this task wakes up periodically and does whatever it needs to do to check for external resources.
As long as it finds some valid resource(s) it just goes back to sleep. If it finds no valid resources it then either invokes a callback method or raises an intent that your client code listens for to display a dialog, ring a bell, etc. Make sure you shut down this task when cleaning up your app, and make sure you can cancel the running state and/or it handles and uses timeouts.
If only once on startup just fire off an AsyncTask that gets some results, and then reports via its UI thread handler (or communicates back to the caller) so a dialog can be shown and perhaps the app closed (if these resources are critical to the app lifecycle).
Related Q&A: Timertask or Handler, AsyncTask Android example (But there are many others resources out there.)
I want to get location from background and submit it to server so which is the best option to do the same like Job scheduler or Service. and why ?. I also want to know about battery saved by job scheduler while continuously we make web apicall.
This is my implementation, I don't use Job Scheduler or Service because it's not necessary. I use the Application class so you will be able to get the location of user in all your app.
First, you need to create a LocationHelper class, that will do all the work for you:
public class LocationHelper implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
private static final int REQUEST_LOCATION_PERMISSION = 0;
private static final int REQUEST_RESOLVE_ERROR = 1;
private static GoogleApiClient mGoogleApiClient;
private Fragment mFragment;
private final Activity mActivity;
private final Callback mCallback;
private Location mLastLocation;
private boolean mResolvingError;
private LocationRequest mLocationRequest;
private boolean mRegisterLocationUpdates;
public interface Callback {
void onLastLocation(Location userLocation);
}
public LocationHelper(Fragment fragment, Callback callback) {
this(fragment.getActivity(), callback);
mFragment = fragment;
}
public LocationHelper(Activity activity, Callback callback) {
mActivity = activity;
mCallback = callback;
mLocationRequest = new LocationRequest();
mGoogleApiClient = new GoogleApiClient.Builder(mActivity)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
#Override
public void onConnected(#Nullable Bundle bundle) {
obtainLastLocation();
}
private void obtainLastLocation() {
// Verifies if user give us permission to obtain its suggestionLocationV2.
if (ActivityCompat.checkSelfPermission(mActivity,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(mActivity,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(mActivity,
Manifest.permission.ACCESS_COARSE_LOCATION)) {
// Show an explanation to the user why we need its suggestionLocationV2.
requestPermissionRationale();
} else {
requestPermission();
}
// We don't have user permission to get its geo suggestionLocationV2, abort mission.
return;
}
if (!mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
return;
}
Location lastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (lastLocation != null) {
onLocationChanged(lastLocation);
} else {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
mRegisterLocationUpdates = true;
}
}
#Override
public void onLocationChanged(Location location) {
if (location == null) return;
removeLocationUpdatesIfNeed();
mLastLocation = location;
DirectoryApp.getInstance().setLastLocation(mLastLocation);
if (mCallback != null) {
mCallback.onLastLocation(mLastLocation);
}
}
private void removeLocationUpdatesIfNeed() {
if (mRegisterLocationUpdates && mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
mRegisterLocationUpdates = false;
}
}
private void requestPermission() {
// Lets ask suggestionLocationV2 permission to user.
if (mFragment != null) {
mFragment.requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
REQUEST_LOCATION_PERMISSION);
} else {
ActivityCompat.requestPermissions(mActivity,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
REQUEST_LOCATION_PERMISSION);
}
}
private void requestPermissionRationale() {
new AlertDialog.Builder(mActivity)
.setMessage("We need the suggestionLocationV2 to provide you best results.")
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
requestPermission();
}
})
.show();
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult result) {
// If not already attempting to resolve an error.
if (!mResolvingError) {
if (result.hasResolution()) {
try {
mResolvingError = true;
result.startResolutionForResult(mActivity, REQUEST_RESOLVE_ERROR);
} catch (IntentSender.SendIntentException e) {
// There was an error with the resolution intent. Try again.
mGoogleApiClient.connect();
}
} else {
GooglePlayServicesUtil.showErrorDialogFragment(result.getErrorCode(), mActivity,
null, REQUEST_RESOLVE_ERROR, null);
mResolvingError = true;
}
}
}
// The follow methods should be called in Activity or Fragment.
public void onStart() {
mGoogleApiClient.connect();
}
public void onStop() {
removeLocationUpdatesIfNeed();
mGoogleApiClient.disconnect();
}
public void onRequestPermissionResult(int requestCode, String[] permissions,
int[] grantResults) {
if (requestCode == REQUEST_LOCATION_PERMISSION
&& grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted. Uhull lets get its suggestionLocationV2 now.
obtainLastLocation();
}
}
}
Note that when the location is changed, we call the Application class to set the new location, so in your Application class you have to create the methods :
public class Application extends MultiDexApplication {
private static App instance;
private Location mLastLocation;
#Override
public void onCreate() {
super.onCreate();
instance = this;
}
public void setLastLocation(Location lastLocation) {
mLastLocation = lastLocation;
}
public Location getLastLocation() {
return mLastLocation;
}
And finally, when you have to use the location, on Fragment or Activity, just start and stop it using the right method`s.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
locationHelper = new LocationHelper(this, this);
}
#Override
public void onStart() {
super.onStart();
locationHelper.onStart();
}
#Override
public void onStop() {
super.onStop();
locationHelper.onStop();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
locationHelper.onRequestPermissionResult(requestCode, permissions, grantResults);
}
if you define "best option" as "most battery efficient way": try to minimize calls that activly connects the internet to read or transfer data.
Instead implement a broadcast receiver that tells your app that there is already internet-traffic going on. when you app receives the broadcast notification it can add ist own internet traffic. this way your app can avoid the battery overhead of connecting to the internet which is is very battery expensive.
For detail see "bundled tranfer" at https://developer.android.com/training/efficient-downloads/efficient-network-access.html
I am trying to get users current location using FusedLocationApi using the following code. I am following the guide provided here https://developer.android.com/training/location/retrieve-current.html
public class MapActivity extends ActionBarActivity implements
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,LocationListener {
private Toolbar mToolbar;
private GoogleMap googleMap;
GoogleApiClient mGoogleApiClient;
private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 1000;
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST =5000;
private Location mLastLocation;
private LocationRequest mLocationRequest;
LocationManager locationManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
mToolbar = (Toolbar)findViewById( R.id.toolbar );
mToolbar.setTitle(R.string.title_activity_map);
setSupportActionBar(mToolbar);
try {
initilizeMap();
} catch (Exception e) {
e.printStackTrace();
}
if (checkPlayServices()) {
buildGoogleApiClient();
}
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(10 * 1000) // 10 seconds, in milliseconds
.setFastestInterval(1 * 1000);
}
private void initilizeMap() {
if (googleMap == null) {
googleMap = ((MapFragment) getFragmentManager().findFragmentById(
R.id.map)).getMap();
// check if map is created successfully or not
if (googleMap == null) {
Toast.makeText(getApplicationContext(),
"Sorry! unable to create maps", Toast.LENGTH_SHORT)
.show();
}
googleMap.setMyLocationEnabled(true);
}
}
private boolean checkPlayServices() {
int resultCode = GooglePlayServicesUtil
.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
GooglePlayServicesUtil.getErrorDialog(resultCode, this,
PLAY_SERVICES_RESOLUTION_REQUEST).show();
} else {
Toast.makeText(getApplicationContext(),
"This device is not supported.", Toast.LENGTH_LONG)
.show();
finish();
}
return false;
}
return true;
}
#Override
protected void onResume() {
super.onResume();
initilizeMap();
checkPlayServices();
if (mGoogleApiClient != null) {
mGoogleApiClient.connect();
}
}
#Override
protected void onPause() {
super.onPause();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.map, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onConnectionFailed(ConnectionResult arg0) {
// TODO Auto-generated method stub
if (arg0.hasResolution()) {
try {
// Start an Activity that tries to resolve the error
arg0.startResolutionForResult(this, CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (Exception e) {
e.printStackTrace();
}
} else {
Log.e("Fail", "Location services connection failed with code " + arg0.getErrorCode());
}
}
#Override
public void onConnected(Bundle arg0) {
// TODO Auto-generated method stub
new GetLocation().execute();
}
#Override
public void onConnectionSuspended(int arg0) {
// TODO Auto-generated method stub
}
private class GetLocation extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(
mGoogleApiClient);
if (mLastLocation != null) {
Log.e("If", "If");
} else {
Log.e("else", "else");
}
return null;
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
}
}
#Override
public void onLocationChanged(Location location) {
// TODO Auto-generated method stub
}
#Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
}
When I run the code it always shows else in log, this means that I am not getting any Location. Is there something missing? what am I doing wrong?
Moved from comments:
make sure you have gps enabled on your phone. When enabling gps, phone may also ask you to send data anonymously to google, you should accept it.
I have to get regular updates of user location. For this I have created an Simple Service with flag set to START_STICKY.
I am using GooglePlayServices LocationClient for getting regular location updates.
I am starting this Service through HomeScreen Activity.
Here is my code for this service
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();
}
}
As from code you can see that for handle:
Google Play Services not available exception.
For connection failed exception.
I am passing an message object to activity(HomeActivity) to handle all exception.
But it is not guaranteed that activity(HomeActvity) is visible when exception occur.
So here I am asking you how to handle all exception properly when LocationClient is used in Simple Background Service.
Edit: Adding MainActivity code
Here is my MainActivity code
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();
}
}
I need a help with my app.
I've been trying yo build a simple location app. Therefore, I followed the Android Developer Training (http://developer.android.com/training/location/retrieve-current.html). However, I am stuck with the last part.
My app seems to crash whenever it hits this code,
mLocationClient.connect();
I've added permission and activated location service in my device. Can anyone help me?
This is my whole code.
public class MainActivity extends FragmentActivity
implements
ConnectionCallbacks,
OnConnectionFailedListener{
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
private LocationClient mLocationClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLocationClient = new LocationClient(this, this, this);
}
#Override
protected void onStart(){
super.onStart();
mLocationClient.connect();
}
#Override
protected void onStop(){
mLocationClient.disconnect();
super.onStop();
}
#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 class ErrorDialogFragment extends DialogFragment{
private Dialog mDialog;
public ErrorDialogFragment(){
super();
mDialog = null;
}
public void setDialog(Dialog dialog){
mDialog = dialog;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState){
return mDialog;
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
switch (requestCode) {
case CONNECTION_FAILURE_RESOLUTION_REQUEST :
switch (resultCode) {
case Activity.RESULT_OK:
break;
default:
break;
}
default:
break;
}
}
private boolean servicesConnected() {
int resultCode =
GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (ConnectionResult.SUCCESS == resultCode) {
Log.d("Location Update", "Google Play Services is available");
return true;
} else {
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(resultCode, this, 0);
if (dialog != null) {
//ErrorDialogFragment errorFragment = new ErrorDialogFragment();
//errorFragment.setDialog(dialog);
//errorFragment.show(getFragmentManager(), "Location Updates");
//errorFragment.show(getSupportFragmentManager(), "Location Updates");
}
return false;
}
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
// TODO Auto-generated method stub
if (connectionResult.hasResolution()) {
try {
connectionResult.startResolutionForResult(
this,
CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
} else {
showErrorDialog(connectionResult.getErrorCode());
}
}
private void showErrorDialog(int errorCode) {
Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
errorCode,
this,
CONNECTION_FAILURE_RESOLUTION_REQUEST);
if (errorDialog != null) {
ErrorDialogFragment errorFragment = new ErrorDialogFragment();
errorFragment.setDialog(errorDialog);
}
}
#Override
public void onConnected(Bundle arg0) {
// TODO Auto-generated method stub
Toast.makeText(this, "Connected", Toast.LENGTH_SHORT).show();
}
#Override
public void onDisconnected() {
// TODO Auto-generated method stub
Toast.makeText(this, "Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
}
}
I think you don't have Google Play Services installed. You have the method servicesConnected(), but you don't use it. You should wrap your call to mLocationClient.connect() in an if statement that checks servicesConnected().
I had a similar issue and I had forgotten to add this in my manifest under application:
<meta-data android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
Read this again for help.