Reverse Geocoding using HERE maps SDK gives error - android

I am trying to retrieve Address for a particular GeoCoordinate using Reverse Geo coding, But I am getting some errors in executing the Reverse GeoCode Request. I am getting Error:400 Bad Request. Here is my full code:
public class Address_Service extends AppCompatActivity {
String Location1,Address;
double Lat,Lng;
private ListView list;
private boolean isMapInitialized = false;
//LIST OF ARRAY STRINGS WHICH WILL SERVE AS LIST ITEMS
ArrayList<String> listItems=new ArrayList<String>();
//DEFINING A STRING ADAPTER WHICH WILL HANDLE THE DATA OF THE LISTVIEW
ArrayAdapter<String> adapter;
private BroadcastReceiver BUS_COD=new BroadcastReceiver() { //this receiver recieves new location from Database service
#Override
public void onReceive(Context context, Intent intent) {
Location1=intent.getStringExtra("BUS_LOC");
Lat = Double.valueOf(Location1.substring(0, 9));//extracting latitude
Lng = Double.valueOf(Location1.substring(10, Location1.length()));//extracting longitude
Log.e("Got new loc from FB",Location1);
get_address();
}
};
public void get_address()
{
ReverseGeocodeRequest2 request = new ReverseGeocodeRequest2(new GeoCoordinate(Lat,Lng,0.0));
request.execute(new ResultListener<com.here.android.mpa.search.Location>() {
#Override
public void onCompleted(com.here.android.mpa.search.Location location, ErrorCode errorCode) {
if(errorCode!=ErrorCode.NONE){
Log.e("Error",errocode.getmessage());
}else{
if (location != null) {
Address = location.getAddress().toString();
listItems.add(Address_of_Bus);
}
}
}
});
}
#Override
protected void onCreate( Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.reverse_geocode_layout);
list=(ListView) (findViewById(R.id.listView));
adapter=new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,listItems);
list.setAdapter(adapter);
initialize();
}
public void initialize() {
MapEngine mapEngine= MapEngine.getInstance();
mapEngine.init(this, new OnEngineInitListener() {
#Override
public void onEngineInitializationCompleted(Error error) {
if (error == OnEngineInitListener.Error.NONE) {
IntentFilter intentFilter=new IntentFilter();
intentFilter.addAction("GOT_NEW_L_M");
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(BUS_COD,intentFilter);
Intent intent=new Intent(Address_Service.this,Database_service.class);
startService(intent);
isMapInitialized = true;
} else {
Log.e("Initialization", "ERROR: Cannot initialize Map Fragment");
}
}
});
}
#Override
protected void onDestroy() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(BUS_COD);
this.stopService(new Intent(Address_Service.this,Database_service.class));
super.onDestroy();
}
#Override
protected void onPause() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(BUS_COD);
super.onPause();
}
#Override
protected void onResume()
{
IntentFilter intentFilter=new IntentFilter();
intentFilter.addAction("GOT_NEW_L_M");
LocalBroadcastManager.getInstance(this).registerReceiver(BUS_COD,intentFilter);
super.onResume();
}
}
And this is the Logcat with Error:
E/NativeCrypto: ssl=0x5466b490 cert_verify_callback calling
verifyCertificateChain authMethod=ECDHE_RSA
09-27 17:24:35.352 3554-3770/
E/NETWORK: Request:
https://places.hybrid.api.here.com/places/v1/meta/offline?
app_id=HxZCZftG2X5aQ0Bhlg1W&app_code=TF3wLtVoLtqhmTi1FOcSaw Error: 400 Bad
Request
I am using this on real device operating at API19.I am actually populating listView with addresses received via Reverse Geocoding.
Here is my layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="1">
<ListView
android:layout_width="match_parent"
android:layout_height="430dp"
android:layout_marginTop="30dp"
android:layout_gravity="center"
android:id="#+id/listView" />
</LinearLayout>

HERE provides different product which are covering also specific features and capabilities:
Forward geocoding
Reverse geocoding
Multi-reverse geocoding
Batch geocoding
Geocoding autocomplete
Places (Search)
Please have a look here for an overview: https://developer.here.com/products/geocoding-and-search

Related

Android is messing up my views by redrawing the same element without any invalidation

Due to some issue, ALL ACTIVITIES in my app are being redrawn and look something similar to the image below. A hacky workaround for me was to add an ImageView as the lowest layer, with the same height and width as parent and use it as a background, which seems to stop this issue from happening. I am attaching the code from one activity here, but please note, this happens across all activities, regardless of the activity extended the BaseActivity class.
The BaseActivityClass is as follows:
public class BaseActivity extends AppCompatActivity implements
GoogleApiClient.OnConnectionFailedListener {
protected GoogleApiClient mGoogleApiClient;
protected Firebase.AuthStateListener mAuthListener;
protected Firebase mFirebaseRef;
protected FirebaseWrapper mFirebaseWrapper;
protected String mProvider;
protected String mEmail;
protected GSharedPreferences mSharedPref;
protected Location mCurrentLocation = null;
// Permission related variables
protected static final int FINE_LOCATION = 100;
protected View mLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSharedPref = GSharedPreferences.getInstance();
// Allow google logins
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.build();
// Create new Client API
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this /* FragmentActivity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.addApi(LocationServices.API)
.build();
mFirebaseWrapper = FirebaseWrapper.getInstance(mGoogleApiClient);
mGoogleApiClient.connect();
if (!((this instanceof LoginActivity) || (this instanceof CreateAccountActivity))) {
mFirebaseRef = new Firebase(Constants.FIREBASE_URL);
mAuthListener = new Firebase.AuthStateListener() {
#Override
public void onAuthStateChanged(AuthData authData) {
if (authData == null) {
kickUserOut();
}
}
};
mFirebaseRef.addAuthStateListener(mAuthListener);
}
// Get the provider and email if set. A null value means the user is not yet authenticated.
mEmail = mSharedPref.getPreference(Constants.ID_SHAREDPREF_EMAIL);
mProvider = mSharedPref.getPreference(Constants.ID_SHAREDPREF_PROVIDER);
requestAllPermissions();
}
#Override
protected void onStop() {
super.onStop();
}
#Override
protected void onStart() {
super.onStart();
}
#Override
public void onDestroy() {
super.onDestroy();
// The Auth listener is created only when the user is not a part of the login or
// create account activity, do the cleanup only in such cases.
if (!((this instanceof LoginActivity) || (this instanceof CreateAccountActivity))) {
mFirebaseRef.removeAuthStateListener(mAuthListener);
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_base, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
super.onBackPressed();
return true;
}
if (id == R.id.action_logout) {
logout();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
#Override
protected void onResume() {
super.onResume();
mSharedPref.writePreference(Constants.CAN_SHOW_NOTIFICATION, Constants.NO);
// mSharedPref.writePreference(Constants.ID_SHAREDPREF_CANGOOFFLINE, Constants.NO);
}
#Override
protected void onPause() {
super.onPause();
mSharedPref.writePreference(Constants.CAN_SHOW_NOTIFICATION, Constants.YES);
}
/**
* This is called from the child activities that are not associated
* with login or account creation flows.
*/
protected void logout() {
Toast.makeText(this, "Attemping to logout.", Toast.LENGTH_LONG);
// mProvider is set only after the user logs in successfully.
if (mProvider != null) {
mFirebaseRef.unauth();
if (mProvider.equals(Constants.GOOGLE_AUTH_PROVIDER)) {
Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback(
new ResultCallback<Status>() {
#Override
public void onResult(Status status) {
// We do not intend to do anything after logout.
// Ignore.
}
});
}
}
}
private void kickUserOut() {
mSharedPref.clear();
// Shared prefs store data about email, clear that and kick users out by moving them
// to login screen.
Intent intent = new Intent(BaseActivity.this, LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
finish();
}
protected void showToast(String aText) {
Toast.makeText(this, aText, Toast.LENGTH_SHORT).show();
}
public void requestAllPermissions() {
mLayout = findViewById(R.id.main_layout);
if(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
Log.i("MainActivity",
"Displaying location permission rationale to provide additional context.");
Snackbar.make(mLayout, R.string.permission_location_rationale,
Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.ok, new View.OnClickListener() {
#Override
public void onClick(View view) {
ActivityCompat.requestPermissions(BaseActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
FINE_LOCATION);
}
})
.show();
} else {
// Location permission has not been granted yet. Request it directly.
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
FINE_LOCATION);
}
}
}
protected LatLng getCurrentLocation()
{
Location currentLocation = LocationServices.FusedLocationApi.getLastLocation(
mGoogleApiClient);
float lat = (float) (currentLocation == null ? -190.00: currentLocation.getLatitude());
float lon = (float) (currentLocation == null ? -190.00: currentLocation.getLongitude());
return new LatLng(lat, lon);
}
}
I have a PreferenceActivity, which has the same issue and looks like the image attached.
public class SettingsActivity extends PreferenceActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction().replace(android.R.id.content, new MyPreferenceFragment()).commit();
}
public static class MyPreferenceFragment extends PreferenceFragment
{
#Override
public void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.layout.activity_settings);
}
}
}
Doing the following (adding ImageView as the first child, encompassing the whole view as background) fixes this issue.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/main_layout">
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="centerCrop"
android:src="#drawable/bg2"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="#+id/list_view_actions_list"
android:drawSelectorOnTop="true"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:dividerHeight="2dp"
android:scrollbars="none" />
</LinearLayout>
</RelativeLayout>
I would appreciate any hints/leads as to what could I have done wrong and how to fix this. If I give an ImageView as a background, then everything works, but I don't want to always stick to a hacky way of fixing the issue. Moreover, the ImageView fix works only when it's a RelativeLayout.
(Incase you are interested in seeing my code it's hosted on github.
My code is hosted at https://github.com/neerajcse/dstudio/.

Listview does not automatically refresh after getting list data from DataStore

I have a ListView which I populate with data from DataStore or from my local database.
I am checking some condition that will determine whether I will fetch data from the DataStore or database. When I fetch from the database the ListView automatically refreshes itself, but when I fetch from the DataStore it does not. I then have to click my TextView, which is below ListView, and when I click it the soft keyboard appears and then my ListView is populated with data from DataStore.
My activity that has the ListView:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_xyz);
list_View = (ListView) findViewById(R.id.data_listView);
list_View.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
list_View.setMultiChoiceModeListener(new Selector());
adapter = new MyAdapter(context,Long.valueOf(id),isOnline());
list_View.setAdapter(adapter);
list_View.setSelection(adapter.getCount() - 1);
adapter.registerDataSetObserver(new DataSetObserver() {
#Override
public void onChanged() {
super.onChanged();
list_View.setSelection(adapter.getCount() - 1);
}
LoadDataTask ldt = new LoadDataTask();
ldt.execute("123456789");
}
private void loadDataFromDataStore(final Long contactId){
final ArrayList<Data> data = new ArrayList<>();;
d("loadingdataFromDatasore");
GetDataTask task = new GetDataTask(new ApiTask.ResultListener() {
#Override
public void successHook(Object o) {
if (o instanceof GetDataResponse) {
GetDataResponse res = (GetDataResponse) o;
if (res.getData() != null && res.getData().getItems() != null) {
for (ListDataItem i : res.getData().getItems()) {
Data dp = new Data(i.getPosition(), i.getMessage(), i.getDateCreated(),i.getMessageId(),1);
adapter.addFromOtherThread(dp);
}
}
d("Messages loaded from server: " + adapter.getCount());
}
}
}
public class LoadDataTask extends AsyncTask<String,String,Void> {
#Override
protected Void doInBackground(String... params){
if(isOnline && isFirstTime){
loadDataFromDataStore(Long.valueOf(params[0]));
}else{
//load from database
}
return null;
}
#Override
protected void onPostExecute(Void v){
adapter.notifyDataSetChanged();
}
}
My adapter class that extends BaseAdapter (I have removed unnecessary code for this question):
public class DataAdapter extends BaseAdapter {
private ArrayList<Data>data_list;
public DataAdapter(){
data_list = new ArrayList<>();
}
public void addFromOtherThread(Data object) {
data_list.add(object);
}
What am I missing that is making listview not to automatically refresh itself even after calling notifyDatasetChanged()?
change :
#Override
protected void onPostExecute(Void v){
adapter.notifyDataSetChanged();
}
}
to:
#Override
protected void onPostExecute(Void v){
adapter.notifyDataSetChanged();
list_View.setAdapter(adapter);
}
}
Let me know if more clarification is required by commenting below.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_xyz);
list_View = (ListView) findViewById(R.id.data_listView);
list_View.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
list_View.setMultiChoiceModeListener(new Selector());
adapter = new MyAdapter(context,Long.valueOf(id),isOnline());
list_View.setAdapter(adapter);
list_View.setSelection(adapter.getCount() - 1);
adapter.registerDataSetObserver(new DataSetObserver() {
#Override
public void onChanged() {
super.onChanged();
list_View.setSelection(adapter.getCount() - 1);
}
loadDataFromDataStore("123456789")
}
private void loadDataFromDataStore(final Long contactId){
final ArrayList<Data> data = new ArrayList<>();;
d("loadingdataFromDatasore");
new GetDataTask(new ApiTask.ResultListener() {
#Override
public void successHook(Object o) {
if (o instanceof GetDataResponse) {
GetDataResponse res = (GetDataResponse) o;
if (res.getData() != null && res.getData().getItems() != null) {
for (ListDataItem i : res.getData().getItems()) {
Data dp = new Data(i.getPosition(), i.getMessage(), i.getDateCreated(),i.getMessageId(),1);
adapter.addFromOtherThread(dp);
}
}
d("Messages loaded from server: " + adapter.getCount());
adapter.notifyDatasetChanges();
}
}
}.execute();
}
GetDataTask should work on background internally you don't need to starts a AsyncTask from here.
If you want to use AsyncTask then your AsyncTask should wait for the result from GetDataTask which it is not doing in your code implementation.
I don't know which kind of framework you are using to making api call but your implementation seems to look wrong.
I have write the code on assumption bases if your GetDataTask is a AsyncTask or some background processor it will work perfectly.

Android GPS location always null inside AsyncTask

I am trying to get the current location of the user from an asynctask. My application depends on the latitude and longitude values. I am trying to show a ProgressDialog to the user till the location is fetched.
Problem :- The location value is always null. I know that getting gps location takes time. But my location value is null even after waiting for sometimes. Its always null.
Below is my code :-
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//some action …
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
if (id == R.id.action_settings)
{
return true;
}
if(id == R.id.action_location)
{
LocationTask locGetter = new LocationTask(MainActivity.this);
locGetter.execute();
}
return super.onOptionsItemSelected(item);
}
}
Below is my AsyncTask
public class LocationTask extends AsyncTask<Void,Void,Void> implements LocationListener
{
private ProgressDialog dialog;
private Activity callingActivity;
LocationManager locationManager;
String provider = LocationManager.GPS_PROVIDER;
public LocationTask(Activity activity)
{
callingActivity = activity;
}
#Override
protected void onPreExecute()
{
dialog= ProgressDialog.show(callingActivity,"Getting Co-ordinates","Please Wait....");
}
#Override
protected Void doInBackground(Void... voids)
{
locationManager = (LocationManager) callingActivity.getSystemService(Context.LOCATION_SERVICE);
Location location = locationManager.getLastKnownLocation(provider);
showLocation(location);
return null;
}
private void showLocation(Location location)
{
if(location == null)
{
Log.d("Location","Failed to get location");
}
else
{
Log.d("Location","Latitude :- "+location.getLatitude()+" Longitude :- "+location.getLongitude());
}
}
#Override
protected void onPostExecute(Void aVoid)
{
dialog.dismiss();
super.onPostExecute(aVoid);
}
#Override
public void onLocationChanged(Location location)
{
showLocation(location);
}
#Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
#Override
public void onProviderEnabled(String s) {
}
#Override
public void onProviderDisabled(String s) {
}
}
UPDATE :-
As mentioned by Ivan I have modified my AsyncTask to get location as below :-
#Override
protected Void doInBackground(Void... voids) {
locationManager = (LocationManager) callingActivity.getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(provider,0,0,this);
if(locationManager != null) {
Location location = locationManager.getLastKnownLocation(provider);
showLocation(location);
}
return null;
}
But this throws "windows leaked" exception in the dialog= ProgressDialog.show(callingActivity,"Getting Co-ordinates","Please Wait...."); inside onPrexecute() method.
Seems to me that you might be missing the requestLocationUpdates(...) call.
Please check this related question for a better understanding on what might be missing, as it sure doesn't look to be a problem with it being inside an AsyncTask, although I don't really see the need for the AsyncTask in your snippet.
Have you tried using String locationProvider = LocationManager.NETWORK_PROVIDER;
to determine if it's the provider that's the issue?
Ivan has mentioned that you won't get updates, but as I understand you're still just looking for the last known location.

How do you keep track of dependant asynchronous tasks?

I'm making an Android Application at the moment using MVC. I'm using an Activity as a Controller and a different class as the View.
The View is waiting for two asynchronous tasks, a Google Map and a task sent to fetch data from a database. The View needs the data from the database to place a marker on the map. If the map loads first the we can't place the marker. If the database task finishes then we needs to wait for the map to load.
How do I check that the dependant tasks are finished?
Should I just have a flag to say if the db task is finished and then when the map loads check this to continue and vice versa for the map.
Or is there a better way to do all this.
This is a simplified version of the View:
public class SellerAddView
implements OnChangeListener<Model>, OnMapReadyCallback{
...
public SellerAddView(View view, Model model, Activity activity){
model.addListener(this);
mapFragment = ((MapFragment)activity.getFragmentManager()
.findFragmentById(R.id.add_map));
mapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
LatLng coords = model.getLatLng();
map.addMarker(new MarkerOptions().position(coords));
}
#Override
public void onChange(SellerAddModel model) {
updateView();
}
}
Here is the simplified Controller:
public class Controller extends Activity{
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View screenView = View.inflate(this, activity_seller_add, null);
model = new Model();
view = new view(screenView, model, this);
populateModel();
setContentView(screenView);
}
public void populateModel(){
handler.post(new Runnable() {
#Override
public void run() {
synchronized (model) {
Model newModel = new ModelDao().getId(id);
model.consume(model);
}
}
});
}
}
So you can use the Splash screen to wait for all data to be loaded, that will be better.
Sample code as following:
public class SplashScreen extends Activity {
private static int SPLASH_DELEY = 3000;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Intent intent = new Intent(SplashScreen.this, MainActivity.class);
startActivity(intent);
finish();
}
}, SPLASH_DELEY);
}
}
And for activity_splash_screen.xml :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context="com.bjiang.map_ex.SplashScreen">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imageLogo"
android:layout_centerInParent="true"
android:src="#drawable/splash_file"/>
</RelativeLayout>

Geocoder autocomplete in android

I've been googling my ass of trying to find someone that are having the same problem as me, without luck. So here's my problem:
I'm trying to implement a autocomplete suggestion of addresses as the user types the name of a place using the geocoder in Android. I want this to behave much the same as the javascript version using a combbox.
I am using a layout with an AutoCompleteTextView, and an arrayadapter to dynamically update the suggestionlist as the user types. I have added a 500ms delay from when the onTextChanged() event is received before a call to the geocoder.getFromLocationName is called using a Handler. If a user types more letter within 500ms, the last event will be cancelled. The problem I am encountering is that the suggestions almost never show up in the UI as selectables in the dropdown. I get the address suggestions, but when I add them to the adapter attached to the autocomplatetextview they simple wont show.
I'm running this on an emulator using API level 7, with google apis included.
Now some source code to aid you:
The layout:
<LinearLayout android:id="#+id/searchInputLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="6dip"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/searchMessage" />
<EditText android:id="#+id/freetextInput"
android:hint="#string/searchFreetextLabel"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#android:drawable/editbox_background" />
<CheckBox android:id="#+id/includeVincinityCheckbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/includeVincinityLabel"
android:checked="true"
android:onClick="includeVincinityClick" />
<AutoCompleteTextView android:id="#+id/locationInput"
android:hint="#string/locationInputHint"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<Button android:id="#+id/searchButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/searchBtnLabel"
android:onClick="searchBtnClicked" />
</LinearLayout>
The source code of my activity (I've omitted code not relevant):
public class SearchLocationTabActivity extends Activity implements TextWatcher, OnItemSelectedListener {
private static final int MESSAGE_TEXT_CHANGED = 0;
private static final int AUTOCOMPLETE_DELAY = 500;
private static final int THRESHOLD = 3;
private String latitude, longitude;
private List<Address> autoCompleteSuggestionAddresses;
private ArrayAdapter<String> autoCompleteAdapter;
private Handler messageHandler;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.search);
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
messageHandler = new MyMessageHandler(this, this);
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) {
messageHandler.removeMessages(MESSAGE_TEXT_CHANGED);
}
#Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
String value = arg0.toString();
if (!"".equals(value) && value.length() >= THRESHOLD) {
Message msg = Message.obtain(messageHandler, MESSAGE_TEXT_CHANGED, arg0.toString());
messageHandler.sendMessageDelayed(msg, AUTOCOMPLETE_DELAY);
} else {
autoCompleteAdapter.clear();
}
}
#Override
public void afterTextChanged(Editable arg0) {
}
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
if (arg2 < autoCompleteSuggestionAddresses.size()) {
Address selected = autoCompleteSuggestionAddresses.get(arg2);
latitude = Double.toString(selected.getLatitude());
longitude = Double.toString(selected.getLongitude());
}
}
private void notifyResult(List<Address> suggestions) {
latitude = longitude = null;
autoCompleteAdapter.clear();
for (Address a : autoCompleteSuggestionAddresses) {
autoCompleteAdapter.add(a.toString());//TODO: figure out a nice way to display this address in list
}
autoCompleteAdapter.notifyDataSetChanged();
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
latitude = longitude = null;
}
private class MyMessageHandler extends Handler {
private Context context;
private AsyncTaskSubscriber subscriber;
public MyMessageHandler(Context context, AsyncTaskSubscriber subscriber) {
this.context = context;
this.subscriber = subscriber;
}
#Override
public void handleMessage(Message msg) {
if (msg.what == MESSAGE_TEXT_CHANGED) {
String enteredText = (String) msg.obj;
try {
autoCompleteSuggestionAddresses = new Geocoder(context).getFromLocationName(enteredText, 10);
notifyResult(response);
} catch (IOException ex) {
Log.e(GeoCoderAsyncTask.class.getName(), "Failed to get autocomplete suggestions", ex);
}
}
}
}
}
Any help is much appreciated!
For those who did not managed to remove the filtering, here is what I've done (among other small modifications but I don't think they have an impact on the filtering part). Note also that for a click on one of the item to be detected, you need to add an OnItemClickListener.
autoCompleteAdapter = new ArrayAdapterNoFilter(this, android.R.layout.simple_dropdown_item_1line);
Where ArrayAdapterNoFilter is inspired from this other answer:
public class ArrayAdapterNoFilter extends ArrayAdapter<String> {
public ArrayAdapterNoFilter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
}
private static final NoFilter NO_FILTER = new NoFilter();
/**
* Override ArrayAdapter.getFilter() to return our own filtering.
*/
#Override
public Filter getFilter() {
return NO_FILTER;
}
/**
* Class which does not perform any filtering. Filtering is already done by
* the web service when asking for the list, so there is no need to do any
* more as well. This way, ArrayAdapter.mOriginalValues is not used when
* calling e.g. ArrayAdapter.add(), but instead ArrayAdapter.mObjects is
* updated directly and methods like getCount() return the expected result.
*/
private static class NoFilter extends Filter {
protected FilterResults performFiltering(CharSequence prefix) {
return new FilterResults();
}
protected void publishResults(CharSequence constraint, FilterResults results) {
// Do nothing
}
}
}
ok, this one has a really simple solution. The results did not show up all the time because of the filtering mechanism in the AutoCompleteTExtView component. Because all results from the geocoder did not necessarily contain the string typed in, it did not show those results.
This actually works for my geocoding code. I can add the textwatcher to a autocomplete text view, and then get the text and run an async task that will get the list of addresses from googles GeoCode class. Using this no filter array adapter above makes it display the addresses as I type the letters correctly.
Thanks!

Categories

Resources