1

In my effort to get a simple address auto complete on android using geocoder, I tried to my patience and finally decided to ask out for help.

original code reference : Geocoder autocomplete in android

So in the below code, all that is happening is trying to auto complete the address as the user types in the autoCompleteTextView. I am calling the function doing the actual work in runOnUiThread,hoping that the UI would not freeze, as the user types in. However the UI freezes after the Threshold (3 characters) and the drop down of the possible addresses appear at it its own pace and not always.

If you guys can tell me where I am going wrong.... thanks in advance

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.location.Address;
import android.location.Geocoder;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;

public class AlarmActivity extends Activity implements TextWatcher {
private static final int THRESHOLD = 3;
private String latitude, longitude;
private List<Address> autoCompleteSuggestionAddresses;
private ArrayAdapter<String> autoCompleteAdapter;



/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.hw);
    setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
    autoCompleteAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, new ArrayList<String>());
    autoCompleteAdapter.setNotifyOnChange(false);
    AutoCompleteTextView locationinput = (AutoCompleteTextView) findViewById(R.id.locationInput);
    locationinput.addTextChangedListener(this);
    locationinput.setOnItemSelectedListener(this);
    locationinput.setThreshold(THRESHOLD);
    locationinput.setAdapter(autoCompleteAdapter);

}

@Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {

}

@Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
final String value = arg0.toString();

if (!"".equals(value) && value.length() >= THRESHOLD) {

    Thread t = new Thread() {
        public void run() {
            try {

                runOnUiThread(new Runnable() {
                    public void run() {
                        notifyResult(value);
                    }
                });
            } catch (Exception e) {}
        }
    };
    t.start();


} else {
    autoCompleteAdapter.clear();
}
}

@Override
public void afterTextChanged(Editable arg0) {
}


private void notifyResult(String value) {
     try {
            autoCompleteSuggestionAddresses = new Geocoder(getBaseContext()).getFromLocationName(value, 10);

            //notifyResult(autoCompleteSuggestionAddresses);

            latitude = longitude = null;
            autoCompleteAdapter.clear();
            for (Address a : autoCompleteSuggestionAddresses) {
                Log.v("Nohsib", a.toString());
                String temp = ""+ a.getFeatureName()+" "+a.getCountryName()+" "+a.getPostalCode();  

                autoCompleteAdapter.add(temp);
            }
            autoCompleteAdapter.notifyDataSetChanged();



        } catch (IOException ex) {
          //  Log.e(GeoCoderAsyncTask.class.getName(), "Failed to get autocomplete suggestions", ex);
        }

}

}

Community
  • 1
  • 1
Nohsib
  • 3,614
  • 14
  • 51
  • 63

1 Answers1

0

I believe the reason the UI is freezing is because even though you are calling notifyResult from a separate thread, it is still being run on the UI thread. What will fix this is to instead use an AsyncTask

Something like:

private class GetSuggestions extends AsyncTask<String, Void, Void> {
     protected Long doInBackground(String... search) {
         value = search[0];
         try {
        autoCompleteSuggestionAddresses = new Geocoder(getBaseContext()).getFromLocationName(value, 10);

        //notifyResult(autoCompleteSuggestionAddresses);

        latitude = longitude = null;
        autoCompleteAdapter.clear();
        for (Address a : autoCompleteSuggestionAddresses) {
            Log.v("Nohsib", a.toString());
            String temp = ""+ a.getFeatureName()+" "+a.getCountryName()+" "+a.getPostalCode();  

            autoCompleteAdapter.add(temp);
        }

    } catch (IOException ex) {
      //  Log.e(GeoCoderAsyncTask.class.getName(), "Failed to get autocomplete suggestions", ex);
    }
     }

     protected void onPostExecute(Long result) {
         autoCompleteAdapter.notifyDataSetChanged();
     }
 }

and then you can start the task by calling new GetSuggestions().execute(value);

Michaeldcooney
  • 1,435
  • 10
  • 14
  • 1
    @ Michaeldcooney : Thanks for the response. However I had tried this approach and it is giving the exception as edited into your solution. So I tried calling the autoCompleteAdapter.notifyDataSetChanged() via the runOnUiThread ,but that doesnot give the suggestions drop down at all.Any suggestions? – Nohsib May 16 '12 at 01:09
  • if the exception is not visible above : Caused by: android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. – Nohsib May 16 '12 at 01:20
  • If you were wondering, this is crashing because you are modifying the data of your adapter in the async task. You should simply pass the autoCompleteSuggestionAddresses as the return value, and then evaluate and add them to the adapter in the onPostExecute method. So instead of returning a Long, you would have your return type be something like List
    – Jawnnypoo Jan 20 '15 at 20:34