The previous post, Create List Using ListView was about displaying an array of a list. It dealt with only one element in a list item. In order to display a List with multiple views in a list item, BaseAdapter could be used. A ListView using BaseAdapter could display a List with multiple views in it.
In this tutorial, we are going to create ListView using BaseAdapter. So, this tutorial covers following points.
– Create custom BaseAdapter, and
– Inflating a custom view as the list item.
Before proceeding with this tutorial, we would like to share one piece of advice. If it is a problem only a ListView can solve, then only use ListView. Android has provided a new component RecyclerView. It is similar to ListView implementation. But, have many modifications for memory management. In addition to that, RecyclerView also provides animations for transitions like addition, removal and update of the list item. For its implementation, we have provided a tutorial RecyclerView – Android.
Create Android Application Project
If you are new to Android Studio, then you could learn about creating new projects from our tutorial Create Android Application Project in Android Studio Continued.
Create Android application project with following attributes.
Project Name | CustomListViewDemo |
---|---|
Package Name | pcsalt.example.customlistviewdemo |
Minimum SDK Version | 21 |
Activity Type | Empty Activity |
Activity Name | MainActivity |
Layout Name | activity_name |
Prepare layout screens
activity_main.xml: Layout for MainActivity.java. For this demo application, it would contain only a ListView.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <ListView android:id="@+id/lvCustomList" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout>
layout_list_item.xml: Layout for list items to be displayed in ListView. In this list, each list item will display an ImageView and two TextView.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical" android:orientation="horizontal" android:padding="10dp"> <ImageView android:id="@+id/ivIcon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/star1" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/tvTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="5dp" android:text="Title" /> <TextView android:id="@+id/tvDesc" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="5dp" android:text="Description" /> </LinearLayout> </LinearLayout>
Create model class
ListData.java: This model class contains two String type values for Title and Description. imgResId is for displaying image in list items.
package pcsalt.example.customlistviewdemo; /* * ListData class will hold data for displaying in ListView * */ public class ListData { String Description; String title; int imgResId; public String getDescription() { return Description; } public void setDescription(String description) { Description = description; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public int getImgResId() { return imgResId; } public void setImgResId(int imgResId) { this.imgResId = imgResId; } }
Inherit BaseAdapter and modify according to functionality
MyBaseAdapter.java: Create a custom BaseAdapter to inflate the ListView items with layout_list_item.xml layout.
package pcsalt.example.customlistviewdemo; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import java.util.ArrayList; public class MyBaseAdapter extends BaseAdapter { ArrayList myList = new ArrayList(); LayoutInflater inflater; Context context; public MyBaseAdapter(Context context, ArrayList myList) { this.myList = myList; this.context = context; inflater = LayoutInflater.from(this.context); } @Override public int getCount() { return myList.size(); } @Override public ListData getItem(int position) { return myList.get(position); } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { MyViewHolder mViewHolder; if (convertView == null) { convertView = inflater.inflate(R.layout.layout_list_item, parent, false); mViewHolder = new MyViewHolder(convertView); convertView.setTag(mViewHolder); } else { mViewHolder = (MyViewHolder) convertView.getTag(); } ListData currentListData = getItem(position); mViewHolder.tvTitle.setText(currentListData.getTitle()); mViewHolder.tvDesc.setText(currentListData.getDescription()); mViewHolder.ivIcon.setImageResource(currentListData.getImgResId()); return convertView; } private class MyViewHolder { TextView tvTitle, tvDesc; ImageView ivIcon; public MyViewHolder(View item) { tvTitle = (TextView) item.findViewById(R.id.tvTitle); tvDesc = (TextView) item.findViewById(R.id.tvDesc); ivIcon = (ImageView) item.findViewById(R.id.ivIcon); } } }
Let us discuss this block of code
if (convertView == null) { convertView = inflater.inflate(R.layout.layout_list_item, parent, false); mViewHolder = new MyViewHolder(convertView); convertView.setTag(mViewHolder); } else { mViewHolder = (MyViewHolder) convertView.getTag(); }
In this code, we are checking if convertView is already initialized or not. If not, then inflate the list item layout, create ViewHolder object and save it in a tag of convertView. If convertView is already initialized, then retrieve the instance of ViewHolder from the convertView tag.
This is required to reuse the memory, which was already instantiated for previous list item. If this is not done, then for each new item getting displayed in the list will instantiate its own memory. And, it may cause OutOfMemoryException.
Populate BaseAdapter with data
To populate data into BaseAdapter, we will pass a List of model class from MainActivity.java
package pcsalt.example.customlistviewdemo; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.widget.ListView; import java.util.ArrayList; public class MainActivity extends Activity { ListView lvDetail; Context context = MainActivity.this; ArrayList myList = new ArrayList(); String[] title = new String[]{ "Title 1", "Title 2", "Title 3", "Title 4", "Title 5", "Title 6", "Title 7", "Title 8" }; String[] desc = new String[]{ "Desc 1", "Desc 2", "Desc 3", "Desc 4", "Desc 5", "Desc 6", "Desc 7", "Desc 8" }; int[] img = new int[]{ R.drawable.star1, R.drawable.star2, R.drawable.star3, R.drawable.star4, R.drawable.star5, R.drawable.star6, R.drawable.star7, R.drawable.star8 }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); lvDetail = (ListView) findViewById(R.id.lvCustomList); // insert data into the list before setting the adapter // otherwise it will generate NullPointerException - Obviously getDataInList(); lvDetail.setAdapter(new MyBaseAdapter(context, myList)); } private void getDataInList() { for (int i = 0; i < title.length; i++) { // Create a new object for each list item ListData ld = new ListData(); ld.setTitle(title[i]); ld.setDescription(desc[i]); ld.setImgResId(img[i]); // Add this object into the ArrayList myList myList.add(ld); } } }