HashMap to ListView
Solution 1
Make simple adapter class:
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(android.R.id.text1)).setText(item.getKey());
((TextView) result.findViewById(android.R.id.text2)).setText(item.getValue());
return result;
}
}
layout/my_adapter_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<TextView
android:id="@android:id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView
android:id="@android:id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
Your code:
public void showCinemas(HashMap<String, String> cinemas) {
MyAdapter adapter = new MyAdapter(cinemas);
list.setAdapter(adapter);
}
Solution 2
HashMap is made of 2 Collection (or better 1 Collection and 1 Set), so it is not really possible by extending ArrayAdapter; but you can easily get a Collection (or better a Set) of Map.Entry, and convert it to a List:
From:
Map<String, Object> map = new HashMap<String, Object>();
to:
List<Map.Entry<String, Object>> list = new ArrayList(map.entrySet());
So I use a derived ArrayAdapter like this one:
class HashMapArrayAdapter extends ArrayAdapter {
private static class ViewHolder {
TextView tV1;
TextView tV2;
}
public HashMapArrayAdapter(Context context, int textViewResourceId, List<Map.Entry<String, Object>> objects) {
super(context, textViewResourceId, objects);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(android.R.layout.simple_list_item_2, parent, false);
viewHolder = new ViewHolder();
viewHolder.tV1 = (TextView) convertView.findViewById(android.R.id.text1);
viewHolder.tV2 = (TextView) convertView.findViewById(android.R.id.text2);
convertView.setTag(viewHolder);
} else
viewHolder = (ViewHolder) convertView.getTag();
Map.Entry<String, Object> entry = (Map.Entry<String, Object>) this.getItem(position);
viewHolder.tV1.setText(entry.getKey());
viewHolder.tV2.setText(entry.getValue().toString());
return convertView;
}
And then to create the adapter:
ArrayAdapter adapter = new HashMapArrayAdapter(this.getActivity(), android.R.layout.simple_list_item_2, new ArrayList(map.entrySet()));
Solution 3
This has some similarities to Zanna's answer above, but is somewhat cleaner, improved and more comprehensive. I think this is about as simple as it gets.
Adapter:
public class MapEntryListAdapter extends ArrayAdapter<Map.Entry<String, Object>>
{
public MapEntryListAdapter (Context context, List<Map.Entry<String, Object>> entryList)
{
super (context, android.R.layout.simple_list_item_2, entryList);
}
@NonNull @Override
public View getView (int position, View convertView, ViewGroup parent)
{
View currentItemView = convertView != null ? convertView :
LayoutInflater.from (getContext ()).inflate (
android.R.layout.simple_list_item_2, parent, false);
Map.Entry<String, Object> currentEntry = this.getItem (position);
TextView textViewKey = currentItemView.findViewById (android.R.id.text1);
TextView textViewValue = currentItemView.findViewById (android.R.id.text2);
textViewKey.setText (currentEntry.getKey ());
textViewValue.setText (currentEntry.getValue ().toString ());
return currentItemView;
}
}
MainActivity - fields:
private Map<String, Object> mMapItems; // original data source of all items
private List<Map.Entry<String, Object>> mListOfMapEntries; // list of entries from mMapItems
private MapEntryListAdapter mMapEntryListAdapter;
MainActivity - onCreate method: (relevant portion)
mMapItems = new LinkedHashMap<> ();
mMapItems.put ("Test Key", "Test Value"); // put in sample item #1
mMapItems.put ("Sample Key", "Sample Value"); // put in sample item #2
mListOfMapEntries = new ArrayList<> (mMapItems.entrySet ()); // create the list
mMapEntryListAdapter = new MapEntryListAdapter (this, mListOfMapEntries);
ListView listView = findViewById (R.id.list_view);
listView.setAdapter (mMapEntryListAdapter);
Note: By design, the data source of this adapter does not duplicate the incoming entryList but rather points to the same actual list. This enables you to easily modify the Adapter's data in MainActivity or wherever else you have the reference to an Adapter of this object. You would then need to call the adapter's notifyDataSetChanged() method to let it know that the list has changed so that it updates the ListView to reflect these changes.
If the contents of your Map object changes later on, you could do the following to bring those updates into your list and then into your ListView:
mListOfMapEntries.clear ();
mListOfMapEntries.addAll (mMapItems.entrySet ());
mMapEntryListAdapter.notifyDataSetChanged ();
This clears the list of all existing items then adds the items from the Map to the list and then, very importantly, tells the adapter to update the ListView.
(Note: Do NOT create a new List object here (as opposed to clearing and adding shown here) because then you will not anymore be modifying the Adapter's data source which will still be pointing to the original list.)
Related videos on Youtube
Suleiman
Updated on January 21, 2020Comments
-
Suleiman over 4 years
I have HashMap, how can I to put it in ListView? Which adapter need to use?
public void showCinemas(HashMap<String, String> cinemas) { ...//What? list.setAdapter(adapter); }
-
Oleksii K. over 10 yearsHe need to show key-value pair in
ListView
, soArrayList
ofHashMap
will not help -
Phantômaxx over 10 yearsIf you set
data=null;
before adding data to listdata, you are always adding null to listdata. Am I wrong? -
RichieHH almost 10 yearsWhat do you mean "only array will suffice"? Nonsense. See full answer below. In this case I maintain my own hashmap but no arrays required.
-
Josh over 9 yearsGreat!! I am pulling a list of TV channels from a json: Image, name and number. The images load using the fetched URL with a self contained image downloader class. If you may need it tell me, Id be glad to share.
-
cafebabe1991 about 8 yearsShouldn't it be values() instead of entrySet ?
-
Madhan over 7 yearsHow to handle OnItemClickListener for this?
-
Carlo Matulessy almost 7 yearsI would suggest for future reference to change your entrySet() to values() as already suggested by @cafebabe1991 ;) Took me sometimes to notice this issue and read the comments below
-
Sam over 5 yearsI think it would be simpler to override ArrayAdapter rather than BaseAdapter. This way, you wouldn't have to override the methods that ArrayAdapter already includes, like getItem() and getCount().
-
Qadir Hussain about 4 yearsUpvote for mentioning the LinkedHashMap. HashMap has some auto sorting problem.
-
Amr SubZero over 3 yearsThe only thing that worked after long journey of trying! Thanks.