Skip to content

Commit 455d795

Browse files
Fix failing location activities (mapbox#307)
* change old locations services with new location engine * hold a weak reference of the context to avoid leaks * fix geocoding service activity using an Android location engine * remove useless code from on location change method (not requesting location updates) * add comment to indicate explicitly that on location change method is not used on purpose
1 parent 4923ce6 commit 455d795

6 files changed

Lines changed: 153 additions & 102 deletions

File tree

mapbox/app/src/main/java/com/mapbox/services/android/testapp/geocoding/GeocodingServiceActivity.java

Lines changed: 99 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.mapbox.services.android.testapp.geocoding;
22

3+
import android.content.Context;
34
import android.content.Intent;
45
import android.location.Location;
56
import android.os.Bundle;
@@ -13,49 +14,52 @@
1314
import android.widget.Toast;
1415

1516
import com.mapbox.services.android.geocoder.AndroidGeocoder;
17+
import com.mapbox.services.android.telemetry.location.AndroidLocationEngine;
18+
import com.mapbox.services.android.telemetry.location.LocationEngine;
19+
import com.mapbox.services.android.telemetry.location.LocationEngineListener;
1620
import com.mapbox.services.android.testapp.R;
1721
import com.mapbox.services.android.testapp.geocoding.service.Constants;
1822
import com.mapbox.services.android.testapp.geocoding.service.FetchAddressIntentService;
19-
import com.mapzen.android.lost.api.LocationServices;
20-
import com.mapzen.android.lost.api.LostApiClient;
23+
24+
import java.lang.ref.WeakReference;
2125

2226
/**
2327
* This activity is inspired by the stock Android Geocoder sample code in
2428
* https://github.com/googlesamples/android-play-location/tree/master/LocationAddress
2529
* <p>
26-
* In this sample, we show how to use Mapbox' Geocoder simply replacing the
30+
* In this sample, we show how to use Mapbox's Geocoder simply replacing the
2731
* android.location.Geocoder object with com.mapbox.services.android.geocoder.AndroidGeocoder.
28-
* To simplify the code, we've replaced Google Play Services with LOST.
32+
* To simplify the code, we've replaced Google Play Services with Android.
2933
*/
30-
public class GeocodingServiceActivity extends AppCompatActivity {
34+
public class GeocodingServiceActivity extends AppCompatActivity implements LocationEngineListener {
3135

32-
protected static final String ADDRESS_REQUESTED_KEY = "address-request-pending";
33-
protected static final String LOCATION_ADDRESS_KEY = "location-address";
36+
private static final String ADDRESS_REQUESTED_KEY = "address-request-pending";
37+
private static final String LOCATION_ADDRESS_KEY = "location-address";
3438

3539
/**
36-
* Provides the entry point to LOST services.
40+
* Provides the entry point to location services.
3741
*/
38-
protected LostApiClient lostApiClient;
42+
private LocationEngine locationEngine;
3943

4044
/**
4145
* Represents a geographical location.
4246
*/
43-
protected Location lastLocation;
47+
private Location lastLocation;
4448

4549
/**
4650
* Tracks whether the user has requested an address. Becomes true when the user requests an
4751
* address and false when the address (or an error message) is delivered.
4852
* The user requests an address by pressing the Fetch Address button. This may happen
49-
* before LostApiClient connects. This activity uses this boolean to keep track of the
53+
* before location engine connects. This activity uses this boolean to keep track of the
5054
* user's intent. If the value is true, the activity tries to fetch the address as soon as
51-
* LostApiClient connects.
55+
* location engine connects.
5256
*/
53-
protected boolean addressRequested;
57+
private static boolean addressRequested;
5458

5559
/**
5660
* The formatted location address.
5761
*/
58-
protected String addressOutput;
62+
private static String addressOutput;
5963

6064
/**
6165
* Receiver registered with this activity to get the response from FetchAddressIntentService.
@@ -65,36 +69,37 @@ public class GeocodingServiceActivity extends AppCompatActivity {
6569
/**
6670
* Displays the location address.
6771
*/
68-
protected TextView locationAddressTextView;
72+
private TextView locationAddressTextView;
6973

7074
/**
7175
* Visible while the address is being fetched.
7276
*/
73-
ProgressBar progressBar;
77+
private ProgressBar progressBar;
7478

7579
/**
7680
* Kicks off the request to fetch an address when pressed.
7781
*/
78-
Button fetchAddressButton;
82+
private Button fetchAddressButton;
7983

8084
@Override
8185
public void onCreate(Bundle savedInstanceState) {
8286
super.onCreate(savedInstanceState);
8387
setContentView(R.layout.activity_geocoding_service);
8488

85-
resultReceiver = new AddressResultReceiver(new Handler());
86-
8789
locationAddressTextView = (TextView) findViewById(R.id.location_address_view);
8890
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
8991
fetchAddressButton = (Button) findViewById(R.id.fetch_address_button);
9092

93+
resultReceiver = new AddressResultReceiver(new Handler(), this, locationAddressTextView, progressBar,
94+
fetchAddressButton);
95+
9196
// Set defaults, then update using values stored in the Bundle.
9297
addressRequested = false;
9398
addressOutput = "";
9499
updateValuesFromBundle(savedInstanceState);
95100

96-
updateUiWidgets();
97-
buildLostApiClient();
101+
updateUiWidgets(addressRequested, progressBar, fetchAddressButton);
102+
buildAndroidLocationEngine();
98103
}
99104

100105
/**
@@ -111,48 +116,51 @@ private void updateValuesFromBundle(Bundle savedInstanceState) {
111116
// and stored in the Bundle. If it was found, display the address string in the UI.
112117
if (savedInstanceState.keySet().contains(LOCATION_ADDRESS_KEY)) {
113118
addressOutput = savedInstanceState.getString(LOCATION_ADDRESS_KEY);
114-
displayAddressOutput();
119+
displayAddressOutput(locationAddressTextView);
115120
}
116121
}
117122
}
118123

119124
/**
120-
* Builds a LostApiClient.
125+
* Builds Android location engine
121126
*/
122-
protected synchronized void buildLostApiClient() {
123-
lostApiClient = new LostApiClient.Builder(this).build();
127+
private synchronized void buildAndroidLocationEngine() {
128+
locationEngine = AndroidLocationEngine.getLocationEngine(this);
129+
locationEngine.addLocationEngineListener(this);
130+
locationEngine.activate();
124131
}
125132

126133
/**
127134
* Runs when user clicks the Fetch Address button. Starts the service to fetch the address if
128-
* LostApiClient is connected.
135+
* location engine is connected.
129136
*/
130137
public void fetchAddressButtonHandler(View view) {
131-
// We only start the service to fetch the address if LostApiClient is connected.
132-
if (lostApiClient.isConnected() && lastLocation != null) {
138+
// We only start the service to fetch the address if location engine is connected.
139+
if (locationEngine.isConnected() && lastLocation != null) {
133140
startIntentService();
134141
}
135142

136-
// If LostApiClient isn't connected, we process the user's request by setting
137-
// addressRequested to true. Later, when LostApiClient connects, we launch the service to
143+
// If location engine isn't connected, we process the user's request by setting
144+
// addressRequested to true. Later, when location engine connects, we launch the service to
138145
// fetch the address. As far as the user is concerned, pressing the Fetch Address button
139146
// immediately kicks off the process of getting the address.
140147
addressRequested = true;
141-
updateUiWidgets();
148+
updateUiWidgets(addressRequested, progressBar, fetchAddressButton);
142149
}
143150

144151
@Override
145-
protected void onStart() {
146-
super.onStart();
147-
lostApiClient.connect();
148-
getLastLocation();
152+
protected void onResume() {
153+
super.onResume();
154+
if (locationEngine != null && locationEngine.isConnected()) {
155+
obtainLastAddress();
156+
}
149157
}
150158

151-
private void getLastLocation() {
159+
private void obtainLastAddress() {
152160
// Gets the best and most recent location currently available, which may be null
153161
// in rare cases when a location is not available.
154-
//noinspection MissingPermission
155-
lastLocation = LocationServices.FusedLocationApi.getLastLocation(lostApiClient);
162+
163+
lastLocation = locationEngine.getLastLocation();
156164
if (lastLocation != null) {
157165
// Determine whether a Geocoder is available.
158166
if (!AndroidGeocoder.isPresent()) {
@@ -161,29 +169,40 @@ private void getLastLocation() {
161169
}
162170

163171
// It is possible that the user presses the button to get the address before the
164-
// LostApiClient object successfully connects. In such a case, addressRequested
172+
// location engine object successfully connects. In such a case, addressRequested
165173
// is set to true, but no attempt is made to fetch the address (see
166174
// fetchAddressButtonHandler()) . Instead, we start the intent service here if the
167-
// user has requested an address, since we now have a connection to LostApiClient.
175+
// user has requested an address, since we now have a connection to location engine.
168176
if (addressRequested) {
169177
startIntentService();
170178
}
171179
}
172180
}
173181

174182
@Override
175-
protected void onStop() {
176-
super.onStop();
177-
if (lostApiClient.isConnected()) {
178-
lostApiClient.disconnect();
183+
public void onConnected() {
184+
obtainLastAddress();
185+
}
186+
187+
@Override
188+
public void onLocationChanged(Location location) {
189+
// Unused on purpose
190+
}
191+
192+
@Override
193+
protected void onPause() {
194+
super.onPause();
195+
if (locationEngine != null) {
196+
locationEngine.removeLocationEngineListener(this);
197+
locationEngine.deactivate();
179198
}
180199
}
181200

182201
/**
183202
* Creates an intent, adds location data to it as an extra, and starts the intent service for
184203
* fetching an address.
185204
*/
186-
protected void startIntentService() {
205+
private void startIntentService() {
187206
// Create an intent for passing to the intent service responsible for fetching the address.
188207
Intent intent = new Intent(this, FetchAddressIntentService.class);
189208

@@ -202,28 +221,28 @@ protected void startIntentService() {
202221
/**
203222
* Updates the address in the UI.
204223
*/
205-
protected void displayAddressOutput() {
206-
locationAddressTextView.setText(addressOutput);
224+
private static void displayAddressOutput(TextView view) {
225+
view.setText(addressOutput);
207226
}
208227

209228
/**
210229
* Toggles the visibility of the progress bar. Enables or disables the Fetch Address button.
211230
*/
212-
private void updateUiWidgets() {
231+
private static void updateUiWidgets(boolean addressRequested, ProgressBar progressBar, Button button) {
213232
if (addressRequested) {
214233
progressBar.setVisibility(ProgressBar.VISIBLE);
215-
fetchAddressButton.setEnabled(false);
234+
button.setEnabled(false);
216235
} else {
217236
progressBar.setVisibility(ProgressBar.GONE);
218-
fetchAddressButton.setEnabled(true);
237+
button.setEnabled(true);
219238
}
220239
}
221240

222241
/**
223-
* Shows a toast with the given text.
242+
* Shows a toast with the given message.
224243
*/
225-
protected void showToast(String text) {
226-
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
244+
private static void showToast(Context context, String message) {
245+
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
227246
}
228247

229248
@Override
@@ -239,9 +258,19 @@ public void onSaveInstanceState(Bundle savedInstanceState) {
239258
/**
240259
* Receiver for data sent from FetchAddressIntentService.
241260
*/
242-
class AddressResultReceiver extends ResultReceiver {
243-
public AddressResultReceiver(Handler handler) {
261+
private static class AddressResultReceiver extends ResultReceiver {
262+
private final WeakReference<Context> contextReference;
263+
private final WeakReference<TextView> textViewReference;
264+
private final WeakReference<ProgressBar> progressBarReference;
265+
private final WeakReference<Button> fetchAddressButtonReference;
266+
267+
public AddressResultReceiver(Handler handler, Context context, TextView resultTextView, ProgressBar progressBar,
268+
Button fetchAddressButton) {
244269
super(handler);
270+
this.contextReference = new WeakReference<>(context);
271+
this.textViewReference = new WeakReference<>(resultTextView);
272+
this.progressBarReference = new WeakReference<>(progressBar);
273+
this.fetchAddressButtonReference = new WeakReference<>(fetchAddressButton);
245274
}
246275

247276
/**
@@ -251,16 +280,28 @@ public AddressResultReceiver(Handler handler) {
251280
protected void onReceiveResult(int resultCode, Bundle resultData) {
252281
// Display the address string or an error message sent from the intent service.
253282
addressOutput = resultData.getString(Constants.RESULT_DATA_KEY);
254-
displayAddressOutput();
283+
TextView view = textViewReference.get();
284+
if (view != null) {
285+
displayAddressOutput(view);
286+
}
255287

256288
// Show a toast message if an address was found.
257289
if (resultCode == Constants.SUCCESS_RESULT) {
258-
showToast(getString(R.string.address_found));
290+
Context context = contextReference.get();
291+
if (context != null) {
292+
String message = context.getString(R.string.address_found);
293+
showToast(context, message);
294+
}
259295
}
260296

261297
// Reset. Enable the Fetch Address button and stop showing the progress bar.
262298
addressRequested = false;
263-
updateUiWidgets();
299+
300+
ProgressBar progressBar = progressBarReference.get();
301+
Button fetchAddressButton = fetchAddressButtonReference.get();
302+
if (progressBar != null && fetchAddressButton != null) {
303+
updateUiWidgets(addressRequested, progressBar, fetchAddressButton);
304+
}
264305
}
265306
}
266307

0 commit comments

Comments
 (0)