Note that there are some explanatory texts on larger screens.

plurals
  1. POOut-of-sync ArrayAdapter with Autocomplete
    primarykey
    data
    text
    <p>I have 3 classes, I wish to use the autocomplete text box to show user certain data (aka cities) from a web service (rest api). I've used this implementation on various features of my own application, but for some reason, there's a synchronization problem within the textchangedlistener...</p> <p>CitiesArrayAdapter.java (to show a different view, in my case the "city, state"):</p> <pre><code>package com.android.lzgo.adapters; import java.util.ArrayList; import java.util.List; import com.android.lzgo.activities.LiftSearchActivity; import com.android.lzgo.activities.R; import com.android.lzgo.models.City; import com.android.lzgo.models.Lift; import android.app.Activity; import android.content.Context; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; public class CitiesArrayAdapter extends ArrayAdapter&lt;City&gt; { private static final String TAG = CitiesArrayAdapter.class.getName(); private final ArrayList&lt;City&gt; cities; private int viewResourceId; public CitiesArrayAdapter(Context context, int textViewResourceId, ArrayList&lt;City&gt; results) { super(context, textViewResourceId, results); this.cities = results; this.viewResourceId = textViewResourceId; } @Override public View getView(int position, View convertView, ViewGroup parent) { // assign the view we are converting to a local variable View v = convertView; if (v == null) { LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = inflater.inflate(viewResourceId, null); } City i = cities.get(position); Log.d(TAG, "Here is my value: " + i); if (i != null) { TextView tt = (TextView) v.findViewById(android.R.id.text1); Log.d(TAG, "Name: " + i.getName() + ", " + i.getProvince_name()); if (tt != null){ tt.setText("Name: " + i.getName() + ", " + i.getProvince_name()); } } // the view must be returned to our activity return v; } </code></pre> <p>}</p> <p>CitiesResponderFragment.java (this is how I get my values from my rest api):</p> <pre><code>package com.android.lzgo.fragment; import java.util.ArrayList; import java.util.List; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONTokener; import com.android.lzgo.activities.LiftSearchActivity; import com.android.lzgo.definitions.Constants; import com.android.lzgo.models.City; import com.android.lzgo.service.LzgoService; import com.google.gson.Gson; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.widget.ArrayAdapter; import android.widget.Toast; public class CitiesResponderFragment extends LzgoResponderFragment { private static String TAG = CitiesResponderFragment.class.getName(); private List&lt;City&gt; mCities; ArrayAdapter&lt;City&gt; adapter; private String enteredCharacters; LiftSearchActivity activity; @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); activity = (LiftSearchActivity) getActivity(); // This gets called each time our Activity has finished creating itself. getCities(); } private void getCities() { if (mCities == null &amp;&amp; activity != null) { Intent intent = new Intent(activity, LzgoService.class); intent.setData(Uri.parse(Constants.REST_CITIES_AUTOCOMPLETE)); Bundle params = new Bundle(); params.putString("search", getenteredCharacters()); intent.putExtra(LzgoService.EXTRA_HTTP_VERB, LzgoService.GET); intent.putExtra(LzgoService.EXTRA_PARAMS, params); intent.putExtra(LzgoService.EXTRA_RESULT_RECEIVER, getResultReceiver()); // Here we send our Intent to our RESTService. activity.startService(intent); } } @Override public void onRESTResult(int code, String result) { Log.e(TAG, Integer.toString(code)); Log.e(TAG, result); // Check to see if we got an HTTP 200 code and have some data. if (code == 200 &amp;&amp; result != null) { mCities = getCitiessFromJson(result); adapter = activity.getArrayAdapter(); adapter.clear(); for( City city : mCities){ //debugging Log.d(TAG, "City : " + city.getName()); adapter.add(city); adapter.notifyDataSetChanged(); } getCities(); } else { Activity activity = getActivity(); if (activity != null &amp;&amp; code == 400) { Toast.makeText(activity, result, Toast.LENGTH_SHORT).show(); } else Toast.makeText(activity, "Failed to load lzgo data. Check your internet settings.", Toast.LENGTH_SHORT).show(); } } private List&lt;City&gt; getCitiessFromJson(String json) { ArrayList&lt;City&gt; cityList = new ArrayList&lt;City&gt;(); Gson gson = new Gson(); try { JSONObject citiesWrapper = (JSONObject) new JSONTokener(json).nextValue(); JSONArray cities = citiesWrapper.getJSONArray("cities"); for (int i = 0; i &lt; cities.length(); i++) { //JSONObject city = cities.getJSONObject(i); String jsonCity = cities.getString(i); City city = gson.fromJson( jsonCity, City.class ); //Log.e(TAG, "Hurray! Parsed json:" + city.getString("name")); //cityList.add(city.getString("name")); cityList.add(city); } } catch (JSONException e) { Log.e(TAG, "Failed to parse JSON.", e); } return cityList; } public String getenteredCharacters() { return enteredCharacters; } public void setenteredCharacters(String characters) { this.enteredCharacters = characters; } } </code></pre> <p>LiftSearchActivity.java (My FragmentActivity):</p> <pre><code>package com.android.lzgo.activities; import java.util.ArrayList; import com.android.lzgo.adapters.CitiesArrayAdapter; import com.android.lzgo.fragment.CitiesResponderFragment; import com.android.lzgo.models.City; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.text.Editable; import android.text.TextWatcher; import android.util.Log; import android.view.View; import android.widget.AutoCompleteTextView; import android.widget.DatePicker; public class LiftSearchActivity extends FragmentActivity{ private static final String TAG = LiftSearchActivity.class.getName(); // User lift input private AutoCompleteTextView autoCityFrom; private AutoCompleteTextView autoCityTo; private DatePicker date; private CitiesArrayAdapter adapter; private ArrayList&lt;City&gt; mCities ; int year , month , day; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.lift_search); mCities = new ArrayList&lt;City&gt;(); adapter = new CitiesArrayAdapter(this, android.R.layout.simple_dropdown_item_1line, mCities); autoCityFrom = (AutoCompleteTextView) findViewById(R.id.cityFrom); autoCityTo = (AutoCompleteTextView) findViewById(R.id.cityTo); adapter.setNotifyOnChange(true); autoCityFrom.setAdapter(adapter); autoCityTo.setAdapter(adapter); autoCityFrom.addTextChangedListener(new TextWatcher() { public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { // no need to do anything } public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { if (((AutoCompleteTextView) autoCityFrom).isPerformingCompletion()) { return; } if (charSequence.length() &lt; 2) { return; } String query = charSequence.toString(); getCities(query); } public void afterTextChanged(Editable editable) { } }); autoCityTo.addTextChangedListener(new TextWatcher() { public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { // no need to do anything } public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { if (((AutoCompleteTextView) autoCityTo).isPerformingCompletion()) { return; } if (charSequence.length() &lt; 2) { return; } String query = charSequence.toString(); getCities(query); } public void afterTextChanged(Editable editable) { } }); date = (DatePicker) findViewById(R.id.dpResult); } public void searchLifts(View view) { Intent intent = new Intent(this, LiftsResultActivity.class); //While autocomplete doesn't work hardcore value... intent.putExtra("from", Integer.toString(9357)); // Sherbrooke intent.putExtra("to", Integer.toString(6193)); // Montreal intent.putExtra("date", Integer.toString(date.getMonth()+1) + "-" + Integer.toString(date.getDayOfMonth()) + "-" + Integer.toString(date.getYear())); startActivity(intent); } public void getCities(String query) { FragmentManager fm = getSupportFragmentManager(); FragmentTransaction ft = fm.beginTransaction(); CitiesResponderFragment responder = (CitiesResponderFragment) fm.findFragmentByTag("RESTResponder"); responder = new CitiesResponderFragment(); responder.setenteredCharacters(query); ft.add(responder, "RESTResponder"); ft.commit(); } public CitiesArrayAdapter getArrayAdapter() { // TODO Auto-generated method stub return adapter; } } </code></pre> <p>I get the correct result and all. But my service doesn't seem to populate my array adapter in my activity, when I try to show my first "city", my adapter contains nothing. I wonder if I have to put a notifydatasetchanged (I tried, but doesn't work). I'm kind of confuse... any pointers?</p> <p>While debugging the application I noticed that the properties mObjects of the ArrayAdapter is cleared even if the associated ArrayList has elements, and then properties mOriginalValues is filled with the Strings loaded the first time.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload