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();
Related
I retrieve some phones and emails of a contact via JSONarray, for every one of this elements it creates a new EditText (with the phone or email).
I want to know how to update my JSONobject if user change the phone number, or an email, after that I want to add this JSONobject's to a JSONarray to post to my service.
This is the code where I put elements in EditText's:
try {
multiplesArray = new JSONArray(multiples);
//multiplesUpdatedArray = new JSONArray();
System.out.println(multiplesArray.toString(2));
for (int i=0; i<multiplesArray.length(); i++) {
JSONObject contact = new JSONObject();
String type = multiplesArray.getJSONObject(i).getString("tipo");
String data = multiplesArray.getJSONObject(i).getString("texto");
String id = multiplesArray.getJSONObject(i).getString("id");
if (type.equals("phone")) {
final EditText etPhoneItem = new EditText(this);
etPhoneItem.setText(data);
viewPhonesContainer.addView(etPhoneItem);
} else if (type.equals("email")) {
final EditText etEmailItem = new EditText(this);
etEmailItem.setText(data);
viewEmailContainer.addView(etEmailItem);
}
contact.put("tipo", type);
contact.put("id", id);
contact.put("texto", data);
contact.put("cat", "");
contact.put("cat_id", "");
/*multiplesUpdatedArray.put("tipo");
multiplesUpdatedArray.put(type);
multiplesUpdatedArray.put("id");
multiplesUpdatedArray.put(id);
multiplesUpdatedArray.put("texto");
multiplesUpdatedArray.put(data);*/
}
} catch (JSONException e) {
e.printStackTrace();
}
I try some code with "setOnFocusChangeListener" but it didn't work :-(
Thanks in advance!
Use addTextChangeListener .
editText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence pCode, int start, int before, int count) {
// change your JSONObject
jsobObject.put("key", "value");
}
#Override
public void afterTextChanged(Editable s) {
}
});
You can do it.
etPhoneItem.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
if (s.length() != 0) {
try {
contact.put("number", s.toString());
} catch (JSONException e) {
e.printStackTrace();
}
}
}
});
Simply you can use textView.addTextChangedListener(yourTextWatcherListener) to get the text when user changes the text. But why update that text in json frequetly, because using TextWatcher you will endup updating the json for each and every character you enter. Updating json frequently is very expensive and very bad practice. Instead of using textwatch listener just form the json when you press the post button.
If you are very clear that you are going to update it frequently, then create pojo classes according to the json structure. Updating the variables of the class is not expensive. Convert the pojo class to json using Jackson when editing is done.
JSON to POJO
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.
I want to use AutoCompleteTextView with Geocoder, but when I start typing suggestions do not pop up.
I do not get why suggestions do not pop up? Is there any solution to this?
Here is my code:
ArrayList<String>addressList = new ArrayList<String>();
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(),android.R.layout.simple_list_item_1, addressList);
autoComplete.setAdapter(adapter);
autoComplete.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(final CharSequence s, int start, int before, int count) {
getAddressInfo(getActivity(), location, s.toString());
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
private void getAddressInfo(Context context, Location location, String locationName){
Geocoder geocoder = new Geocoder(context, Locale.getDefault());
try {
List<Address> a = geocoder.getFromLocationName(locationName, 5);
for(int i=0;i<a.size();i++){
String city = a.get(0).getLocality();
String country = a.get(0).getCountryName();
String address = a.get(0).getAddressLine(0); // If any additional address line present than only, check with max available address lines by getMaxAddressLineIndex()
addressList.add(address+", "+city+", "+country);
}
} catch (IOException e) {
e.printStackTrace();
}
adapter.notifyDataSetChanged();
}
From what I can tell from the code you provided it looks like you may have forgotten to set a threshold on the AutoCompleteTextView that you are using. The threshold determines how many characters a user must type before the suggestions will appear; if you do not set a threshold no results will ever be shown.
Try doing this before setting your adapter:
public void setupAutoCompleteTextView(AutoCompleteTextView autoCompleteTextView) {
ArrayAdapter<String> adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, addressList);
autoCompleteTextView.setThreshold(1);
autoCompleteTextView.setAdapter(adapter);
autoCompleteTextView.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(final CharSequence s, int start, int before, int count) {
getAddressInfo(MainActivity.this, s.toString());
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
private void getAddressInfo(Context context, String locationName){
Geocoder geocoder = new Geocoder(context, Locale.getDefault());
try {
List<Address> a = geocoder.getFromLocationName(locationName, 5);
for(int i=0;i<a.size();i++){
String city = a.get(i).getLocality();
String country = a.get(i).getCountryName();
String address = a.get(i).getAddressLine(0); // If any additional address line present than only, check with max available address lines by getMaxAddressLineIndex()
addressList.add(address+", "+city+", "+country);
}
} catch (IOException e) {
e.printStackTrace();
}
}
Hope that helps!
I am loading the phone contacts ina list and implementing TextChangedListener on edittext as below
editTxt.addTextChangedListener(new TextWatcher() {
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
public void afterTextChanged(Editable s) {
final TextView noDataFound = (TextView) findViewById(R.id.norecords);
inputName = s.toString();
if(inputName!=null&&!inputName.trim().equals("")){
Log.d(TAG, "LoadMoreEntries --> Constants.loadEntries : "
+ Constants.loadEntries);
if (Constants.loadEntries != null) {
Constants.loadEntries.cancel(true);
}
Constants.loadEntries = new LoadEntries();
Constants.loadEntries.execute();
}
Button closesearch = (Button) findViewById(R.id.closesearch);
if (inputName != null && !inputName.trim().equals("")) {
closesearch.setVisibility(View.VISIBLE);
} else {
closesearch.setVisibility(View.GONE);
}
closesearch.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (Constants.loadEntries != null) {
Constants.loadEntries.cancel(true);
Constants.loadEntries = new LoadEntries();
Constants.loadEntries.execute();
}else {
}
return false;
}
});
}
public void onTextChanged(CharSequence s, int start, int before,
int count) {
}
});
here when the user types the correct name it is giving the names and when he types wrong name it shows no data.
my issue is when i typing the correct name and erasing, the whole list is loaded but when i type wrong name and displaying
no data and when erasing the name, list is not updating. also i have " x " button after typing name and clicking on that
should get all my list back. Any help is appreciated
Use Google Places AutoComplete API rather than implementing Textwatcher. Google Places AutoComplete API is really effective when you start type and take pause then it will show dropdown and dropdown list is updated at every character.
Using this you can easily update your dropdown list of your autocomplete.
Here is explanation of this.
editTxt.setAdapter(new PlacesAutoCompleteAdapter(this,R.layout.yourlayout));
here is PlacesAutoCompleteAdapter class which is filter result and return filtered result.
private class PlacesAutoCompleteAdapter extends ArrayAdapter<String> implements Filterable {
private ArrayList<String> resultList;
private String[] myArray;
public PlacesAutoCompleteAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
}
#Override
public int getCount() {
return myArray.length;
}
#Override
public String getItem(int index) {
return myArray[index];
}
#Override
public Filter getFilter() {
Filter filter = new Filter() {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
if (constraint != null) {
// Retrieve the autocomplete results.
myArray = autocomplete(constraint.toString()); // here we are calling myAutocomplete method.
// Assign the data to the FilterResults
filterResults.values = myArray;
filterResults.count = myArray.length;
}
return filterResults;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results != null && results.count > 0) {
notifyDataSetChanged();
}
else {
notifyDataSetInvalidated();
}
}};
return filter;
}
}
private String[] autocomplete(String dropdownString) {
ArrayList<String> resultList = null;
StringBuilder jsonResults = new StringBuilder();
String term;
try {
term=URLEncoder.encode(dropdownString, "utf8");
} catch (Exception e) {
e.printStackTrace();
term = dropdownString;
}
StringBuilder sb = new StringBuilder(PLACES_API_BASE + TYPE_AUTOCOMPLETE);
sb.append("?param="+param1+"); // this is parameter if your getting data from server.
sb.append("&term="+term); // this term which you typing in edittext.
String url = sb.toString();
// you can do here anything with your list. get it and populate it.
return myArray;
}
PLACES_API_BASE:- here is url if you are getting data from Web(in my example www.myurl/myapp).
TYPE_AUTOCOMPLETE:- file name or exact location from where are you getting data(in my example abc.php).
If you have any query ask me. don't be hesitate.
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.