Geocoding with Background Threads

Using background threads to handle time-consuming operations is very common. The general pattern is to handle a UI event (such as a button click) to initiate a timely operation. From the event handler, you create a new thread to execute the work and start the thread. The UI thread then returns to the user interface to handle interaction with the user, while the background thread works. After the background thread completes, a part of the UI might have to be updated or the user might have to be notified. The background thread does not update the UI directly; instead, the background thread notifies the UI thread to update itself. Listing 7-17 demonstrates this idea using geocoding.

Listing 7-17. Geocoding in a Separate Thread import java.io.IOException; import java.util.List;

import android.app.AlertDialog;

import android.app.Dialog;

import android.app.ProgressDialog;

import android.location.Address;

import android.location.Geocoder;

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.EditText;

import com.google.android.maps.GeoPoint; import com.google.android.maps.MapActivity; import com.google.android.maps.MapView;

public class GeocodingWithThreadsDemoActivity extends MapActivity

Geocoder geocoder = null; MapView mapView = null; ProgressDialog progDialog=null; List<Address> addressList=null; ^Override protected boolean isRouteDisplayed() { return false;

^Override protected void onCreate(Bundle icicle) { super.onCreate(icicle);

setContentView(R.layout.geocode); mapView = (MapView)findViewByld(R.id.geoMap); // lat/long of Jacksonville, FL int lat = (int)(30.334954*1000000); int lng = (int)(-8l.5625*1000000); GeoPoint pt = new GeoPoint(lat,lng); mapView.getController().setZoom(l0); mapView.getController().setCenter(pt); mapView.getController().animateTo(pt); //

Button geoBtn =(Button)findViewById(R.id.geocodeBtn); geocoder = new Geocoder(this); //

geoBtn.setOnClickListener(new OnClickListener(){ ^Override public void onClick(View view) {

EditText loc = (EditText)findViewByld(R.id.location); String locationName = loc.getText().toString();

progDialog =

ProgressDialog.show(GeocodingWithThreadsDemoActivity.this, "Processing...", "Finding Location...", true, false);

findLocation(locationName);

private void findLocation(final String locationName) {

// do background work addressList = geocoder.getFromLocationName(locationName, 5); //send message to handler to process results uiCallback.sendEmptyMessage(o);

} catch (IOException e) { e.printStackTrace();

// ui thread callback handler private Handler uiCallback = new Handler() {

^Override public void handleMessage(Message msg) {

progDialog.dismiss();

if(addressList!=null && addressList.size()>0) {

int lat = (int)addressList.get(0).getLatitude()*1000000; int lng = (int)addressList.get(0).getLongitude()*1000000; GeoPoint pt = new GeoPoint(lat,lng); mapView.getController().setZoom(l0); mapView.getController().setCenter(pt); mapView.getController().animateTo(pt);

Dialog foundNothingDlg = new AlertDialog.Builder(GeocodingWithThreadsDemoActivity.this) .setIcon(0)

.setTitle("Failed to Find Location") .setPositiveButton("Ok", null) .setMessage("Location Not Found...") .create();

foundNothingDlg.show();

// geocode.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fin_parent" android:layout_height="fill_parent"> <LinearLayout android:layout_width="fill_parent" android:layout_alignParentBottom="true"

android:layout_height="wrap_content" android:orientation="vertical" >

<EditText android:layout_width="fill_parent" android:id="@+id/location" android:layout_height="wrap_content" android:text="ORLANDO FLORIDA"/>

<Button android:id="@+id/geocodeBtn" android:layout_width="wrap_content"

android:layout_height="wrap_content" android:text="Find Location"/> </LinearLayout>

<com.google.android.maps.MapView android:id="@+id/geoMap" android:clickable="true" android:layout_width="fill_parent" android:layout_height="320px" android:apiKey="PUT_MAPPING-API KEY HERE" />

</RelativeLayout>

Listing 7-17 is a modified version of the example in Listing 7-16. The difference is that now, in the onClick() method, you display a progress dialog and call findLocation() (see Figure 7-10). findLocation() then creates a new thread and calls the start() method, which ultimately results in a call to the thread's run() method. In the run() method, you use the Geocoder class to search for the location. When the search is done, you must post the message to something that knows how to interact with the UI thread, because you need to update the map. Android provides the android.os.Handler class for this purpose. From the background thread, call the uiCallback.sendEmptyMessage(0) to have the UI thread process the results from the search. The code calls the handler's callback, which looks at the addressList returned by the Geocoder. The callback then updates the map with the result or displays an alert dialog to indicate that the search returned nothing. The UI for this example is shown in Figure 7-10.

chapter 7 ■ exploring security AND LOCATION-BASED SERVICES 257

Figure 7-10. Showing a progress window during long operations
0 0

Post a comment