RecyclerView -  an entirely updated approach to showing a collection of data. Google developers released this widget as an alternative to the predecessor: ListView. While most of what RecyclerView offers is an improvement over the existing functionality of ListView, there are a few notable features missing from the RecyclerView API. For example, we lost our dear friend OnItemClickListener and our lesser, but still kinda close friend, ChoiceModes. And if all that lost functionality wasn’t depressing enough, we also lost all of the sub-classes and custom implementations of ListView, like ExpandableListView.So, if we would like to build an expandable list view by
RecyclerView, we must customize it. Today, in this post, I will present a third-party library developed by ThoughtBot, Inc which I think it's the best to this time, which providing us a full-featured expandable list view.DEMO VIDEO:
Importing the library
build.gradle:
compile 'com.thoughtbot:expandablerecyclerview:1.0'
Customizing POJO classes
MobileOS (as a group object) and Phone (stand as child object):
MobileOS.java
package info.devexchanges.expandablerecyclerview.model;
import android.annotation.SuppressLint;
import com.thoughtbot.expandablerecyclerview.models.ExpandableGroup;
import java.util.List;
@SuppressLint("ParcelCreator")
public class MobileOS extends ExpandableGroup<Phone> {
    public MobileOS(String title, List<Phone> items) {
        super(title, items);
    }
}
Phone.java
    As you can see, the child class must implement package info.devexchanges.expandablerecyclerview.model;
import android.os.Parcel;
import android.os.Parcelable;
public class Phone implements Parcelable{
    private String name;
    public Phone(Parcel in) {
        name = in.readString();
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Phone(String name) {
        this.name = name;
    }
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
    }
    @Override
    public int describeContents() {
        return 0;
    }
    public static final Creator<Phone> CREATOR = new Creator<Phone>() {
        @Override
        public Phone createFromParcel(Parcel in) {
            return new Phone(in);
        }
        @Override
        public Phone[] newArray(int size) {
            return new Phone[size];
        }
    };
}
Parcelable and the group class must have a List of child class, express that a group has many children in expandable list view.Group and Child ViewHolder
GroupViewHolder and ChildViewHolder. These are both wrappers around regular original RecyclerView.ViewHolder so implement any view inflation and binding methods you may need:
OSViewHolder.java
    As you see, you can override package info.devexchanges.expandablerecyclerview.viewholder;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.thoughtbot.expandablerecyclerview.models.ExpandableGroup;
import com.thoughtbot.expandablerecyclerview.viewholders.GroupViewHolder;
import info.devexchanges.expandablerecyclerview.R;
public class OSViewHolder extends GroupViewHolder {
    private TextView osName;
    public OSViewHolder(View itemView) {
        super(itemView);
        osName = (TextView) itemView.findViewById(R.id.mobile_os);
    }
    @Override
    public void expand() {
        osName.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.down_arrow, 0);
        Log.i("Adapter", "expand");
    }
    @Override
    public void collapse() {
        Log.i("Adapter", "collapse");
        osName.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.up_arrow, 0);
    }
    public void setGroupName(ExpandableGroup group) {
        osName.setText(group.getTitle());
    }
}
expand() and collapse() to handling group view expand/collapse event.
PhoneViewHolder.java
    There are 2 xml files to display group and child views of the expandable list view:
package info.devexchanges.expandablerecyclerview.viewholder;
import android.view.View;
import android.widget.TextView;
import com.thoughtbot.expandablerecyclerview.models.ExpandableGroup;
import com.thoughtbot.expandablerecyclerview.viewholders.ChildViewHolder;
import info.devexchanges.expandablerecyclerview.R;
import info.devexchanges.expandablerecyclerview.model.Phone;
public class PhoneViewHolder extends ChildViewHolder {
    private TextView phoneName;
    public PhoneViewHolder(View itemView) {
        super(itemView);
        phoneName = (TextView) itemView.findViewById(R.id.phone_name);
    }
    public void onBind(Phone phone, ExpandableGroup group) {
        phoneName.setText(phone.getName());
        if (group.getTitle().equals("Android")) {
            phoneName.setCompoundDrawablesWithIntrinsicBounds(R.drawable.nexus, 0, 0, 0);
        } else if (group.getTitle().equals("iOS")) {
            phoneName.setCompoundDrawablesWithIntrinsicBounds(R.drawable.iphone, 0, 0, 0);
        } else {
            phoneName.setCompoundDrawablesWithIntrinsicBounds(R.drawable.window_phone, 0, 0, 0);
        }
    }
}
group_view_holder.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:background="@android:color/black">
    <TextView
        android:id="@+id/mobile_os"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:drawablePadding="5dp"
        android:drawableRight="@drawable/down_arrow"
        android:gravity="left|center"
        android:padding="8dp"
        android:textColor="#e6e600" />
</RelativeLayout>
child_view_holder.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">
    <TextView
        android:id="@+id/phone_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:padding="10dp" />
</RelativeLayout>
Creating RecyclerView adapter class
ExpandableRecyclerViewAdapter abstract class, we can customize a RecyclerView adapter. Requirement methods are similar with original RecyclerView.Adapter:
RecyclerAdapter.java
    The last step is creating a running activity. In it's xml file, please put a package info.devexchanges.expandablerecyclerview.adapter;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.thoughtbot.expandablerecyclerview.ExpandableRecyclerViewAdapter;
import com.thoughtbot.expandablerecyclerview.models.ExpandableGroup;
import java.util.List;
import info.devexchanges.expandablerecyclerview.R;
import info.devexchanges.expandablerecyclerview.model.MobileOS;
import info.devexchanges.expandablerecyclerview.model.Phone;
import info.devexchanges.expandablerecyclerview.viewholder.OSViewHolder;
import info.devexchanges.expandablerecyclerview.viewholder.PhoneViewHolder;
public class RecyclerAdapter extends ExpandableRecyclerViewAdapter<OSViewHolder, PhoneViewHolder> {
    private Activity activity;
    public RecyclerAdapter(Activity activity, List<? extends ExpandableGroup> groups) {
        super(groups);
        this.activity = activity;
    }
    @Override
    public OSViewHolder onCreateGroupViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(R.layout.group_view_holder, parent, false);
        return new OSViewHolder(view);
    }
    @Override
    public PhoneViewHolder onCreateChildViewHolder(ViewGroup parent, final int viewType) {
        LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(R.layout.child_view_holder, parent, false);
        return new PhoneViewHolder(view);
    }
    @Override
    public void onBindChildViewHolder(PhoneViewHolder holder, int flatPosition, ExpandableGroup group, int childIndex) {
        final Phone phone = ((MobileOS) group).getItems().get(childIndex);
        holder.onBind(phone,group);
    }
    @Override
    public void onBindGroupViewHolder(OSViewHolder holder, int flatPosition, ExpandableGroup group) {
        holder.setGroupName(group);
    }
}
RecyclerView object to this layout:
activity_main.xml
    In the Java code, it have no important point except set up <?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.expandablerecyclerview.MainActivity">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</RelativeLayout>
LayoutManager for RecyclerView. Moreover, if you want to save/restore it's expand/collapse state, please overriding onSaveInstanceState() and onRestoreInstanceState() method.Sour code for this activity:
MainActivity.java
    Running application, we'll have this output:package info.devexchanges.expandablerecyclerview;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;
import info.devexchanges.expandablerecyclerview.adapter.RecyclerAdapter;
import info.devexchanges.expandablerecyclerview.model.MobileOS;
import info.devexchanges.expandablerecyclerview.model.Phone;
public class MainActivity extends AppCompatActivity {
    private RecyclerView recyclerView;
    private ArrayList<MobileOS> mobileOSes;
    private RecyclerAdapter adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        mobileOSes = new ArrayList<>();
        setData();
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        adapter = new RecyclerAdapter(this, mobileOSes);
        recyclerView.setAdapter(adapter);
    }
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        adapter.onSaveInstanceState(outState);
    }
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        adapter.onRestoreInstanceState(savedInstanceState);
    }
    private void setData() {
        ArrayList<Phone> iphones = new ArrayList<>();
        iphones.add(new Phone("iPhone 4"));
        iphones.add(new Phone("iPhone 4S"));
        iphones.add(new Phone("iPhone 5"));
        iphones.add(new Phone("iPhone 5S"));
        iphones.add(new Phone("iPhone 6"));
        iphones.add(new Phone("iPhone 6Plus"));
        iphones.add(new Phone("iPhone 6S"));
        iphones.add(new Phone("iPhone 6S Plus"));
        ArrayList<Phone> nexus = new ArrayList<>();
        nexus.add(new Phone("Nexus One"));
        nexus.add(new Phone("Nexus S"));
        nexus.add(new Phone("Nexus 4"));
        nexus.add(new Phone("Nexus 5"));
        nexus.add(new Phone("Nexus 6"));
        nexus.add(new Phone("Nexus 5X"));
        nexus.add(new Phone("Nexus 6P"));
        nexus.add(new Phone("Nexus 7"));
        ArrayList<Phone> windowPhones = new ArrayList<>();
        windowPhones.add(new Phone("Nokia Lumia 800"));
        windowPhones.add(new Phone("Nokia Lumia 710"));
        windowPhones.add(new Phone("Nokia Lumia 900"));
        windowPhones.add(new Phone("Nokia Lumia 610"));
        windowPhones.add(new Phone("Nokia Lumia 510"));
        windowPhones.add(new Phone("Nokia Lumia 820"));
        windowPhones.add(new Phone("Nokia Lumia 920"));
        mobileOSes.add(new MobileOS("iOS", iphones));
        mobileOSes.add(new MobileOS("Android", nexus));
        mobileOSes.add(new MobileOS("Window Phone", windowPhones));
    }
}
Conclusions
RecyclerView. Of course, you can realize that my post don't provide the way to handle child view click event. Okey, the fact that this library has an another module called expandablecheckrecyclerview which provide the checkable child views (bot single and multi check mode) and handling the child view click event with  onCheckChildCLick interface, you can go to it's Github page to read and find out the way to use it.References:
- Library page on Github: https://github.com/thoughtbot/expandable-recycler-view
 - ThoughBot, Inc home page: https://thoughtbot.com/