Building Apps with Location & Maps
1 Making Your app Location-Aware
- location awareness
- Google Play services location APIs
- automate location tracking, geofencing, and activity recognition, get the current location, get periodic location updates, and look up address
1.1 Getting the Last Known Location
- use
Google Play services location APIs
- use
fused location provider
getLastLocation()
1.1.1 Set up Google Play services
1.1.2 Specify App Permissions
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.gms.location.sample.locationupdates" >
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
</manifest>
1.1.3 Create Location Services Client
FuesdLocationProviderClient fusedClient = LocationServices.getFusedLoationProviderClient(this);
1.1.4 Get the Last Known Location
getLastLocation()
retures a Task- retrieve the latitude and longitude coordinates from a Location Object
fusedClient.getLastLocation().addOnSuccessLitener(this, new OnSuccessListener<Location>() {
@Override
public void onSuccess(Location location) {
//Got last known location. In some rare situations this can be null.
if (location != null) {}
}
});
1.2 Changing Location Settings
- GPS or Wi-Fi scanning
- the required level of accuracy/power consumption and desired update interval, and the device automatically makes the appropriate changes to system settings
LocationRequest
data object defined these settings
1.2.1 Configure Location Services
SettingClient
- coarse location detection is sufficient
- Android 6.0+ or API 23+, request those permissions at run time
1.2.2 Set up a Location Request
- create a
LocationRequest
to store parametres for requests - LocationRequest
- set the update interval, receive location updates
- set fastest update interval, handle location updates
- set priority, the priority of the request,
protected void createLocationRequest() {
LocationRequest locationRequest = new LocationRequest();
locationRequest.setInterval(1000);
locationRequest.setFastestInterval(5000);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
1.2.3 Get current Location Settings
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(request);
SettingsClient client = LocationService.getSettingsClient(this);
Task<LocationSettingsResponse> task = client.checkLocationSettings(builder.build());
1.2.4 Prompt the User to Change Location Settings
1.3 Receiving Location Updates
getLastLocation()
requestLocationUpdates()
1.3.1 Get the Last Known Location
currentLocation
- request
access_fine_location
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
1.3.2 Request Location Updates
- invoke
LocationCallback.onLocationChanged()
- issue a PendingIntent that contains the location in its extended data
if (requestingLocationUpdates) {
fusedClient.requestLocationUpdates(locationRequest, locationCallback, null/*Looper*/);
}
1.3.3 Define the Location Update Callback
- define LocationCallback
- implement LocationCallback interface, and invoke
LocationCallback.onLocationChanged()
LocationCallback locationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult result) {
for (Location location : result.getLocations()) {
}
}
});
1.3.4 Stop Location Updates
- reduce power consumption, and don’t collect information in bg
- at
onPause()
, callfusedClient.removeLocationUpdates(locationCallback)
- at
onResume()
, callfusedClient.requestLocationUpdates()
1.3.5 Save the State of the Activity
-
onSaveInstanceState()
to save the instance state@Override protected void onSaveInstanceState(Bundle outState) { outState.putBoolean(REQUESTING_LOCATION_UPDATES_KEY, requestingLocationUpdates); }
-
at
onCreate()
update Values From Bundle of savedInstanceStateif (savedInstanceState.keySet().contains(REQUESTING_LOCATION_UPDATES_KEY)) { requestingLocationUpdates = savedInstanceState.getBoolean(REQUESTING_LOCATION_UPDATES_KEY); } updateUI();
1.4 Displaying a Location Address
- the latitude and longitude coordinates
- use
Geocoder
to inter convert an address and coordinates
1.4.1 Get a geographic location
- request
ACCESS_FINE_LOCATION
permission getLastLocation()
- create a instance of FusedLocationProviderClient
1.4.2 Define an intent service to fetch the address
- Geocoder provides
getFromLocation()
, can’t call it from the main(UI) thread IntentService
provides a structure for running a task on a bg thread- handle a long-running operation without affecting ui responsiveness
AsynTask
is designed for short operationsAsynTask
should not keep UI’s referenceIntentService
need not be cancelled when the activity is rebuilt
- define a
FetchAddressIntentService
extendsIntentService
ResultReceiver
1.4.2.1 Define the intent Service in manifest
<service android:name=".FetchAddressIntentService" android:exported="false" />
1.4.2.2 Create a Geocoder
@Override
protected void onHandleIntent(Intent intent) {
Geocoder geocoder = new Geocoder(this, Locale.getDefault());
}
1.4.2.3 Retrieve the street address data
- define a
Constants
to contain many values - call
getFromLocation()
to get a street address - filter some error cases
Address
providesgetAddressLine()
deliveResultToReceiver()
to send the result back to the requesting activity
1.4.2.4 Reture the address to the requestor
public class FetchAddressIntentService extends IntentService {
protected ResultReceiver receiver;
private void deliverResultToReceiver(int resultCode, String msg) {
Bundle bundle = new Bundle();
bundle.putString(Contants.RESULT_DATA_KEY, msg);
receiver.send(resultCode, bundle);
1.4.3 Start the intent Service
Intent intent = new Intent(this, FetchAddressIntentService.class);
intent.putExtra(Constants.RECEIVER, mResultReceiver);
intent.putExtra(Constants.LOCATION_DATA_EXTRA, mLastLocation);
startService(intent);
1.4.4 Receive the geocoding results
class AddressResultReceiver extends ResultReceiver {
public AddressResultReceiver(Handler handler) {
super(handler);
}
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
// Display the address string
// or an error message sent from the intent service.
mAddressOutput = resultData.getString(Constants.RESULT_DATA_KEY);
displayAddressOutput();
// Show a toast message if an address was found.
if (resultCode == Constants.SUCCESS_RESULT) {
showToast(getString(R.string.address_found));
}
}
}