I am new to Android development and I ran into a problem which I find difficult to solve. I am trying to figure out how to use an AutoCompleteTextView widget properly. I want to create a AutoCompleteTextView, using XML data from a web service. I managed to get it to work, but I am defenitely not pleased with the output.
I would like to put a HashMap with id => name pairs into the AutoCompleteTextView and get the id of the clicked item. When I click on the autocomplete filtered set output, I want to populate a list underneath the autocompletion box, which I also managed to get to work.
Done so far:
autocomplete works well for simple ArrayList, all data filtered
correct
onItemClick event fires properly after click
parent.getItemAtPosition(position) returns correct String
representation of the clicked item
The event onItemClick(AdapterView parent, View v, int position, long id) does not behave as I would like. How can I figure out the unfiltered array position of the clicked item? The position of the filtered one is the one I am not interested in.
Further questions:
How to handle HashMaps or Collections in AutoCompleteTextView
How to get the right itemId in the onItemClick event
I did very extensive research on this issue, but did not find any valuable information which would answer my questions.
The event onItemClick(AdapterView parent, View v, int position, long
id) does not behave as I would like.
This is a normal situation when filtering an adapter. Although the adapter keeps a reference to the initial unfiltered data from its point of view it has a single set of data on which is based(no matter if is the initial one or resulted from a filter operation). But this shouldn't raise any problems. With the default sdk adapters(or with a subclass), in the onItemClick() you get the position for the current list on which the adapter is based. You could then use getItem() to get data item for that position(again it doesn't matter if initial or filtered).
String data = getItem(position);
int realPosition = list.indexOf(data); // if you want to know the unfiltered position
this will work for lists and Maps(assuming that you use the SimpleAdapter). And for a Maps you always have the option of adding an additional key to set the unfiltered position in the initial list.
If you use your own adapter along with an AutoCompleteTextView you could make the onItemClick() give you the right id(the position however you can't change).
public class SpecialAutoComplete extends AutoCompleteTextView {
public SpecialAutoComplete(Context context) {
super(context);
}
#Override
public void onFilterComplete(int count) {
// this will be called when the adapter finished the filter
// operation and it notifies the AutoCompleteTextView
long[] realIds = new long[count]; // this will hold the real ids from our maps
for (int i = 0; i < count; i++) {
final HashMap<String, String> item = (HashMap<String, String>) getAdapter()
.getItem(i);
realIds[i] = Long.valueOf(item.get("id")); // get the ids from the filtered items
}
// update the adapter with the real ids so it has the proper data
((SimpleAdapterExtension) getAdapter()).setRealIds(realIds);
super.onFilterComplete(count);
}
}
and the adapter:
public class SimpleAdapterExtension extends SimpleAdapter {
private List<? extends Map<String, String>> mData;
private long[] mCurrentIds;
public SimpleAdapterExtension(Context context,
List<? extends Map<String, String>> data, int resource,
String[] from, int[] to) {
super(context, data, resource, from, to);
mData = data;
}
#Override
public long getItemId(int position) {
// this will be used to get the id provided to the onItemClick callback
return mCurrentIds[position];
}
#Override
public boolean hasStableIds() {
return true;
}
public void setRealIds(long[] realIds) {
mCurrentIds = realIds;
}
}
If you also implement the Filter class for the adapter then you could get the ids from there without the need to override the AutoCompleTextView class.
Using the Luksprog approach, I made some similar with ArrayAdapter.
public class SimpleAutoCompleteAdapter extends ArrayAdapter<String>{
private String[] mData;
private int[] mCurrentIds;
public SimpleAutoCompleteAdapter(Context context, int textViewResourceId,
String[] objects) {
super(context, textViewResourceId, objects);
mData=objects;
}
#Override
public long getItemId(int position) {
String data = getItem(position);
int index = Arrays.asList(mData).indexOf(data);
/*
* Atention , if your list has more that one same String , you have to improve here
*/
// this will be used to get the id provided to the onItemClick callback
if (index>0)
return (long)mCurrentIds[index];
else return 0;
}
#Override
public boolean hasStableIds() {
return true;
}
public void setRealIds(int[] realIds) {
mCurrentIds = realIds;
}
}
Implement onItemClickListener for AutoCompleteTextView, then use indexOf on your list to find the index of selected item.
actvCity.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
int index = cityNames.indexOf(actvCity.getText().toString());
// Do Whatever you want to do ;)
}
});
First add your data into custom arraylist
// mList used for adding custom data into your model
private List<OutletListSRModel> mList = new ArrayList<>();
// listdata used for adding string data for auto completing.
ArrayList<String> listdata = new ArrayList<String>();
for (int i = 0; i < JArray.length(); i++) {
JSONObject responseJson = JArray.getJSONObject(i);
OutletListSRModel mModel = new OutletListSRModel();
mModel.setId(responseJson.getString("id"));
mModel.name(responseJson.getString("outlet_name"));
listdata.add(responseJson.getString("outlet_name"));
}
ArrayAdapter adapter = new
ArrayAdapter(getActivity(),
android.R.layout.simple_list_item_1, listdata);
searchOutletKey.setAdapter(adapter);
Now for getting any value from model which we added above. we can get like this.
searchOutletKey.setOnItemClickListener ( new AdapterView.OnItemClickListener ( ) {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String txtOutletId = mOutletListSRModel.get(position).getId();
}
});
Related
I have implemented a custom adapter and listItemView. The adapter sets an onlclick listener to a button that is on the listItemView. The onclick listener simply calls a private method I have in the adapter and passes it the position of the item to be removed. I know the position is correct because the database removes the proper item. I have found similar questions but have not been able to adapt the answers to work for me. Ideas and thoughts are greatly appreciated. Thanks.
Here is the full adapter class
public class FoodListAdapter extends ArrayAdapter<FoodListItem> {
//private
private int type;
public FoodListAdapter(Context context, ArrayList<FoodListItem> _objects) {
super(context, 0, _objects);
type = 0;
}
public FoodListAdapter(Context context, ArrayList<FoodListItem> _objects, int _type) {
super(context, 0, _objects);
type = _type;
}
#Override
public View getView(int position, View reusableView, ViewGroup parent)
{
//Cast the reusable view to a listAdpaterItemView
FoodListItemView listItemView = (FoodListItemView) reusableView;
//Check if the listAdapterItem is null
if(listItemView == null)
{
//If it is null, then create a view.
listItemView = FoodListItemView.inflate(parent, this, type);
}
if (type == 2)
{
Button deleteButton = (Button) listItemView.findViewById(R.id.listItemViewDeleteBTN);
deleteButton.setTag(new Integer(position));
}
//Now we need to set the view to display the data.
listItemView.setData(getItem(position));
return listItemView;
}
}
Here is a portion of my code used in fragment. Note that I have a private variable decalred in the class for listAdapter, though I don't think I need that.
private void displayListForDate(Calendar _date)
{
//get the list view
ListView listView = (ListView) getView().findViewById(1);
//Clear the listview by removing the listadapter and setting it to null.
//listView.setAdapter(null);
//First we must get the items.
Global global = (Global) getActivity().getApplicationContext();
DietSQLiteHelper database = global.getDatabase();
//Create a list to hold the items we ate. This list will then be added to the listView.
final ArrayList<FoodListItem> consumedList;
//Add the items to the array.
consumedList = database.getConsumed(_date.getTimeInMillis());
//Create an adapter to be used by the listView
listAdapter = new FoodListAdapter(getActivity().getBaseContext(), consumedList, 2);
//Add the adapter to the listView.
listView.setAdapter(listAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
consumedList.remove(position);
listAdapter.notifyDataSetChanged();
}
});
}
If you didn't implement "equals" method of FoodListItem, try to implements it.
I would suggest,
that you just update the underlying data, in your case its ArrayList<FoodItems>.
In your Adapter make this simple method and change :
private List<FoodListItem> myList = new ArrayList<FoodListItem>();
public FoodListAdapter(Context context, List<FoodListItem> myList) {
super(context, 0, myList);
type = 0;
this.myList = myList;
}
public FoodListAdapter(Context context, List<FoodListItem> myList, int _type) {
super(context, 0, myList);
type = _type;
this.myList = myList;
}
// Also update your getView() method to use myList!
#Override
public View getView(int position, View reusableView, ViewGroup parent)
{
...
listItemView.setData(myList.get(position));
public void removeItem(int positio){
if(myList != null){
myList.remove(position);
}
}
And then in class, you are creating the adapter (Activity/Fragment), just call the method.
// Update the underlying ArrayAdapter
adapter.removeItem(position);
// Notify the adapter, the data has changed
adapter.notifyDataSetChanged();
Also, you shouldnt open connection to your SQLiteDatabase on UI thread, because you are blocking it. You never know, how fast is the reading from disk going to be. If it takes too long, user can think, that your application froze and therefore, he leaves, which you dont want. I would suggest to use AsyncTask, you will find a lot of examples.
I went through and cleaned up my code and it now works, here is the working code. I really don't know exactly the difference other than I updated the IDs that I was using to assign and get views. If anyone can explain the cause for the issue I was having I would appreciate it.
Here is the snippet from my fragment where I create the list view and assign an adapter.
private void displayListForDate(Calendar _date)
{
//get the list view
ListView listView = (ListView) getView().findViewById(R.id.listView);
//Clear the listview by removing the listadapter and setting it to null.
//listView.setAdapter(null);
//First we must get the items.
Global global = (Global) getActivity().getApplicationContext();
DietSQLiteHelper database = global.getDatabase();
//Create a list to hold the items we ate. This list will then be added to the listView.
ArrayList<FoodListItem> consumedList;
//Add the items to the array.
consumedList = database.getConsumed(_date.getTimeInMillis());
//Create an adapter to be used by the listView
listAdapter = new FoodListAdapter(getActivity().getBaseContext(), consumedList, 2);
//Add the adapter to the listView.
listView.setAdapter(listAdapter);
}
and here is my adapter class.
public class FoodListAdapter extends ArrayAdapter<FoodListItem>
{
//private
private int type;
public FoodListAdapter(Context context, ArrayList<FoodListItem> _objects) {
super(context, 0, _objects);
type = 0;
}
public FoodListAdapter(Context context, ArrayList<FoodListItem> _objects, int _type) {
super(context, 0, _objects);
type = _type;
}
#Override
public View getView(int position, View reusableView, ViewGroup parent)
{
//Cast the reusable view to a listAdpaterItemView
FoodListItemView listItemView = (FoodListItemView) reusableView;
//Check if the listAdapterItem is null
if(listItemView == null)
{
//If it is null, then create a view.
listItemView = FoodListItemView.inflate(parent, type);
}
if (type == 2)
{
Button deleteButton = (Button) listItemView.findViewById(R.id.listItemViewDeleteBTN);
deleteButton.setTag(new Integer(position));
deleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Integer tag = (Integer) view.getTag();
deleteItem(tag.intValue());
}
});
}
//Now we need to set the view to display the data.
listItemView.setData(getItem(position));
return listItemView;
}
private void deleteItem(int position)
{
FoodListItem item = getItem(position);
Global global = (Global) getContext().getApplicationContext();
DietSQLiteHelper database = global.getDatabase();
database.removeConsumed(item.getID());
remove(getItem(position));
}
}
I am trying to figure out how to find the position of a custom ParseObject in a ParseQueryAdapter<> so that I can set the position of a spinner or check rows of a check list in my Android project.
I am currently using a custom adapter extending ParseQueryAdapter<Vendor> where Vendor extends ParseObject. I also have an Item that extends ParseObject that is associated with a Vendor. In this specific example, if I want to edit an Item, I want the previously chosen Vendor displayed in the spinner. I want to set the selection of a spinner that is backed by my custom ParseQueryAdapter<Vendor>. Before I integrated Parse, I was using an ArrayAdapter<CharSequence> which could do:
String vendorName = Vendor.getName();
int position = adapter.getPosition(vendorName);
spinner.setSelection(position);
I was thinking that I could get the position of a Vendor object like when I was just using the String name in the array, but ParseQueryAdapter doesn't have a getPosition method. I was thinking of making a custom method to do so, but am at a loss of how to find the position of the Vendor. I am also thinking that I might need .isEqualTo(Vendor vendor) method in my Vendor class.
You need to facade the ParseQuery Adapter, do something like this :
public class CustomListAdapter extends BaseAdapter {
private final YourParseAdapter adapter;
public CustomListAdapter(final Context context) {
this.adapter = new YourParseAdapter(context);
adapter.registerDataSetObserver(new DataSetObserver() {
#Override
public void onChanged() {
super.onChanged();
notifyDataSetChanged();
}
});
}
public void reloadObjects() {
adapter.loadObjects();
}
// Customize the layout by overriding getItemView
#Override
public View getView(int i, View v, ViewGroup viewGroup) {
View result = adapter.getView(i, v, viewGroup);
// HERE YOU HAVE THE VIEW GENERATED BY PARSE AND THE ITEM POSITION
return result;
}
#Override
public int getCount() {
return adapter.getCount();
}
#Override
public Object getItem(int i) {
return adapter.getItem(i);
}
#Override
public long getItemId(int i) {
return adapter.getItemId(i);
}
}
I figured out what I needed to do. Instead of using a ParseQueryAdapter<Vendor>, I got my List<Vendor> from a separate query then I used an ArrayAdapter<Vendor> so that I could use the adapter.getPosition(obj) method. Since the ArrayAdapter uses .indexOf(Obj) which in turn uses .equals(Obj), I added to my Vendor object:
#Override
public boolean equals(Object o) {
return this.getObjectId().equals(((Vendor) o).getObjectId());
}
I just needed to have a way for my custom object to be compared.
i have a spinner populated by an arraylist with multiple hashmaps at each index for each "rung" on the spinner. So when the item is selected, i want to get the single key that is selected and do something with it
i do like this in my pic but there is a problem
how can i solve it
image http://www.qzal.net/01/2012-10/13530999521.png
Here is a usable copy of the code:
spinner2.setOnItemSelectedListener(new CustomOnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
ArrayList<HashMap<String, String>> arrList = new ArrayList<HashMap<String,String>>();
// for each key in the hashMap at this position..
for (String key : arrList.get(position).get("SectionID"))
{
}
}
#Override
public void onNothingSelected(AdapterView<?> adapter) {}
});
You must do this one level at a time. First fetch each HashMap from your ArrayList, then ask for your specific key:
for (HashMap<String, String> map : arrList) {
String value = map.get("SectionID");
// Do something
}
However if you just initialized arrList there won't be anything in it...
If I have 2 spinner depended with type ArrayList>
spinner2.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
ArrayList<HashMap<String, String>> arrList = new ArrayList<HashMap<String,String>>();
for (HashMap<String, String> map2 : arrList) {
String value = map2.get("SectionID");
// Do something
Context context = getApplicationContext();
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, value, duration);
toast.show();
Log.d("wwwwwwwwwwwwwwwwwwww: ", value);
// Do something
}
}
#Override
public void onNothingSelected(AdapterView<?> adapter) {
}
});
i do like this but kothing happend and logcat not having error
I do not know how to get the item with tag (courseid) in this array after the user click the item in spinner.
If you only want to get the courseid from each row, you do not need a custom OnItemSelectedListener. Simple use:
// Let's use the regular listener vvvvvvvvvvvvvvvvvvvvvv
spinner.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
HashMap<String, String> map = arrList.get(position);
String id = map.get("courseid");
// Do something
}
#Override
public void onNothingSelected(AdapterView<?> adapter) {}
});
Where arrList is the class variable that holds the data for your SimpleAdapter.
i do like this but kothing happend and logcat not having error
That is because you just created arrList, so it is empty:
ArrayList<HashMap<String, String>> arrList = new ArrayList<HashMap<String,String>>();
for (HashMap<String, String> map2 : arrList) { // This arrList has no data!
You need to use the ArrayList that you used when you created your SimpleAdapter.
new SimpleAdapter(this, arrList, ...);
This is the ArrayList you must use and it must be a class variable.
Your post is a little hard to understand, but i think i have an idea. you have a single spinner populated by an arraylist with multiple hashmaps at each index for each "rung" on the spinner. So when the item is selected, you want to get the single key that is selected and do something with it. Well as we know, a hashMap isn't really indexed so we have to use alternative methods to get at it, correct?
ArrayList<HashMap<String, String>> arrList = new ArrayList<HashMap<String,String>>();
spinner.setOnItemSelectedListener(new CustomOnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> adapterView, View view,
int position, long id) {
// for each key in the hashMap at this position..
for (String key : arrList.get(position).keySet()) {
if (key == "Calculus") {
// do something
} else if (key == "Physics") {
// do something else
}
}
}
The idea is really simple here. you get the entire keySet of the hashMap at the index of the position selected on the spinner and you do something for each key in it, depending on what it says. This should work without too much hassle, assuming you only have one key-value pair there.
BUT I have to say that you should really re-think the design a bit. You have multiple hashMap containers just holding one thing each. It really is a waste of resources. it's hard to recommend an alternative because i don't exactly know how this data is being used, but you should know that making objects in java isn't free.
I learn work with Android. I started to create a project with Contacts.
I insert contacts into the SQLite database and then I put them from the database and show them in ListView. Thats OK. But I would like to click on an item in the List and then to edit the item. Therefore I need to get somehow the ID of the item and work with it...I do not know if it is clear...As you can see, in the function onItemClick() , there is running a new activity ...and in the new activity, I need the ID of the item in order to work with it.
public class ContactList extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.seznam_kontaktu2);
SQLInsert info = new SQLInsert(this);
info.open();
ArrayList<String> data = info.getDataArrayList(); //It returns Array of "Lastname, Name" which is shown in the List
info.close();
ListView lv1 = (ListView) findViewById(R.id.ListView01);
lv1.setAdapter (new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, data));
lv1.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
startActivity(new Intent("net.johnyho.cz.EDITOVATKONTAKT"));
}
});
}
One option that has worked for me is to create a custom ArrayAdapter class along with a custom AdapterItem class. We store the id on our AdapterItem, and return it using our custom ArrayAdapter.
MyAdapterItem might look something like ...
public class MyAdapterItem implements Comparable
{
public String name;
public long rowId;
public MyAdapterItem()
{
rowId = -1L;
name = "";
}
public MyAdapterItem(long _rowId, String _name)
{
rowId = _rowId;
name = _name;
}
public int compareTo( Object o )
{
return toString().compareTo(o.toString());
}
public String toString()
{
return name;
}
}
Our custom ArrayAdapter, MyAdapter, then overrides getItemId(). It reads and returns the stored row id (making the assumption it is working with elements of MyAdapterItem). The other methods on ArrayAdapter will continue to work with our custom class - the toString method is used by the list for display purposes, and by providing a compareTo method the list knows how to sort the values.
public class MyAdapter<MyAdapterItem> extends ArrayAdapter
{
public MyAdapter(Context context, int resourceId)
{
super(context, resourceId);
}
#Override
public long getItemId( int position )
{
MyAdapterItem item = (MyAdapterItem)this.getItem(position);
return item.rowId;
}
}
Back in your Activity's onCreate the OnItemClickListener now provides the correct row id in the "id" parameter.
What is not shown is the new implementation of info.getDataArrayList() - it must be modified to create new MyAdapterItem objects instead of simple Strings.
ArrayList<MyAdapterItem> data = info.getDataArrayList();
ListView lv1 = (ListView) findViewById(R.id.ListView01);
lv1.setAdapter( new MyAdapter<MyAdapterItem>(this, android.R.layout.simple_list_item_1, data) );
lv1.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View view, int position, long id)
{
// do whatever - the value in "id" is supplied by getRowId on our adapter
}
});
Also, if you attach a context menu to your ListView, the MenuItem objects passed into your Activity's onContextItemSelected method will also return the correct row id.
#Override
public boolean onContextItemSelected(MenuItem item)
{
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
long rowId = info.id;
// do something with the id
}
public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) {
startActivity(new Intent("net.johnyho.cz.EDITOVATKONTAKT"));
}
hi i dont know what are the column names of your application.but for example id is your primary key identifier then move cursor to arg2 postion and get the value of _id and then pass it to startActivity and it will work.first thing apply SQLiteOpenHelper class its easy for use then apply this.