I have an Activity where a user types in an EditText, hits a search button, and the app queries a web service and places the results in a ListView.
I'd like to do away with the search button.
Obviously I don't want every character the user types to hit the web service. I want to only execute 1 web service call when the user is finished typing.
The way I'm achieving this is like so:
I have a member variable which holds an AsyncTask. When the text in the EditText changes, the AsyncTask fires. Inside doInBackground(), a call to Thread.sleep() is hit. This sleep period is essentially a timer waiting to see if the user types anything else. After the sleep call, the call to the web service is made if the AsyncTask has not been cancelled. If the user types another letter, cancel() is called on the AsyncTask (to stop the web service from being called), the member variable holding the AsyncTask is set to null, and a new instance of the AsyncTask is created.
I have a few questions here: Am I leaking memory? Is this particularly bad in any way? I understand it may not be most efficient, but am I going to seriously slow down someone's phone? Is there a better way of doing this?
private SearchTask mSearchTask = null;
...
mSearchText.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Auto-generated method stub
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// Auto-generated method stub
}
public void afterTextChanged(Editable s) {
if (s != null && s.length() > 0) {
// stop any current search thread
if (mSearchTask != null && !mSearchTask.isCancelled()) {
mSearchTask.cancel(false);
}
// search for products
SearchCriteria crit = new SearchCriteria();
crit.strSearchWord = mSearchText.getText().toString().trim();
mSearchTask = null;
mSearchTask = new SearchTask();
mSearchTask.execute(crit);
}
}
});
...
private class SearchTask extends AsyncTask<SearchCriteria, Integer, Boolean> {
protected Boolean doInBackground(SearchCriteria... params) {
SearchCriteria crit = null;
if (params.length > 0) {
crit = params[0];
if (crit != null) {
try {
Thread.sleep(1000L);
if (!isCancelled()) {
// perform search
return true;
}
}
catch(Exception e) {
}
}
}
return false;
}
protected void onPostExecute(Boolean success) {
if (success != null && success == true) {
// do something
}
else {
// do something else
}
}
}
I would be more tempted to launch a thread in x milliseconds and do the check then, as opposed to launching the thread immediately with a sleep in there.
private Handler mMessageHandler = new Handler();
private Runnable mSearchRunnable = new Runnable() {
public void run() {
if (!isCancelled()) {
// perform search
}
}
};
then you can put this in you afterTextChanged:
mMessageHandler.postDelayed(mSearchRunnable, 1000);
you can then cancel the thread if the user enters more data with:
mMessageHandler.removeCallbacks(mSearchRunnable);
You should think about calling cancel(true) to try to shutdown the task while it is waiting or if the call to the webserver is running already. That might save you some process-cycles tho your webserver could be unamused about the broken calls.
If you want to save some gc-cycles you could reuse your SearchCriteria object if that is possible.
Apart from this I can't see any memory leaks. Your objects have short lifecycles and you don't cache them. The only problem that might arise is too many parallel AsyncTasks with running http-requests which will cause an early out of memory. We had that problem once with one app during the monkey-test.
hi this is the link which may be helps you..
http://thinkandroid.wordpress.com/2010/02/08/writing-your-own-autocompletetextview/
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
lv1 = (ListView) findViewById(R.id.ListView01);
ed = (AutoCompleteTextView) findViewById(R.id.EditTextSearch);
// AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.autocomplete_country);
ArrayAdapter<String> adapter1 = new ArrayAdapter<String>(this, R.layout.list_item, countryName);
ed.setAdapter(adapter1);
this.getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
final List<HashMap<String, String>> fillMaps = new ArrayList<HashMap<String, String>>();
for (int i = 0; i < countryName.length; i++) {
HashMap<String, String> map = new HashMap<String, String>();
map.put("flag", "" + imageId[i]);
map.put("country", countryName[i].toString());
map.put("capital", capitalName[i].toString());
map.put("countrytime",
convertDateTimeToGMT(GMTplusMinusInMillisecond[i],
plusMinus[i]));
map.put("GMT", GMTplusMinus[i].toString());
fillMaps.add(map);
}
// fill in the grid_item layout
SimpleAdapter adapter = new SimpleAdapter(this, fillMaps,
R.layout.grid_item, from, to);
lv1.setAdapter(adapter);
ed.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
public void onTextChanged(CharSequence s, int start, int before,
int count) {
fillMaps.clear();
textlength = ed.getText().length();
for (int i = 0; i < countryName.length; i++) {
if (textlength <= countryName[i].length()) {
if (ed.getText()
.toString()
.equalsIgnoreCase(
(String) countryName[i].subSequence(0,
textlength))) {
HashMap<String, String> map = new HashMap<String, String>();
map.put("flag", "" + imageId[i]);
map.put("country", countryName[i].toString());
map.put("capital", capitalName[i].toString());
map.put("countrytime",
convertDateTimeToGMT(
GMTplusMinusInMillisecond[i],
plusMinus[i]));
map.put("GMT", GMTplusMinus[i].toString());
fillMaps.add(map);
}
}
}
if(!fillMaps.isEmpty())
{
SimpleAdapter adapter = new SimpleAdapter(
WorldClockActivity.this, fillMaps, R.layout.grid_item,
from, to);
lv1.setAdapter(adapter);
}
else
{ String[] COUNTRIES = new String[] {"No record found"};
lv1.setAdapter(new ArrayAdapter<String>(WorldClockActivity.this,R.layout.list_item, COUNTRIES));
}
// lv1.setAdapter(new
// ArrayAdapter<String>(WorldClockActivity.this,android.R.layout.simple_list_item_1
// , arr_sort));
}
});
}
public static String convertDateTimeToGMT(long millis, int plusMinus) {
Calendar CalGMT;
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
CalGMT = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
CalGMT.get(Calendar.DAY_OF_MONTH);
CalGMT.get(Calendar.MONTH);
CalGMT.get(Calendar.YEAR);
CalGMT.get(Calendar.HOUR_OF_DAY);
CalGMT.get(Calendar.MINUTE);
CalGMT.get(Calendar.SECOND);
if (plusMinus == 1) {
CalGMT.setTimeInMillis(CalGMT.getTimeInMillis() + millis);
} else if (plusMinus == 0) {
CalGMT.setTimeInMillis(CalGMT.getTimeInMillis() - millis);
}
String sendDateTimeInGMT = CalGMT.get(Calendar.HOUR_OF_DAY) + ":"
+ CalGMT.get(Calendar.MINUTE) + ":"
+ CalGMT.get(Calendar.SECOND);
return sendDateTimeInGMT;
}
}
I have done the application using the above code in this application i have use AutoCompleteTextView for provide search facility in list view then list view show the name of all the country and user able to search country by country name when user type in AutoCompleteTextView then related search is show in listview.
Ex if user want to search Canada in the world country list then user only type ca in AutoCompleteTextView then a another list is appear blow the AutoCompleteTextView and show the all country name start ca name then user chose Canada in this list then get the all information of Canada in listview.
Related
I am using an API that delivers me the gas stations in Germany. I get the location and the name of the gas station using Asynctask.
I am putting these datas into a listView. For the listView I have implemented the setOnItemClickListener method, that is currently in doInBackground. If you click on a item, a new layout will be opened where all the fetched data are listed again, nothing special.
At the office I am using Android Studio 3.2.1 (Windows) at home I am using Android Studio 2.3.2 (Linux Ubuntu 64 bit).
At home I get the warning that the setOnItemClickListener should not be in DoInBackground. I know, that UI operations should be not there, yes.
But at office I don't get this warning. The syntax of the code is correct, when I start it from the office pc, everything works.
When I do the same at home, my whole phone (Samsung Galaxy S7) crashes (System.UI has stopped working) and even a hard reset did not work. For my home laptop Jack is enabled in order to work with Java 1.8 the API requires this.
The freezing appears when I scroll down the ListView and click on Items. Here is the code, I really do not know what kind of error this is:
public class ListOfGasStations extends AppCompatActivity {
Button button;
EditText editText;
ListView listView;
List<String> names = new ArrayList<String>();
int size;
String[] locationArray;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_of_gas_stations);
editText = findViewById(R.id.inputaddress);
button = findViewById(R.id.buttonaddress);
listView = findViewById(R.id.listviewgas);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new Test().execute();
}
});
}
class Test extends AsyncTask<Void, Void, Void> {
#SuppressLint("NewApi")
#Override
protected Void doInBackground(Void... params) {
double addresslat = getLat(String.valueOf(editText.getText()));
double addresslong = getLong(String.valueOf(editText.getText()));
StationListResult result;
Tankerkoenig.Api api = new Tankerkoenig.ApiBuilder()
.withApiKey("MY_API_KEY")
.build();
try {
result = api.list(addresslat, addresslong)
.setSorting(StationListRequest.SortingRequestType.DISTANCE)
.setGasRequestType(GasRequestType.DIESEL)
.setSearchRadius(5)
.execute();
size = result.getStations().size();
int sizeOfStations;
System.out.println("Size" + size);
locationArray = new String[size];
for (int k = 0; k < size; k++) {
//size of the station names
sizeOfStations = String.valueOf(result.getStations().get(k).getBrand()).length();
//get gas stations name
String removeUmlaute = String.valueOf(result.getStations().get(k).getBrand()).substring(9, sizeOfStations - 1).toUpperCase();
//get street names
String location = String.valueOf(result.getStations().get(k).getLocation().getStreetName();
locationArray[k] = location;
names.add(removeUmlaute + "\n" + "\n" + location");
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
for (int i = 0; i < size; i++) {
if (position == i) {
Intent intent = new Intent(ListOfGasStations.this, NavToLocation.class);
intent.putExtra("message", locationArray[i]);
startActivity(intent);
}
}
}
});
}
} catch (RequesterException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void foo) {
super.onPostExecute(foo);
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(ListOfGasStations.this, android.R.layout.simple_list_item_1, names);
listView.setAdapter(arrayAdapter);
}
}
public double getLat(String address) {
double p1 = 0;
Geocoder coder = new Geocoder(this);
try {
ArrayList<Address> addresses = (ArrayList<Address>) coder.getFromLocationName(editText.getText().toString(), 1);
for (Address add : addresses) {
p1 = add.getLatitude();
}
} catch (IOException e) {
e.printStackTrace();
}
return p1;
}
public double getLong(String address) {
double p2 = 0;
Geocoder coder = new Geocoder(this);
try {
ArrayList<Address> addresses = (ArrayList<Address>) coder.getFromLocationName(editText.getText().toString(), 1);
for (Address add : addresses) {
p2 = add.getLongitude();
}
} catch (IOException e) {
e.printStackTrace();
}
return p2;
}
}
The warning may be different on different IDE version. There are some reason for freezing UI.
May be the listview item is so long. Cause listview load all items at a time. (Solution: Better is using RecyclerView)
It is true that you cannot touch UI element from async thread but you calling onclick in doInBackground. (Solution: use it in uiThread ).
You are calling onclick for every listViewItem that means you creating a memory inside doInBackground. May be it is the problem to reuse it. (So betting create onclik in onPostExecute or after finish async.)
Remember: onPostExecute call can destroy async execution (Mean work in donInBackground). So i am afraid to using onCLick in doInBackGround may the main cause of app freeze..
I use Looper.prepare and Looper.loop in Runnable's run function. But the problem is that the thread not loop at all, the Runnable just run one time. In Activity1, I use three Runnable threads, all looping. Two threads get Data and pictures from net constantly through "while" loop(needn't update UI), one thread select data and pic from local sqlite constantly through "Looper". The data is:
protected void onCreate(Bundle savedInstanceState) {
......
new Thread(getMessageTask).start();
getMessageHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
i++;
System.out.println("niuanmata" + i); //one appear the first one
try {
ArrayList<Map<String, String>> listMessages = (ArrayList<Map<String, String>>)msg.obj;
boolean listchange = true;
if (oldMessages.size() != 0) {
if (listMessages.size() == oldMessages.size()) {
for (int i = 0; i < listMessages.size(); i++) {
Map<String, String> oldmessage = (Map<String, String>) oldMessages.get(i);
Map<String, String> newmessage = (Map<String, String>) listMessages.get(i);
if ((oldmessage.get("mID") != newmessage.get("mID")) || (oldmessage.get("mainContent") != newmessage.get("mainContent")) || (oldmessage.get("deadLine") != newmessage.get("deadLine"))) {
break;
}
if (i == (listMessages.size() - 1)) {
listchange = false;
}
}
}
}
if (listchange) {
SimpleAdapter adapter = new SimpleAdapter(MainActivity.this, listMessages, R.layout.layout_invites,
new String[]{"mID", "creater", "mainContent", "deadLine", "mtype", "createrLogo"},
new int[]{R.id.tv_list_type, R.id.tv_list_name, R.id.tv_list_inviteword, R.id.tv_list_invitedate, R.id.tv_list_inviteid, R.id.iv_list_logo});
lvMessage.setAdapter(adapter);
oldMessages = listMessages;
}
} catch (Exception e) {
Toast.makeText(MainActivity.this, "wrong: " + e.toString(), Toast.LENGTH_SHORT).show();
return;
}
}
};
......
lvMessage.setOnItemClickListener(new AdapterView.OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) { //when creater click, update the message; when others click, reset the alarm
Toast.makeText(MainActivity.this, "ok" , Toast.LENGTH_SHORT).show();
}
});
}
.........
Runnable synchroDataTask = new Runnable() {
#Override
public synchronized void run() {
//data syschno
while (IOHelper.loopjudge()) {
{
AccountsDB adb = new AccountsDB(MainActivity.this);
String thelastupdate = adb.getLastUpdate(account.getChatNO());
Calendar calendar = IOHelper.StringToCalendar(thelastupdate);
calendar.add(Calendar.MINUTE, -30);
String accountData = synchroDataWebservice(account.getChatNO(), IOHelper.CalendarToString(calendar)); //get the datas of the account synchroly
AccountBLL.saveDBofWebString(accountData, MainActivity.this, account); //use static method to save the DB string as SQLite data
}
}
.........
#Override
public synchronized void run() {
while (IOHelper.loopjudge()) {
......
}
.......
Runnable getMessageTask = new Runnable() {
#Override
public synchronized void run() {
Looper.prepare();
//while (IOHelper.loopjudge() && (!stopThread)) {
MessageDB messagedb = new MessageDB(MainActivity.this);
List<MessageMain> messages = messagedb.getMessageByChatNO(account.getChatNO());
ArrayList<Map<String, String>> listMessages = setMessaageListToMap(messages);
Message msg = Message.obtain();
msg.obj = listMessages;
getMessageHandler.sendMessageDelayed(msg, 1000);
//}
Looper.loop();
}
};
......
In my limited experience with android, I use while to do the Loop in getMessageTask , because the data and UI's listview need to be updated constantly. But the listview can not be clicked. Then change to Looper, but the the UI's listview can't be updated constantly....
The answer is that I misunderstand the meaning of Looper, think the Looper.prepare() and Looper.loop() as the while() loop, then make the mistake.
Looper.prepare() and Looper.loop() just means that this thread can be looped, but I must write while loop or for loop by myself.
I have a Activity that contains over 100 complex views (with images, text views etc). Showing up these views is to hard to do it without a Thread that loads the views asynchronously. So I tried to do it with an AsyncTask. I am not sure whether this is the correct way because the "hard staff" is something that HAS to be done in the UI Thread.
Now I've got the problem that the UI freezes though I used the onProgressUpdate for adding the views in the to parent view. I thought that this would result in single loading views that appear successive in the parent view. But this is not the case.
doInBackground fires all publishProgress calls and after that the main thread is blocked (activity frozen, loadbar does not rotate anymore). Is there a way to achieve what I wanted to have? I looked for solutions but alway ended up with ideas of using AsyncTask and no one had to do view-stuff as "hard staff". I am not using "get" in the AsyncTask what seems to be a problem with AsyncTask.
Here is my code for this. If you need any further information please tell me!
Is there any other way to solute this problem? Is my AsyncTask implementation not correct? I am looking for a way to load these complex views asyncronous to the parent view without blocking the main thread.
Thanks in advance!
public class LoadKraut extends AsyncTask<Integer,Kraut,Void> {
private Context context;
private LinearLayout parent;
private HashMap<String,HeadlineAlphabet> headlinesAlphabet = new HashMap<String, HeadlineAlphabet>();
private long time;
private Integer kategorie;
private char letter = 'X';
private int counter = 0;
private ProgressDialog dialog;
public LoadKraut(Context context) {
/**
* Kategorie:
* 1 - A-Z
* 2 - Notiz
* 3 - Favorit
* 4 - Giftig
*/
Log.i("Kraut", "Start thread" + (System.currentTimeMillis()-time) + "ms");
this.context = context;
this.dialog = new ProgressDialog(context);
this.time = System.currentTimeMillis();
}
#Override
protected void onPreExecute() {
dialog.setMessage("Lade Kräuter. Dieser Vorgang kann einen Moment dauern.");
dialog.show();
}
#Override
protected Void doInBackground(Integer... params) {
this.kategorie = params[0];
//Create overview
try {
DatabaseHelper databaseHelper = new DatabaseHelper(context);
Dao<Kraut,Integer> dao = databaseHelper.getKrautDAO();
parent = (LinearLayout) ((Activity) context).findViewById(R.id.ll_conainter_sv_uebersicht_kraeuter);
//setKraeuter(list, linearLayout, giftig)
long test = System.currentTimeMillis();
List<Kraut> list = new ArrayList<>();
switch (kategorie) {
case 1:
list = dao.queryForAll();
break;
case 2:
list = dao.queryBuilder().where().ne("notiz","").query();
break;
case 3:
list = dao.queryBuilder().where().eq("favorit",true).query();
break;
case 4:
list = dao.queryBuilder().where().eq("toedlichBunny",true).query();
break;
}
Log.i("Kraut","Fetching duration: " + String.valueOf(System.currentTimeMillis() - test));
Iterator<Kraut> iterator = list.iterator();
while(iterator.hasNext()) {
Kraut kraut = iterator.next();
Log.i("Kraut","called pp for" + kraut.getName());
publishProgress(kraut);
}
} catch (SQLException e) {
e.printStackTrace();
}
Log.i("Kraut", "End " + (System.currentTimeMillis()-time) + "ms");
return null;
}
#Override
protected void onProgressUpdate(Kraut... value) {
//Set all Krauts and headlines A-Z
long test = System.currentTimeMillis();
Kraut kraut = value[0];
Log.i("Kraut", String.valueOf(counter));
if((kategorie==1 || kategorie==4) && kraut.getName().charAt(0)!=letter) {
letter = kraut.getName().charAt(0);
HeadlineAlphabet letterHeadline = new HeadlineAlphabet(context);
letterHeadline.setText(String.valueOf(kraut.getName().charAt(0)));
headlinesAlphabet.put(String.valueOf(letterHeadline.getText()),letterHeadline);
parent.addView(letterHeadline);
}
KrautView krautView=null;
if(kategorie==1 || kategorie==3) {
krautView = new KrautUebersicht(context,kategorie);
} else if(kategorie==2) {
krautView = new KrautUebersichtNotiz(context);
}
if(krautView!=null) {
krautView.setKraut(kraut);
parent.addView((LinearLayout) krautView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
parent.getRootView().invalidate();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
counter++;
Log.i("Kraut","Kraut View creation duration: " + String.valueOf(System.currentTimeMillis() - test));
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if(kategorie==1) {
//Set Alphabet Column right side
ArrayList<String> anfangsbuchstaben = Kraut.getAnfangsbuchstaben(context);
// Do this with an xml !
for (int i = 1; i <= 26; i++) {
//Log.i("Kraut", String.valueOf(i));
String currentLetter = Helper.getCharForNumber(i);
int id = context.getResources().getIdentifier("tv_"+currentLetter.toLowerCase(),"id",context.getPackageName());
TextView textView = (TextView) ((Activity) context).findViewById(id);
//If no Kraut contains Letter
if (!anfangsbuchstaben.contains(currentLetter)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
textView.setTextColor(context.getResources().getColor(R.color.darkgrey, context.getTheme()));
} else {
textView.setTextColor(context.getResources().getColor(R.color.darkgrey));
}
//Make clickable to jump to A-Z Headlines
} else {
textView.setOnClickListener(new JumpToLetterOnClickListener(headlinesAlphabet));
}
}
}
parent.invalidate();
if(dialog.isShowing()) {
dialog.dismiss();
}
}
}
Note that onProgressView() is called repeatedly as your AsyncTask runs. Therefore, it should be kept as short as possible. This also means that your current code is creating lots of views and adding them to the UI. Instead, you should add the view just once and then update its data in onProgressView().
Also, as Mike M. states in the comments, you should not call Thread.sleep() in onProgressView() since it runs on the UI thread. This is most likely the main reason your app is freezing.
I want to develop a dynamic AutoCompleteTextView for Android that populate with JSON data retrieved from MySQL database. Basically it is not a hard task but where I am facing problem? I am inspired by the jQuery Autocomplete option where dynamically fetch data after input letters. But android AutoCompleteTextView is pre-populated with all JSON data.
I am trying to query from millions of data which is really hard to store. Is there any way to search database for the input dynamically?
E.g:
Such as if user input "a" then it will retrieve the best result for "a". Then if user type "ab" it will be refreshed and populated with new results from database.
Thanks
I'll give you just a general overview only for your task Which looks like this,
public List<String> suggest; //List of suggestions
autoComplete.addTextChangedListener(new TextWatcher(){
public void afterTextChanged(Editable editable) {
// TODO Auto-generated method stub
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// TODO Auto-generated method stub
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
String newText = s.toString();
new getJson().execute(newText);
}
});
getJson AsyncTask -> For retrieving new values from server
class getJson extends AsyncTask<String,String,String>{
#Override
protected String doInBackground(String... key) {
String newText = key[0];
newText = newText.trim();
newText = newText.replace(" ", "+");
try{
//Codes to retrieve the data for suggestions
suggest = new ArrayList<String>();
JSONArray jArray = new JSONArray(data);
for(loop the array){
String SuggestKey = //retrieve values by iterating;
suggest.add(SuggestKey);
}
}catch(Exception e){
Log.w("Error", e.getMessage());
}
//Populate suggestions
runOnUiThread(new Runnable(){
public void run(){
aAdapter = new ArrayAdapter<String>(getApplicationContext(),R.layout.item,suggest);
autoComplete.setAdapter(aAdapter);
aAdapter.notifyDataSetChanged();
}
});
return null;
}
See here for the detail info.
As an user is typing in an AutoCompleteTextView, I want to get some results from an webservice and display them in the box.
For this I declared globally
ArrayAdapter<String> adapter;
autoCompleteText;
ArrayList<String> searchList;
I put this in my onCreate(). searchList is an ArrayList where I will get the results from the web service. Search() is my webservice search. I want it to search after the user typed at least 3 chars so that I used a TextWatcher on the field.
adapter = new ArrayAdapter<String>(MyActivity.this
, android.R.layout.simple_list_item_1, searchList);
autoCompleteText.setAdapter(adapter);
autoCompleteText.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
if (s.length() >= 3) {
new Search().execute(null, null, null);
}
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
});
Method from Search() - GET request in AsyncTask where I update my searchList
#Override
protected void onPostExecute(final Void unused) {
dlg.dismiss();
if (result != null) {
try {
JSONObject myJson = new JSONObject(result.substring(4));
JSONObject resp = myJson.getJSONObject("response");
for (Iterator<String> iterator = resp.keys(); iterator.hasNext();) {
String key = iterator.next();
System.out.println(key + " = " + resp.getString(key));
if(! searchList.contains(resp.getString(key)))
searchList.add(resp.getString(key));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
I would prefer to use ArrayAdapter and not a CustomAdapter. Any ideas?
Try calling notifyDataSetChanged() in onPostExecute() after changing the list.
This is how I update my AutoCompleteTextView:
String[] data = terms.toArray(new String[terms.size()]);
// terms is a List<String>
ArrayAdapter<?> adapter = new ArrayAdapter<Object>(activity, android.R.layout.simple_dropdown_item_1line, data);
keywordField.setAdapter(adapter); // keywordField is a AutoCompleteTextView
if(terms.size() < 40) keywordField.setThreshold(1);
else keywordField.setThreshold(2);
Now of course, this is static and doesn't deal with an over-the-air suggestions but, I can also suggest you to notify adapter for the changes after you assign it to the AutoCompleteTextView:
adapter.notifyDataSetChanged();