131
ArrayList<MyClass> myList = new ArrayList<MyClass>(); ListView listView = (ListView) findViewById(R.id.list); ArrayAdapter<MyClass> adapter = new ArrayAdapter<MyClass>(this, R.layout.row, to, myList.); listView.setAdapter(adapter); 

Class: MyClass

class MyClass { public String reason; public long long_val; } 

I have created row.xml in layouts, but don't know how to show both reason and long_val in the ListView using ArrayAdapter.

5 Answers 5

157

Implement custom adapter for your class:

public class MyClassAdapter extends ArrayAdapter<MyClass> { private static class ViewHolder { private TextView itemView; } public MyClassAdapter(Context context, int textViewResourceId, ArrayList<MyClass> items) { super(context, textViewResourceId, items); } public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = LayoutInflater.from(this.getContext()) .inflate(R.layout.listview_association, parent, false); viewHolder = new ViewHolder(); viewHolder.itemView = (TextView) convertView.findViewById(R.id.ItemView); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } MyClass item = getItem(position); if (item!= null) { // My layout has only one TextView // do whatever you want with your string and long viewHolder.itemView.setText(String.format("%s %d", item.reason, item.long_val)); } return convertView; } } 

For those not very familiar with the Android framework, this is explained in better detail here: https://github.com/codepath/android_guides/wiki/Using-an-ArrayAdapter-with-ListView.

Sign up to request clarification or add additional context in comments.

17 Comments

Sorry, MyClass item = items.get(position) solves the error, mismatches variables by me.
I've removed items field from above code, because it can easily lead to errors - for example if someone change internal list of items using adapter.clear() or adapter.add(...)
Am I correct in assuming textViewResourceId isn't used above?
where did viewHolder come from?
What is R.layout.listview_association? Is that your custom layout? Can I replace it with android.R.layout.simple_list_item_1?
|
80

You could just add a toString() method to MyClass, per http://developer.android.com/reference/android/widget/ArrayAdapter.html:

However the TextView is referenced, it will be filled with the toString() of each object in the array. You can add lists or arrays of custom objects. Override the toString() method of your objects to determine what text will be displayed for the item in the list.

class MyClass { @Override public String toString() { return "Hello, world."; } } 

5 Comments

Although the simplest solution, this is (IMHO) not a very good idea. Three reasons: If you ever need localization, you will have to refactor. This only works if you have 1 adapter, if you have 2 different adapters for MyClass, you wil have to refactor. Finally, it's generally a bad idea to tie presentation logic to your models. Models should not be aware of how they are presented to the user.
to address some of @fernandohur concerns you can simply create a dedicated view class for the ArrayAdapter... so a model class of type MyClass would require you to add a dedicated class called MyClassView which wraps the underlying model (and provides the toString( ) implementation
This answer was from 2011, and I agree with @fernandohur -- there are better ways of handling this now.
i think this is a good answer because, in a lot of times each class have an atribute than represent the name of the object.
This should be the accepted answer. Overriding an adapter just for binding the printed name is bad coding.
23

I think this is the best approach. Using generic ArrayAdapter class and extends your own Object adapter is as simple as follows:

public abstract class GenericArrayAdapter<T> extends ArrayAdapter<T> { // Vars private LayoutInflater mInflater; public GenericArrayAdapter(Context context, ArrayList<T> objects) { super(context, 0, objects); init(context); } // Headers public abstract void drawText(TextView textView, T object); private void init(Context context) { this.mInflater = LayoutInflater.from(context); } @Override public View getView(int position, View convertView, ViewGroup parent) { final ViewHolder vh; if (convertView == null) { convertView = mInflater.inflate(android.R.layout.simple_list_item_1, parent, false); vh = new ViewHolder(convertView); convertView.setTag(vh); } else { vh = (ViewHolder) convertView.getTag(); } drawText(vh.textView, getItem(position)); return convertView; } static class ViewHolder { TextView textView; private ViewHolder(View rootView) { textView = (TextView) rootView.findViewById(android.R.id.text1); } } } 

and here your adapter (example):

public class SizeArrayAdapter extends GenericArrayAdapter<Size> { public SizeArrayAdapter(Context context, ArrayList<Size> objects) { super(context, objects); } @Override public void drawText(TextView textView, Size object) { textView.setText(object.getName()); } } 

and finally, how to initialize it:

ArrayList<Size> sizes = getArguments().getParcelableArrayList(Constants.ARG_PRODUCT_SIZES); SizeArrayAdapter sizeArrayAdapter = new SizeArrayAdapter(getActivity(), sizes); listView.setAdapter(sizeArrayAdapter); 

I've created a Gist with TextView layout gravity customizable ArrayAdapter:

https://gist.github.com/m3n0R/8822803

5 Comments

I really liked your code a LOT, but it took me a while to figure out, why it was crashing with android.content.res.Resources$NotFoundException: Resource ID #0x0. You have in your generic adapter call on super(..,0,..), where 0 is actually a layout resource, which does not exist, so it must be changed to something else.. Also, your gist is 404
In the end I ended up changing a lot - layout of the dropdown menu was different than the layout of shown item, the drawText was only called on the spinner header, not on its items on clicked..
This should be valid as generic adapter. Could you solve the problem?
Yeah, I made it work. I realized you provide a solution for something a little different then what I wanted, but I was able to use your code as a starting point and make amendments in a way that it did for me what I wanted. Thanks for this piece of code.
This should be provided by default.
6

Subclass the ArrayAdapter and override the method getView() to return your own view that contains the contents that you want to display.

Comments

5

Here's a quick and dirty example of how to use an ArrayAdapter if you don't want to bother yourself with extending the mother class:

class MyClass extends Activity { private ArrayAdapter<String> mAdapter = null; @Override protected void onCreate(Bundle savedInstanceState) { mAdapter = new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_dropdown_item_1line, android.R.id.text1); final ListView list = (ListView) findViewById(R.id.list); list.setAdapter(mAdapter); //Add Some Items in your list: for (int i = 1; i <= 10; i++) { mAdapter.add("Item " + i); } // And if you want selection feedback: list.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //Do whatever you want with the selected item Log.d(TAG, mAdapter.getItem(position) + " has been selected!"); } }); } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.