Populating multiple list views on a single Activity by using RecyclerView in Android

Populating multiple list views on a single Activity by using RecyclerView in Android

    With RecyclerView, building list view is now more simple, especially with new "scrolling mechanism", we now can put multiple RecyclerViews into a single screen (Activity or Fragment) without customizing in code.
    In this tip, I will present this solution through combining NestedScrollView and RecyclerView in the activity layout file. Of course, if you use ListView, please read my previous post to find out the way to expand it's height to maximum to display all list items.

Configuration in the layout (XML) file

    Make a NestedScrollView work as the root view and put 2 RecyclerView objects as it's children views to build this layout:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    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="info.devexchanges.multiplerecyclerview.MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_vertical"
            android:paddingBottom="10dp"
            android:text="Asia"
            android:textStyle="bold" />

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/activity_horizontal_margin"
            android:gravity="center_vertical"
            android:paddingBottom="10dp"
            android:text="Europe"
            android:textStyle="bold" />

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler_1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </LinearLayout>
</android.support.v4.widget.NestedScrollView>
    And this is layout for each RecyclerView item:
item_recycler_view.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="8dp">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <ImageView
            android:id="@+id/image"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:src="@drawable/world"
            android:contentDescription="@null" />

        <TextView
            android:id="@+id/text"
            android:textColor="@color/colorPrimary"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textStyle="bold"
            android:layout_centerVertical="true"
            android:layout_toRightOf="@+id/image"
            android:layout_toEndOf="@+id/image"
            android:padding="10dp"
            android:text="@string/app_name" />
    </RelativeLayout>
</android.support.v7.widget.CardView>
    NOTE: In order to use RecyclerView, CardView and NestedScrollView from Design Support Library, you must add these dependencies to your app level build.gradle:
compile 'com.android.support:design:25.1.0'
compile 'com.android.support:recyclerview-v7:25.1.0'
compile 'com.android.support:cardview-v7:25.1.0'

Set LayoutManager and data in programmatically code

    Back to your main activity programmatically code, there is no special thing here, please set LayoutManager for each RecyclerView (here is LinearLayoutManager) and initializing data/"adapter" for them:
MainActivity.java
package info.devexchanges.multiplerecyclerview;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

public class MainActivity extends AppCompatActivity {

    private String[] asiaCountries = {"Vietnam", "China", "Japan", "Korea", "India", "Singapore", "Thailand", "Malaysia"};
    private String[] europeCountries = {"France", "Germany", "Sweden", "Denmark", "England", "Spain", "Portugal", "Norway"};

    private RecyclerView firstRecyclerView;
    private RecyclerView secondRecyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        firstRecyclerView = (RecyclerView)findViewById(R.id.recycler);
        secondRecyclerView = (RecyclerView)findViewById(R.id.recycler_1);

        //create and set layout manager for each RecyclerView
        RecyclerView.LayoutManager firstLayoutManager = new LinearLayoutManager(this);
        RecyclerView.LayoutManager secondLayoutManager = new LinearLayoutManager(this);

        firstRecyclerView.setLayoutManager(firstLayoutManager);
        secondRecyclerView.setLayoutManager(secondLayoutManager);

        //Initializing and set adapter for each RecyclerView
        RecyclerViewAdapter firstAdapter = new RecyclerViewAdapter(this, asiaCountries);
        RecyclerViewAdapter secondAdapter = new RecyclerViewAdapter(this, europeCountries);

        firstRecyclerView.setAdapter(firstAdapter);
        secondRecyclerView.setAdapter(secondAdapter);
    }
}
    And this is the sample "adapter" class for these RecyclerViews:
RecyclerViewAdapter.java
package info.devexchanges.multiplerecyclerview;

import android.app.Activity;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
    private Activity activity;
    private String[] strings;

    public RecyclerViewAdapter(Activity activity, String[] strings) {
        this.activity = activity;
        this.strings = strings;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = activity.getLayoutInflater();
        View view = inflater.inflate(R.layout.item_recycler_view, parent, false);

        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, final int position) {
        viewHolder.textView.setText(strings[position]);
    }

    @Override
    public int getItemCount() {
        return strings.length;
    }

    class ViewHolder extends RecyclerView.ViewHolder {
        private TextView textView;

        public ViewHolder(View view) {
            super(view);
            textView = (TextView) view.findViewById(R.id.text);
        }
    }
}

Running the project

    This is output of this sample project, you can see that I've build 2 list views into a single screen successful:

Final thought

    As you can see, with simple configuration in the activity layout file, you now can put make a screen which contains multiple list views by using RecyclerViews. Further, please check other posts about this widget on my blog:
Combining grid view and list view on a screen by using RecyclerViews Android

Combining grid view and list view on a screen by using RecyclerViews Android

    As you can read at my previous post, if you use GridView to build a grid layout and ListView to make a list layout in Android, putting these 2 widgets into a single screen is not easy, my solution is making a custom GridView which expanding it's full height and set it as the ListView's header later.
    But now, Google has released RecyclerView - the successor of 2 old widgets (ListView and GridView), we can build this design easily because of it's own scroll and reuse mechanism.
    Now, take a few time to read some important steps in this "combining work"!

Declaring Activity layout

    Firstly, you only need to put 2 RecyclerViews object to your activity/fragment layout. For better scroll later, please wrap theme in a NestedScrollView like this:
actiity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    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"
    android:background="#ffffe0"
    tools:context="info.devexchanges.gridlistrecyclerview.MainActivity">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingBottom="10dp"
            android:text="@string/os"
            android:textStyle="bold" />

        <android.support.v7.widget.RecyclerView
            android:id="@+id/grid"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingBottom="10dp"
            android:paddingTop="10dp"
            android:text="@string/corporation"
            android:textStyle="bold" />

        <android.support.v7.widget.RecyclerView
            android:id="@+id/list"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </LinearLayout>
</android.support.v4.widget.NestedScrollView>

Providing custom layouts for grid/list row

    Of course, you always need to creating layout for each RecyclerView item. In this project, every item is a CardView:
item_list.xml
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="8dp">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <ImageView
            android:id="@+id/image"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:layout_marginLeft="5dp"
            android:contentDescription="@string/app_name" />

        <TextView
            android:id="@+id/text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:layout_toRightOf="@+id/image"
            android:gravity="center" />
    </RelativeLayout>
</android.support.v7.widget.CardView>
item_grid.xml
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="5dp"
    app:cardCornerRadius="10dp">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center">

        <ImageView
            android:id="@+id/image"
            android:layout_width="120dp"
            android:layout_height="120dp"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="5dp"
            android:contentDescription="@null" />

        <TextView
            android:id="@+id/text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/image"
            android:layout_marginTop="5dp"
            android:background="@color/colorPrimaryDark"
            android:gravity="center"
            android:padding="5dp"
            android:textColor="#ffffff"
            android:textStyle="bold" />
    </RelativeLayout>
</android.support.v7.widget.CardView>

Creating adapter classes

    Now, we must create 2 adapter classes for 2 RecyclerViews based on RecyclerView.Adapter:
ListViewAdapter.java
package info.devexchanges.gridlistrecyclerview.adapter;

import android.app.Activity;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

import info.devexchanges.gridlistrecyclerview.R;
import info.devexchanges.gridlistrecyclerview.RecyclerViewItem;

public class ListViewAdapter extends RecyclerView.Adapter<ListViewAdapter.ViewHolder> {
    private Activity activity;
    private List<RecyclerViewItem> items;

    public ListViewAdapter(Activity activity, List<RecyclerViewItem> items) {
        this.activity = activity;
        this.items = items;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = activity.getLayoutInflater();
        View view = inflater.inflate(R.layout.item_list, parent, false);

        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, final int position) {
        viewHolder.imageView.setImageResource(items.get(position).getDrawableId());
        viewHolder.textView.setText(items.get(position).getName());
    }

    @Override
    public int getItemCount() {
        return items.size();
    }

    /**
     * View holder to display each RecylerView item
     */
    protected class ViewHolder extends RecyclerView.ViewHolder {
        private ImageView imageView;
        private TextView textView;

        public ViewHolder(View view) {
            super(view);
            imageView = (ImageView) view.findViewById(R.id.image);
            textView = (TextView)view.findViewById(R.id.text);
        }

    }
}
GridViewAdapter.java
package info.devexchanges.gridlistrecyclerview.adapter;

import android.app.Activity;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

import info.devexchanges.gridlistrecyclerview.R;
import info.devexchanges.gridlistrecyclerview.RecyclerViewItem;

public class GridViewAdapter extends RecyclerView.Adapter<GridViewAdapter.ViewHolder> {
    private List<RecyclerViewItem> items;
    private Activity activity;

    public GridViewAdapter(Activity activity, List<RecyclerViewItem> items) {
        this.activity = activity;
        this.items = items;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        LayoutInflater inflater = activity.getLayoutInflater();
        View view = inflater.inflate(R.layout.item_grid, viewGroup, false);

        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(GridViewAdapter.ViewHolder viewHolder, int position) {
        viewHolder.imageView.setImageResource(items.get(position).getDrawableId());
        viewHolder.textView.setText(items.get(position).getName());
    }

    @Override
    public int getItemCount() {
        return items.size();
    }

    /**
     * View holder to display each RecylerView item
     */
    protected class ViewHolder extends RecyclerView.ViewHolder {
        private ImageView imageView;
        private TextView textView;

        public ViewHolder(View view) {
            super(view);
            textView = (TextView)view.findViewById(R.id.text);
            imageView = (ImageView) view.findViewById(R.id.image);
        }
    }
}

Configuration in Activity/Fragment

    There is no special point in your activity or fragment programmatically code, locating all xml elements from layout file, create LayoutManager for RecyclerViews, initializing adapters and attaching them,...This is full code for my main activity:
MainActivity.java
package info.devexchanges.gridlistrecyclerview;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

import java.util.ArrayList;

import info.devexchanges.gridlistrecyclerview.adapter.GridViewAdapter;
import info.devexchanges.gridlistrecyclerview.adapter.ListViewAdapter;

public class MainActivity extends AppCompatActivity {

    private RecyclerView listView;
    private RecyclerView gridView;
    private ListViewAdapter listViewAdapter;
    private GridViewAdapter gridViewAdapter;
    private ArrayList<RecyclerViewItem> corporations;
    private ArrayList<RecyclerViewItem> operatingSystems;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listView = (RecyclerView) findViewById(R.id.list);
        gridView = (RecyclerView) findViewById(R.id.grid);

        setDummyData();

        listView.setHasFixedSize(true);
        gridView.setHasFixedSize(true);

        //set layout manager and adapter for "ListView"
        LinearLayoutManager horizontalManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
        listView.setLayoutManager(horizontalManager);
        listViewAdapter = new ListViewAdapter(this, corporations);
        listView.setAdapter(listViewAdapter);

        //set layout manager and adapter for "GridView"
        GridLayoutManager layoutManager = new GridLayoutManager(this, 2);
        gridView.setLayoutManager(layoutManager);
        gridViewAdapter = new GridViewAdapter(this, operatingSystems);
        gridView.setAdapter(gridViewAdapter);
    }

    private void setDummyData() {
        corporations = new ArrayList<>();
        corporations.add(new RecyclerViewItem(R.drawable.microsoft, "Microsoft"));
        corporations.add(new RecyclerViewItem(R.drawable.apple, "Apple"));
        corporations.add(new RecyclerViewItem(R.drawable.google, "Google"));
        corporations.add(new RecyclerViewItem(R.drawable.oracle, "Oracle"));
        corporations.add(new RecyclerViewItem(R.drawable.yahoo, "Yahoo"));
        corporations.add(new RecyclerViewItem(R.drawable.mozilla, "Mozilla"));

        operatingSystems = new ArrayList<>();
        operatingSystems.add(new RecyclerViewItem(R.drawable.bbos, "BlackBerry OS"));
        operatingSystems.add(new RecyclerViewItem(R.drawable.ios, "iOS"));
        operatingSystems.add(new RecyclerViewItem(R.drawable.tizen, "Tizen"));
        operatingSystems.add(new RecyclerViewItem(R.drawable.android, "Android"));
        operatingSystems.add(new RecyclerViewItem(R.drawable.symbian, "Symbian"));
        operatingSystems.add(new RecyclerViewItem(R.drawable.firefox_os, "Firefox OS"));
        operatingSystems.add(new RecyclerViewItem(R.drawable.wp_os, "Windows Phone OS"));
    }
}
And this is the POJO class of this project:
RecyclerViewItem.java
package info.devexchanges.gridlistrecyclerview;

public class RecyclerViewItem {

    private int drawableId;
    private String name;

    public RecyclerViewItem(int drawableId, String name) {
        this.drawableId = drawableId;
        this.name = name;
    }

    public int getDrawableId() {
        return drawableId;
    }

    public String getName() {
        return name;
    }
}
    NOTE: Never forget to put RecyclerView and CardView dependencies to your app-level build.gradle file:
compile 'com.android.support:recyclerview-v7:25.0.0'
compile 'com.android.support:cardview-v7:25.0.0'

Running application

    You'll have this output after complete this project:

Conclusions

    As you can see on the code above, RecyclerView can be put in ScrollView or NestedScrollView, which ListView/GridView cannot do. During work, as a Android developer, you should pay attention to the update features from Google to deal with the topic that problematic formerly. Through this post, I hope you can understand more about using RecyclerView in building list interface. Finally, you can take full code be click the button below!

Loading holder view in Android

    Most of mobile applications use online data through Internet connection. This mean users always need a period time to waiting data loaded from server to display on our applications interface. The matter here is during this loading process, as an fronted-end developer, what should we do with app interface without data? The simplest way is show a progress dialog, but in some cases, it's disadvantage because it restricts user actions and cause uncomfortable feeling.
    Some popular apps has an another approach: using loader view/loader holder. It's the default interface, visible when app launched and the data is blank. When data was loaded to device and available, loader holder view will disappear and real-data was displayed (usually by TextView and ImageView). This approach make your app seem smoothly and more friendly!
    In this post, I will present a third-party called loaderviewlibrary to make this interface, output of loader view may be like this:

Importing library

    Adding this dependency to your app-level build.gradle to use this library:
dependencies {
    compile 'com.elyeproj.libraries:loaderviewlibrary:1.0.3'
}
    Now, we have 2 objects to build the loader view named LoaderTextView and LoaderImageView.

Usages in XML

    Two above classes is subclass of TextView and ImageView so we can use them normally in xml files.
    Define Loader View for TextView in layout XML:
<com.elyeproj.loaderviewlibrary.LoaderTextView
     android:layout_width="match_parent"
     android:layout_height="wrap_content" />
    Loader View for ImageView defined in layout XML:
<com.elyeproj.loaderviewlibrary.LoaderImageView
     android:layout_width="100dp"
     android:layout_height="100dp" />
    Requirement: your project min-sdk must be 16 or higher.

Sample project

    Now, I will provide a sample project about using this library. I will load JSON and Bitmap from URLs and display to a list view. Declaring the main activity layout containing only a ListView first:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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="info.devexchanges.loaderview.MainActivity">

    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="none" />
</RelativeLayout>
    In each list view row (item), I have a LoaderTextView and LoaderImageView to display data later:
item_listview.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:paddingBottom="@dimen/activity_horizontal_margin">

    <com.elyeproj.loaderviewlibrary.LoaderImageView
        android:id="@+id/image_view"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_centerVertical="true" />

    <com.elyeproj.loaderviewlibrary.LoaderTextView
        android:id="@+id/text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_marginLeft="@dimen/activity_horizontal_margin"
        android:layout_toRightOf="@id/image_view"
        android:gravity="left"
        android:maxHeight="120dp" />
</RelativeLayout>
    Customizing a ListView adapter based on ArrayAdapter:
ListViewAdapter.java
package info.devexchanges.loaderview;

import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.squareup.picasso.Picasso;

import java.util.ArrayList;

public class ListViewAdapter extends ArrayAdapter<String> {

    private Activity activity;
    private boolean isLoadImage;
    private final static String IMAGE_URL = "http://i.imgur.com/cReBvDB.png";

    public ListViewAdapter(Activity context, int resource, ArrayList<String> objects, boolean isLoadImage) {
        super(context, resource, objects);
        this.activity = context;
        this.isLoadImage = isLoadImage;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        // If holder not exist then locate all view from UI file.
        if (convertView == null) {
            // inflate UI from XML file
            convertView = inflater.inflate(R.layout.item_listview, parent, false);
            // get all UI view
            holder = new ViewHolder(convertView);
            // set tag for holder
            convertView.setTag(holder);
        }  else {
            // if holder created, get tag from view
            holder = (ViewHolder) convertView.getTag();
        }

        if (!getItem(position).equals("")) {
            holder.countryName.setText(getItem(position));
        }
        if (isLoadImage) {
            Picasso.with(activity).load(IMAGE_URL).into(holder.imageView);
        }

        return convertView;
    }

    private class ViewHolder{

        private ImageView imageView;
        private TextView countryName;

        public ViewHolder (View view) {
            imageView = (ImageView)view.findViewById(R.id.image_view);
            countryName = (TextView)view.findViewById(R.id.text_view);
        }
    }
}
    In the main activity, data will be loaded from URL when click on a button in option menu. Before it's clicked, list view data is blank and the loader holders will appear. Source code for this activity:
MainActivity.java
package info.devexchanges.loaderview;

import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    private ListView listView;
    private ArrayList<String> strings;
    private ArrayAdapter<String> adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listView = (ListView)findViewById(R.id.list_view);
        strings = new ArrayList<>();

        for (int i = 0; i < 5; i++) {
            strings.add("");
        }

        adapter = new ListViewAdapter(this, R.layout.item_listview, strings, false);
        listView.setAdapter(adapter);
    }

    private void loadJSONDataFromURL() {
        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
               new GetJSONTask(MainActivity.this).execute();
            }
        }, 1000);
        Log.i("Main", "load data");
    }

    //parsing json after getting from Internet
    public void parseJsonResponse(String result) {
        strings.clear();
        try {
            JSONObject json = new JSONObject(result);
            JSONArray jArray = new JSONArray(json.getString("message"));
            for (int i = 0; i < jArray.length(); i++) {
                JSONObject jObject = jArray.getJSONObject(i);
                strings.add(jObject.getString("name"));
            }

            adapter.notifyDataSetChanged();
            Log.i("Main", "finish load data");
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.load) {
            adapter = new ListViewAdapter(this, R.layout.item_listview, strings, true);
            listView.setAdapter(adapter);
            loadJSONDataFromURL();
        }
        return super.onOptionsItemSelected(item);
    }
}
    And the menu file:
res/menu/main.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/load"
        android:title="Load Data"
        android:icon="@drawable/load"
        app:showAsAction="always" />
</menu>
    Important Note:
-    Request Internet permission in AndroidManifest.xml to get data from URLs:
<uses-permission android:name="android.permission.INTERNET"/>
-    I use Picasso library to load image from an URL, please add it's dependency to app-level build.gradle:
compile 'com.squareup.picasso:picasso:2.5.2'

Running application

    Output of this project:

Conclusions

    I have just present the simplest way to creating a loader view (loading holder) to "wait for data loading" in Android application. If your app has much complicated or big data, you should take attention in this solution instead of using progress dialog, your app UX will be better!
    Moreover, you can go to this library page on Github to read more details about it. Hope this is helpful with your work. Finally, you can get my full code by clicking the button below.

Building list and grid layout with RecyclerView in Android

Building list and grid layout with RecyclerView in Android

    In Android application development, we are used to using ListView and GridView to building a list or grid layout. Up to now, with Material Design has been published, by only one widget called RecyclerView, we can create both of them by changing it's LayoutManager. Moreover, with it, developer also can do some exciting animations with Action Bar when scrolling screen. So that, it's time we have to change to keep pace with the development of design technology.
    Through this post, I will present the way to creating horizontal/vertical list and grid layout with this new widget.

Layout Manager for RecyclerView

    The most important point in building layout type with RecyclerView is initializing it's LayoutManager. For example:
//create a horizontal list view
LinearLayoutManager horizontalManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, true);
.
.
//create a vertical list view
LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
.
.
//create a grid layout
GridLayoutManager layoutManager = new GridLayoutManager(this, 3); //3 is number of coloumn
    And attatch layout manager to RecyclerView with this method:
recyclerView.setLayoutManager(layoutManager);

Sample horizontal and vertical list view

    In this sample project, I put two type of list view in one screen. Make an activity layout simple like this:
activity_list_view.xml
<?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:orientation="vertical"
    android:padding="@dimen/activity_horizontal_margin">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="10dp"
        android:paddingTop="10dp"
        android:text="Horizontal ListView"
        android:textStyle="bold" />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/horizontal_recycler"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="10dp"
        android:paddingTop="10dp"
        android:text="Vertical ListView"
        android:textStyle="bold" />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyle_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>
    And it's programmatically code:
ListViewActivity.java
package info.devexchanges.recyclerview;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

public class ListViewActivity extends AppCompatActivity {

    private RecyclerView horizontalList;
    private RecyclerView verticalList;
    private HorizontalListAdapter horizontalAdapter;
    private VerticalListAdapter verticalAdapter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_list_view);

        horizontalList = (RecyclerView)findViewById(R.id.horizontal_recycler);
        verticalList = (RecyclerView)findViewById(R.id.recyle_view);

        horizontalList.setHasFixedSize(true);
        verticalList.setHasFixedSize(true);

        //set horizontal LinearLayout as layout manager to creating horizontal list view
        LinearLayoutManager horizontalManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
        horizontalList.setLayoutManager(horizontalManager);
        horizontalAdapter = new HorizontalListAdapter(this);
        horizontalList.setAdapter(horizontalAdapter);

        //set vertical LinearLayout as layout manager for vertial listview
        LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
        verticalList.setLayoutManager(layoutManager);
        verticalAdapter = new VerticalListAdapter(this);
        verticalList.setAdapter(verticalAdapter);
    }
}
    2 simple RecyclerView adapters in this case (like ListView adapter):
HorizontalListAdapter.java
package info.devexchanges.recyclerview;

import android.app.Activity;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.Toast;

public class HorizontalListAdapter extends RecyclerView.Adapter<HorizontalListAdapter.ViewHolder> {

    private Activity activity;

    public HorizontalListAdapter(Activity activity) {
        this.activity = activity;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        LayoutInflater inflater = activity.getLayoutInflater();
        View view = inflater.inflate(R.layout.item_horizontal_list, viewGroup, false);

        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(HorizontalListAdapter.ViewHolder viewHolder, final int position) {
        viewHolder.linearLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(activity, "Position clicked: " + position, Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public int getItemCount() {
        return 10;
    }

    /**
     * View holder to display each RecylerView item
     */
    protected class ViewHolder extends RecyclerView.ViewHolder {

        private LinearLayout linearLayout;

        public ViewHolder(View view) {
            super(view);
            linearLayout = (LinearLayout) view.findViewById(R.id.layout);
        }
    }
}
VerticalListAdapter.java

package info.devexchanges.recyclerview;

import android.app.Activity;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;

public class VerticalListAdapter extends RecyclerView.Adapter<VerticalListAdapter.ViewHolder> {

    private Activity activity;

    public VerticalListAdapter(Activity activity) {
        this.activity = activity;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = activity.getLayoutInflater();
        View view = inflater.inflate(R.layout.item_recycler_view, parent, false);

        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, final int position) {
        if ((position + 1) % 2 == 0) {
            viewHolder.imageView.setImageResource(R.drawable.even);
        } else {
            viewHolder.imageView.setImageResource(R.drawable.odd);
        }
        viewHolder.container.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(activity, "Position: " + position, Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public int getItemCount() {
        return 10;
    }

    /**
     * View holder to display each RecylerView item
     */
    protected class ViewHolder extends RecyclerView.ViewHolder {
        private ImageView imageView;
        private RelativeLayout container;

        public ViewHolder(View view) {
            super(view);
            imageView = (ImageView) view.findViewById(R.id.image);
            container = (RelativeLayout) view.findViewById(R.id.container);
        }

    }
}
    Running this activity, we'll have this output:

Sample grid view

    Similar with list view, grid layout by RecyclerView is not much complicated. Firstly, designing a layout:
activity_grid.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    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">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyle_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</RelativeLayout>
Simple programmatically code:
GridViewActivity.java
package info.devexchanges.recyclerview;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;

public class GridViewActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private GridViewAdapter adapter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_grid);

        recyclerView = (RecyclerView)findViewById(R.id.recyle_view);
        recyclerView.setHasFixedSize(true);

        //set GridLayoutManager
        GridLayoutManager layoutManager = new GridLayoutManager(this, 3);
        recyclerView.setLayoutManager(layoutManager);
        adapter = new GridViewAdapter(this);
        recyclerView.setAdapter(adapter);
    }
}
    Layout for each grid's item:
item_grid.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="120dp"
    android:layout_height="120dp">

    <ImageView
        android:id="@+id/image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"
        android:src="@drawable/sample_1" />

    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:background="#80000000"
        android:padding="10dp"
        android:textColor="#ffffff" />

</RelativeLayout>
    And the RecyclerView adapter:
GridViewAdapter.java
package info.devexchanges.recyclerview;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

public class GridViewAdapter extends RecyclerView.Adapter<GridViewAdapter.ViewHolder> {

    private Activity activity;

    public GridViewAdapter(Activity activity) {
        this.activity = activity;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        LayoutInflater inflater = activity.getLayoutInflater();
        View view = inflater.inflate(R.layout.item_grid, viewGroup, false);

        return new ViewHolder(view);
    }

    @SuppressLint("SetTextI18n")
    @Override
    public void onBindViewHolder(GridViewAdapter.ViewHolder viewHolder, final int position) {
        if (position % 3 == 0) {
            viewHolder.imageView.setImageResource(R.drawable.sample_3);
        } else if (position % 3 == 1) {
            viewHolder.imageView.setImageResource(R.drawable.sample_1);
        } else {
            viewHolder.imageView.setImageResource(R.drawable.sample_2);
        }
        viewHolder.textView.setText("Position: " + (position + 1));
        viewHolder.imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(activity, "You clicked at position: " + position, Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public int getItemCount() {
        return 10;
    }

    /**
     * View holder to display each RecylerView item
     */
    protected class ViewHolder extends RecyclerView.ViewHolder {

        private TextView textView;
        private ImageView imageView;

        public ViewHolder(View view) {
            super(view);
            imageView = (ImageView) view.findViewById(R.id.image);
            textView = (TextView) view.findViewById(R.id.text);
        }
    }
}
    Running it, we have this output:

RecyclerView weaknesses

    Through all codes above, you realize that RecyclerView has some own weakness, not perfect yet:
  • Cannot adding header/footer view easily like ListView (by call addHeaderView/addFooterView method). 
  • It's difficult to handle item clicked event.
  • Cannot "auto column" with grid layout. If you would like to set dynamic column for different devices, please initialize the manager with an integer resource value and provide different values for different screens (i.e. values-w600, values-large, values-land). 
    Even though, it still should be used. Hopefully, in the near future, RecyclerView will be fixed and improved to change itself better and the Material Design technology become more perfect. Moreover, you should read my previous post about RecyclerView and CardView as items to understand the adapter and it's own ViewHolder. Finally, project source code now availble on @Github.
Android Basic Training Course: Getting Fancy with ListView

Android Basic Training Course: Getting Fancy with ListView

    A normal ListView is one of the most important widgets in Android, simply because it is used frequently. No matter when you select a contact to make a call, an e-mail to forward, or an electronic book reader, the ListView widget are built to cater for all purposes above. Definitely it will more cool if they are not merely simple texts.

The first basic knowledge

    A classic ListView in Android is a list of simple text - dense but not attractive. Basically, we passed to ListView a string of words in an array and Android uses a simple layout is available to turn them into a list.
    However, we can have a list that is created by rows of icons, symbols and texts, check boxes and text, or anything that we want. It should be noted here is to provide enough data for the adapter and adapter help create a set of View objects fuller for each line.
    For example, suppose we wanted to have a ListView with items created by a symbol, followed by a text line. We can create a layout for a line that looks like this:
    This layout uses a LinearLayout to set the contents of a row, with a logo on the left and the content (with a custom font) on the right.
    However, by default, Android does not know we want to use this layout to your ListView. To create a link between them, we need to give your Adapter ID of layout custom resources mentioned above, so put this code in your Activity:
package devexchanges.info.basiclistview;

import android.annotation.SuppressLint;
import android.app.ListActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class ListViewDemo extends ListActivity {

    private TextView selection;
    private static final String[] items = { "lorem", "ipsum", "dolor", "sit",
            "amet", "consectetuer", "adipiscing", "elit", "morbi", "vel",
            "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam", "vel",
            "erat", "placerat", "ante", "porttitor", "sodales", "pellentesque",
            "augue", "purus" };

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.activity_list_demo);
        setListAdapter(new ArrayAdapter<>(this, R.layout.row, R.id.label, items));
        selection = (TextView) findViewById(R.id.selection);
    }

    @SuppressLint("SetTextI18n")
    public void onListItemClick(ListView parent, View v, int position, long id) {
        selection.setText(items[position] + " Clicked!");
    }
}
    Note: Reference to a layout (row.xml), we use R.layout as a prefix before the name of the XML file layout (R.layout.row). Code for this file in this sample project:
    Output when running this project:

Dynamic ListView

    As seen in the previous section, how to provide an alternative layout to use for the treatment of lines in the simplest case is very beautiful. However, what happens if we want to change icon based on the row data? For example, suppose we want to use a symbol for short words and other symbols for words long. In this case, we will need to extend our ListView adapter class from ArrayAdapter to customizing our logic. Specifically, we need to override the method getView():
package devexchanges.info.basiclistview;

import android.app.ListActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class DynamicDemo extends ListActivity {
    TextView selection;
    private static final String[] items = {"lorem", "ipsum", "dolor", "sit",
            "amet", "consectetuer", "adipiscing", "elit", "morbi", "vel",
            "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam", "vel",
            "erat", "placerat", "ante", "porttitor", "sodales", "pellentesque",
            "augue", "purus"};

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.activity_list_demo);
        setListAdapter(new IconicAdapter());
        selection = (TextView) findViewById(R.id.selection);
    }

    public void onListItemClick(ListView parent, View v, int position, long id) {
        selection.setText(items[position]);
    }

    private class IconicAdapter extends ArrayAdapter<String> {
        public IconicAdapter() {
            super(DynamicDemo.this, R.layout.row, R.id.label, items);
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            View row = super.getView(position, convertView, parent);
            ImageView icon = (ImageView) row.findViewById(R.id.icon);
            if (items[position].length() > 4) {
                icon.setImageResource(R.mipmap.ic_delete);
            } else {
                icon.setImageResource(R.mipmap.ic_check);
            }
            return (row);
        }
    }
}
    Our IconicAdapter - a nested class in the Activity within 2 methods. Firstly, it has a constructor with a parameter passed to ArrayAdapter similar to what we did in the previous example. Secondly, it has methods getView() is executed - do 2 works:
- It uses the method overrided from getView() super class, returns to us an object View of row - fitted by ArrayAdapter. Specifically, our words are put into the TextView by ArrayAdapter that do it in a normal way.
- It finds the ImageView object and apply to it the logic made to know which symbols should be used, reference to one of the two resources are R.mipmap.ic_check and R.mipmap.ic_delete) .
    With above row.xml file, this is output:

Recycling Views

    The execution getView() method in the previous example worked fine, but was not effective. Each time a user scrolls down or roll up, we had to create a new heap objects to contain the row view newly appear. It's a bad idea, wasteful memory and battery power and has some more risks. So, we will think about reuse the view.
    As you see in the code above, getView() has an important View parameter called convertView. Sometimes, convertView may be null. In such cases, we need to create an object for each of the first View (through convert XML structure file to View) - like we do in the previous example. However, if convertView not null, then obviously it is one of the objects View was we created earlier! It would appear primarily when users scroll ListView. When the new line appears, Android will recycle lines have been rolled over to prevent from the create this line. See this example:
public class ListViewDemo extends ListActivity {
    private TextView selection;
    private static final String[] items = {"lorem", "ipsum", "dolor", "sit",
            "amet", "consectetuer", "adipiscing", "elit", "morbi", "vel",
            "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam", "vel",
            "erat", "placerat", "ante", "porttitor", "sodales", "pellentesque",
            "augue", "purus"};

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.main);
        setListAdapter(new IconicAdapter());
        selection = (TextView) findViewById(R.id.selection);
    }

    public void onListItemClick(ListView parent, View v, int position, long id) {
        selection.setText(items[position]);
    }

    class IconicAdapter extends ArrayAdapter<String> {
        IconicAdapter() {
            super(ListViewDemo.this, R.layout.row, items);
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            View row = convertView;
            if (row == null) {
                LayoutInflater inflater = getLayoutInflater();
                row = inflater.inflate(R.layout.row, parent, false);
            }
            TextView label = (TextView) row.findViewById(R.id.label);
            label.setText(items[position]);
            ImageView icon = (ImageView) row.findViewById(R.id.icon);
            if (items[position].length() > 4) {
                icon.setImageResource(R.drawable.delete);
            } else {
                icon.setImageResource(R.drawable.ok);
            }
            return row;
        }
    }
}
    Here we check to see if the convertView is null and, if so we then inflate our row—but if it is not null, we just reuse it. The work to fill in the contents (icon image, text) is the same in either case. The advantage is that if the convertView is not null, we avoid the potentially expensive inflation step.

Use ViewHolder Pattern

    The most optimized design for ListView is using a ViewHolder class to recycling the views. All View objects have getTag() and setTag() methods. These allow you to associate an arbitrary object with the widget. That holder pattern uses that “tag” to hold an object that, in turn, holds each of the child widgets of interest. By attaching that holder to the row View, every time we use the row, we already have access to the child widgets we care about, without having to call findViewById() again.
    And you can see most of my post related ListView use this feature, a ViewHolder class can be very simple with a constructor which declared items through call findViewbyId() in it:
class ViewHolder {
 private class ViewHolder {

        private ImageView icon;
        private TextView text;

        public ViewHolder(View v) {
            icon = (ImageView)v.findViewById(R.id.icon);
            text = (TextView)v.findViewById(R.id.label);
        }
    }
     By it, in getView(), when convertView is null, we inflate the XML file and convert to View, after that,  linked it with the ViewHolder instance through call setTag(). Moreover, if convertView is not null, recycling it with the exist ViewHolder object with getTag():
 
            ViewHolder holder; //initialize a null ViewHolder object
            LayoutInflater inflater = (LayoutInflater) getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
            // If holder not exist then locate all view from UI file.
            if (convertView == null) {
                // inflate UI from XML file
                convertView = inflater.inflate(R.layout.row, parent, false);
                // get all UI view
                holder = new ViewHolder(convertView);
                // set tag for holder
                convertView.setTag(holder);
            } else {
                // if holder created, get tag from view
                holder = (ViewHolder) convertView.getTag();
            }
    With this design pattern, our ListView will be scrolled very smoothly, it's performance is optimized. You can realize it effect when the ListView data is much complicated. And this is full code for this Activity (extends from AppCompatActivity, not ListActivity like the examples above):
package info.devexchanges.listviewsample;

import android.app.Activity;
import android.app.ListActivity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private TextView selection;
    private ListView listView;
    private static final String[] items = {"lorem", "ipsum", "dolor", "sit",
            "amet", "consectetuer", "adipiscing", "elit", "morbi", "vel",
            "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam", "vel",
            "erat", "placerat", "ante", "porttitor", "sodales", "pellentesque",
            "augue", "purus"};

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.activity_main);
        selection = (TextView) findViewById(R.id.selection);
        listView = (ListView) findViewById(R.id.list);

        //set on click listener for each List Item
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
                selection.setText(items[position]);
            }
        });

        //set listview adapter
        ArrayAdapter<String> adapter = new IconicAdapter();
        listView.setAdapter(adapter);
    }

    private class IconicAdapter extends ArrayAdapter<String> {

        public IconicAdapter() {
            super(MainActivity.this, R.layout.row, items);
        }

        public View getView(int position, View convertView, ViewGroup parent) {

            ViewHolder holder; //initialize a null ViewHolder object
            LayoutInflater inflater = (LayoutInflater) getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
            // If holder not exist then locate all view from UI file.
            if (convertView == null) {
                // inflate UI from XML file
                convertView = inflater.inflate(R.layout.row, parent, false);
                // get all UI view
                holder = new ViewHolder(convertView);
                // set tag for holder
                convertView.setTag(holder);
            } else {
                // if holder created, get tag from view
                holder = (ViewHolder) convertView.getTag();
            }

            if (items[position].length() > 4) {
                holder.icon.setImageResource(R.mipmap.ic_delete);
            } else {
                holder.icon.setImageResource(R.mipmap.ic_check);
            }
            holder.text.setText(items[position]);

            return convertView;
        }
    }

    private class ViewHolder {

        private ImageView icon;
        private TextView text;

        public ViewHolder(View v) {
            icon = (ImageView)v.findViewById(R.id.icon);
            text = (TextView)v.findViewById(R.id.label);
        }
    }
}

Conclusions

    Once again, I would like to emphasize that ListView is the most important widget in Android, it is a fast way to organize data in a list format on the screen. From now on, you can visit my ListView tag link to read more useful tips about it. Up to the next chapter, I will guide about embedded the WebKit Browser to Android app. Finally, you can get full project code about ListView using ViewHolder pattern from +GitHub by click the button below.