I want to use HashMap
for a list of items of Adapter
for a ListView
. I was going to use ArrayAdapter<>
but I can\'t
There are no predefined Adapters which will render a HashMap. I suggest creating your own Adapter by extending BaseAdapter.
Edit: It is posible to use HashMap with and extended BaseAdapter, here's an(untested) example:
public class HashMapAdapter extends BaseAdapter {
private HashMap<String, String> mData = new HashMap<String, String>();
private String[] mKeys;
public HashMapAdapter(HashMap<String, String> data){
mData = data;
mKeys = mData.keySet().toArray(new String[data.size()]);
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Object getItem(int position) {
return mData.get(mKeys[position]);
}
@Override
public long getItemId(int arg0) {
return arg0;
}
@Override
public View getView(int pos, View convertView, ViewGroup parent) {
String key = mKeys[pos];
String Value = getItem(pos).toString();
//do your view stuff here
return convertView;
}
}
This comes with the following caveat, the order of the items is not guaranteed to be the same order you added them. Writing this example has made me realize; Don't use HashMap in an adapter :)
In your adapter file
MyAdapter.java
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Map;
public class MyAdapter extends BaseAdapter {
private final ArrayList mData;
public MyAdapter(Map<String, String> map) {
mData = new ArrayList();
mData.addAll(map.entrySet());
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Map.Entry<String, String> getItem(int position) {
return (Map.Entry) mData.get(position);
}
@Override
public long getItemId(int position) {
// TODO implement you own logic with ID
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final View result;
if (convertView == null) {
result = LayoutInflater.from(parent.getContext()).inflate(R.layout.my_adapter_item, parent, false);
} else {
result = convertView;
}
Map.Entry<String, String> item = getItem(position);
// TODO replace findViewById by ViewHolder
((TextView) result.findViewById(R.id.text1)).setText(item.getKey());
((TextView) result.findViewById(R.id.text2)).setText(item.getValue());
return result;
}
}
Call this adapter
public void showCinemas(HashMap<String, String> cinemas) {
MyAdapter adapter = new MyAdapter(cinemas);
list.setAdapter(adapter);
}
To maintain order in the dictionary, if the key type is applicable, you could always add them to an ArrayList of their own, sort it using Collections.sort, and work with that as your reference point.
private ArrayList<String> mKeys = new ArrayList<>();
for (String aKey :data.keySet()){
mKeys.add(aKey);
}
Collections.sort(mKeys);
Thanks for the answer longhairedsi
This comes with the following caveat, the order of the items is not guaranteed to be the same order you added them. Writing this example has made me realize; Don't use HashMap in an adapter :)
To get around this problem, use a LinkedHashMap instead.
public class HashMapAdapter extends BaseAdapter {
private LinkedHashMap<String, String> mData = new LinkedHashMap<String, String>();
private String[] mKeys;
public HashMapAdapter(LinkedHashMap<String, String> data){
mData = data;
mKeys = mData.keySet().toArray(new String[data.size()]);
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Object getItem(int position) {
return mData.get(mKeys[position]);
}
@Override
public long getItemId(int arg0) {
return arg0;
}
@Override
public View getView(int pos, View convertView, ViewGroup parent) {
String key = mKeys[pos];
String Value = getItem(pos).toString();
//do your view stuff here
return convertView;
}
}
What you can do, IMHO, is generate a new list for they key values of the Hashmap that you are trying to add, and then pass that list to the custom adapter. Then import the HashMap collection in the adapter and use HashMap.get(key);
from the list of reference keys.
You can get an array of your map entries:
Entry<MyKey, MyValue>[] entries =
map.entrySet().toArray(new Entry<MyKey, MyValue>[0]);
That being said, if you are planning on updating your map or using map features in the adapter then making a custom adapter is not difficult and would make much more sense.
You can start out by subclassing BaseAdapter, which provides implementations for all but a few of the Adapter methods you need to get running.