Pages

Friday, January 5, 2018

Custom Recyclerview with Adapter


Custom Recycler view demo.


Add the gradle dependency to your app build.gradle file

compile 'com.android.support:recyclerview-v7:25.3.1'
Demo

Models class

import java.util.ArrayList;
import java.util.List;

public class Getdata {

    public List<Data> data = new ArrayList<>();

    public Pagination pagination = new Pagination();

    public Meta meta = new Meta();

    public class Meta {
        public String status;
        public String msg;
    }

    public class Pagination {
        public String count;
    }

    public class Data {
        public Images images = new Images();

        public String username;

        public class Images {


            public Fixed_width_small_still fixed_width_small_still = new Fixed_width_small_still();

            public FixedHeight fixed_height = new FixedHeight();

            public Preview_gif preview_gif = new Preview_gif();

            public class Preview_gif {
                public String url;
            }

            public class FixedHeight{
                public String url;
                public String width;
                public String height;
            }

            public class Fixed_width_small_still {
                public String url;
                public String width;
                public String height;
            }
        }
    }
}

StaggeredGridLayoutActivity.java

public class StaggeredGridLayoutActivity extends AppCompatActivity {
    private ProgressDialogFragment progressDialogFragment;

    StaggeredGridLayutAdapter mAdapter;

    @BindView(R.id.recycler_view)
    RecyclerView recycler_view;

    private EndlessRecyclerViewScrollListener endlessscrollListener;
    public int page = 0;
    private StaggeredGridLayoutManager staggeredGridLayoutManager;
    ArrayList<Getdata.Data> getDataArray;
    Getdata getdatas;

     @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_staggeredgridlayout);
        ButterKnife.bind(this);
        getDataArray = new ArrayList<>();
        staggeredGridLayoutManager = new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.HORIZONTAL);
        staggeredGridLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
//        staggeredGridLayoutManager.invalidateSpanAssignments();
        recycler_view.setLayoutManager(staggeredGridLayoutManager);
        mAdapter = new StaggeredGridLayutAdapter(this, getDataArray);
        recycler_view.setAdapter(mAdapter);

        endlessscrollListener = new EndlessRecyclerViewScrollListener(staggeredGridLayoutManager) {
            @Override
            public void onLoadMore(int page, int totalItemsCount, RecyclerView view) {
                Log.e("Page==", page + "" + " total==" + totalItemsCount);
                loadMore(getDataArray.size() + 1);
            }
        };
        recycler_view.addOnScrollListener(endlessscrollListener);
        getData(page);
    }

    private void getData(int page) {
        showProgressDailog("Please Wait");
        WebserviceApi webserviceApi = ServiceGenerator.createService(WebserviceApi.class);
        Call<Getdata> getdataCall = webserviceApi.getGifDatas("dc6zaTOxFJmzC", page + "");
        getdataCall.enqueue(new Callback<Getdata>() {
            @Override
            public void onResponse(Call<Getdata> call, Response<Getdata> response) {
                hideProgressDialog();
                Log.e("getData success", "getData success");
                getdatas = response.body();
                if (getDataArray != null) {
                    getDataArray.addAll(getdatas.data);
                    mAdapter.notifyDataChanged();
                }
            }

            @Override
            public void onFailure(Call<Getdata> call, Throwable t) {
                hideProgressDialog();
                Log.e("Fail", "fail");
            }
        });
    }

    public void loadMore(int page) {
        WebserviceApi webserviceApi = ServiceGenerator.createService(WebserviceApi.class);

        Call<Getdata> getdataCall = webserviceApi.getGifDatas("dc6zaTOxFJmzC", page + "");
        getdataCall.enqueue(new Callback<Getdata>() {
            @Override
            public void onResponse(Call<Getdata> call, Response<Getdata> response) {
                Log.e("loadMore success", "loadMore success");
                getdatas = response.body();
                if (getDataArray.size() > 0) {
                    if (getDataArray != null) {
                        getDataArray.addAll(getdatas.data);
                        mAdapter.notifyDataChanged();
                    } else {
                        Toast.makeText(StaggeredGridLayoutActivity.this, "No More Data Available", Toast.LENGTH_LONG).show();
                    }
                }
            }

            @Override
            public void onFailure(Call<Getdata> call, Throwable t) {
                Log.e("Fail", "fail");
            }
        });
    }

    public void showProgressDailog(String message) {
        progressDialogFragment = new ProgressDialogFragment(message);
        progressDialogFragment.show(getFragmentManager(), "");
        progressDialogFragment.setCancelable(false);
    }

    public void hideProgressDialog() {
        try {
            if (progressDialogFragment != null) {
                progressDialogFragment.dismiss();
            }
        } catch (Exception e) {
        }
    }

}


EndlessRecyclerViewScrollListener.java


import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;

public abstract class EndlessRecyclerViewScrollListener extends RecyclerView.OnScrollListener {
    // The minimum amount of items to have below your current scroll position
    // before loading more.
    private int visibleThreshold = 5;
    // The current offset index of data you have loaded
    private int currentPage = 0;
    // The total number of items in the dataset after the last load
    private int previousTotalItemCount = 0;
    // True if we are still waiting for the last set of data to load.
    private boolean loading = true;
    // Sets the starting page index
    private int startingPageIndex = 0;

    RecyclerView.LayoutManager mLayoutManager;

    public EndlessRecyclerViewScrollListener(LinearLayoutManager layoutManager) {
        this.mLayoutManager = layoutManager;
    }

    public EndlessRecyclerViewScrollListener(GridLayoutManager layoutManager) {
        this.mLayoutManager = layoutManager;
        visibleThreshold = visibleThreshold * layoutManager.getSpanCount();
    }

    public EndlessRecyclerViewScrollListener(StaggeredGridLayoutManager layoutManager) {
        this.mLayoutManager = layoutManager;
        visibleThreshold = visibleThreshold * layoutManager.getSpanCount();
    }

    public int getLastVisibleItem(int[] lastVisibleItemPositions) {
        int maxSize = 0;
        for (int i = 0; i < lastVisibleItemPositions.length; i++) {
            if (i == 0) {
                maxSize = lastVisibleItemPositions[i];
            }
            else if (lastVisibleItemPositions[i] > maxSize) {
                maxSize = lastVisibleItemPositions[i];
            }
        }
        return maxSize;
    }

    // This happens many times a second during a scroll, so be wary of the code you place here.
    // We are given a few useful parameters to help us work out if we need to load some more data,
    // but first we check if we are waiting for the previous load to finish.
    @Override
    public void onScrolled(RecyclerView view, int dx, int dy) {
        int lastVisibleItemPosition = 0;
        int totalItemCount = mLayoutManager.getItemCount();

        if (mLayoutManager instanceof StaggeredGridLayoutManager) {
            int[] lastVisibleItemPositions = ((StaggeredGridLayoutManager) mLayoutManager).findLastVisibleItemPositions(null);
            // get maximum element within the list
            lastVisibleItemPosition = getLastVisibleItem(lastVisibleItemPositions);
        } else if (mLayoutManager instanceof GridLayoutManager) {
            lastVisibleItemPosition = ((GridLayoutManager) mLayoutManager).findLastVisibleItemPosition();
        } else if (mLayoutManager instanceof LinearLayoutManager) {
            lastVisibleItemPosition = ((LinearLayoutManager) mLayoutManager).findLastVisibleItemPosition();
        } 

        // If the total item count is zero and the previous isn't, assume the
        // list is invalidated and should be reset back to initial state
        if (totalItemCount < previousTotalItemCount) {
            this.currentPage = this.startingPageIndex;
            this.previousTotalItemCount = totalItemCount;
            if (totalItemCount == 0) {
                this.loading = true;
            }
        }
        // If it’s still loading, we check to see if the dataset count has
        // changed, if so we conclude it has finished loading and update the current page
        // number and total item count.
        if (loading && (totalItemCount > previousTotalItemCount)) {
            loading = false;
            previousTotalItemCount = totalItemCount;
        }

        // If it isn’t currently loading, we check to see if we have breached
        // the visibleThreshold and need to reload more data.
        // If we do need to reload some more data, we execute onLoadMore to fetch the data.
        // threshold should reflect how many total columns there are too
        if (!loading && (lastVisibleItemPosition + visibleThreshold) > totalItemCount) {
            currentPage++;
            onLoadMore(currentPage, totalItemCount, view);
            loading = true;
        }
    }
    
    // Call this method whenever performing new searches
    public void resetState() {
        this.currentPage = this.startingPageIndex;
        this.previousTotalItemCount = 0;
        this.loading = true;
    }

    // Defines the process for actually loading more data based on page
    public abstract void onLoadMore(int page, int totalItemsCount, RecyclerView view);

}


StaggeredGridLayutAdapter.java


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

    Context mContext;
    boolean isLoading = false, isMoreDataAvailable = true;
    ArrayList<Getdata.Data> getDataArray;

    public StaggeredGridLayutAdapter(Context context, ArrayList<Getdata.Data> dataList) {
        getDataArray = dataList;
        mContext = context;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(mContext).inflate(R.layout.staggered_list_item, parent, false);
        return new MyViewHolder(view);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        //if (holder instanceof MyViewHolder) {
        MyViewHolder myViewHolder = (MyViewHolder) holder;
        Getdata.Data data = getDataArray.get(position);
        myViewHolder.country_name.setText(data.username);

        Glide.with(mContext).load(data.images.fixed_height.url).placeholder(R.drawable.ic_launcher).diskCacheStrategy(DiskCacheStrategy.ALL).crossFade().
                into(((MyViewHolder) holder).country_photo);

    }

    @Override
    public int getItemCount() {
        return getDataArray == null ? 0 : getDataArray.size();
    }

    public void notifyDataChanged() {
        notifyDataSetChanged();
        isLoading = false;
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {

        public ImageView country_photo;
        public TextView country_name;
//        GifImageView gifImageView;

        public MyViewHolder(View itemView) {
            super(itemView);
//            gifImageView = (GifImageView) itemView.findViewById(R.id.gifimgView);
            country_photo = (ImageView) itemView.findViewById(R.id.country_photo);
            country_name = (TextView) itemView.findViewById(R.id.country_name);
        }
    }
}


activity_staggeredgridlayout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="8dp">

    <!--<android.support.v4.widget.SwipeRefreshLayout-->
    <!--android:id="@+id/swipe_container"-->
    <!--android:layout_width="match_parent"-->
    <!--android:layout_height="match_parent">-->

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="horizontal" />
    <!--</android.support.v4.widget.SwipeRefreshLayout>-->

</LinearLayout>

staggered_list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    card_view:cardUseCompatPadding="true">


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

        <ImageView
            android:id="@+id/country_photo"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:adjustViewBounds="true"
            android:scaleType="fitXY" />

        <TextView
            android:id="@+id/country_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#1976D2"
            android:gravity="center_horizontal"
            android:paddingBottom="8dp"
            android:paddingTop="8dp"
            android:text="@string/hello_world"
            android:textColor="#ffffff"
            android:textSize="12dp"
            android:visibility="gone" />

    </LinearLayout>

</RelativeLayout>

Wednesday, September 20, 2017

Deep Linking Demo

First of all login Or SignUp in https://dashboard.branch.io/

Now Login in to https://dashboard.branch.io/login


Add dependency in build.gradle file

compile 'io.branch.sdk.android:library:2.8.0'


Code
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import io.branch.indexing.BranchUniversalObject;
import io.branch.referral.Branch;
import io.branch.referral.BranchError;
import io.branch.referral.util.LinkProperties;

public class DeepLinking extends AppCompatActivity {

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

    @Override
    public void onStart() {
        super.onStart();
        Branch branch = Branch.getInstance();

        branch.initSession(new Branch.BranchUniversalReferralInitListener() {
            @Override
            public void onInitFinished(BranchUniversalObject branchUniversalObject, LinkProperties linkProperties, BranchError error) {
                if (error == null) {
                    // params are the deep linked params associated with the link that the user clicked -> was re-directed to this app
                    // params will be empty if no data found
                    // ... insert custom logic here ...
                } else {
                    Log.i("MyApp", error.getMessage());
                }
            }
        }, this.getIntent().getData(), this);
    }


    @Override
    protected void onNewIntent(Intent intent) {
//        super.onNewIntent(intent);
        this.setIntent(intent);

    }

}

Change StatusBar color android

Using following way we can change statusbar color 

We also have to check version of the os for change statusbar color.


CustomControlsActivity.java

public class CustomControlsActivity extends AppCompatActivity {


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.custom_controls_layout);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.colorPrimaryDark));
        }
    }

}


Wednesday, September 6, 2017

Facebook Login Integration

The Facebook SDK for Android enables people to sign into your app with Facebook Login. When people log into your app with Facebook they can grant permissions to your app so you can retrieve information or perform actions on Facebook on their behalf.


Generate your app signature for facebook

1)Open Command prompt
2)Fire Keytool command

keytool -exportcert -alias androiddebugkey -keystore "&lt;path-to-users-directory&gt;\.android\debug.keystore" | openssl sha1 -binary | openssl base64

KeyTool Path from file location

keytool -exportcert -alias androiddebugkey -keystore "C:\Users\Your name\.android\debug.keystore" | openssl sha1 -binary | openssl base64

3)While you generating key hash it will ask for password you have to give password android

Create Application after generating kayhash

Create your new facebook application using below link

https://developers.facebook.com/apps



Add Gradle dependency to build.gradle in your android studio project

compile 'com.facebook.android:facebook-android-sdk:4.23.0'
Add to your AndroidManifest.xml

<meta-data
            android:name="com.facebook.sdk.ApplicationId"
            android:value="your created facebook_app_id" />
        <meta-data
            android:name="com.facebook.sdk.AutoLogAppEventsEnabled"
            android:value="false" />

        <activity
            android:name="com.facebook.FacebookActivity"
            android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
            android:label="@string/app_name" />
        <activity
            android:name="com.facebook.CustomTabActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data android:scheme="@string/fb_login_protocol_scheme" />
            </intent-filter>
        </activity>

        <provider
            android:name="com.facebook.FacebookContentProvider"
            android:authorities="com.facebook.app.FacebookContentProvider1234"

            android:exported="true" />



==> activity_facebook_login.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:layout_margin="15dp"
    android:gravity="center"
    android:orientation="vertical">


    <RelativeLayout
        android:id="@+id/rl_facebook_invite"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="15dp"
        android:background="@drawable/bg_btn_rounded_fb"
        android:gravity="center">

        <ImageView
            android:id="@+id/iv_fb_logo"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginRight="10dp"
            android:src="@drawable/icon_facebook" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_toEndOf="@+id/iv_fb_logo"
            android:layout_toRightOf="@+id/iv_fb_logo"
            android:paddingBottom="10dp"
            android:paddingTop="10dp"
            android:text="Invite Friend"
            android:textColor="@color/white"
            android:textSize="18dp"
            android:textStyle="bold" />

    </RelativeLayout>


    <com.facebook.login.widget.LoginButton
        android:id="@+id/login_button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="15dp"
        android:paddingBottom="10dp"
        android:paddingTop="10dp"
        android:textSize="18dp" />



</LinearLayout>


==>FaceBookLoginActivity.java

import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.RelativeLayout;

import com.facebook.CallbackManager;
import com.facebook.FacebookCallback;
import com.facebook.FacebookException;
import com.facebook.FacebookSdk;
import com.facebook.appevents.AppEventsLogger;
import com.facebook.login.LoginManager;
import com.facebook.login.LoginResult;
import com.facebook.login.widget.LoginButton;
import com.facebook.share.model.AppInviteContent;
import com.facebook.share.widget.AppInviteDialog;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import butterknife.BindView;
import butterknife.ButterKnife;


public class FaceBookLoginActivity extends AppCompatActivity implements View.OnClickListener {

    @BindView(R.id.rl_facebook_invite)
    RelativeLayout rl_facebook_invite;

    @BindView(R.id.login_button)
    LoginButton login_button;


    String appLinkUrl, previewImageUrl;
    CallbackManager callbackManager;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_facebook_login);
        ButterKnife.bind(this);

        init();
        printHashKey();
        rl_facebook_invite.setOnClickListener(this);
    }

    public void printHashKey() {
        // Add code to print out the key hash
        try {
            PackageInfo info = getPackageManager().getPackageInfo(
                    "com.yourpackage.name",
                    PackageManager.GET_SIGNATURES);
            for (Signature signature : info.signatures) {
                MessageDigest md = MessageDigest.getInstance("SHA");
                md.update(signature.toByteArray());
                Log.d("Facebook KeyHash:", Base64.encodeToString(md.digest(), Base64.DEFAULT));
            }
        } catch (PackageManager.NameNotFoundException e) {

        } catch (NoSuchAlgorithmException e) {

        }
    }

    private void init() {
        FacebookSdk.sdkInitialize(getApplicationContext());
        AppEventsLogger.activateApp(this);

//        if User want to logout from facebook than use following statement
//        LoginManager.getInstance().logOut();

        callbackManager = CallbackManager.Factory.create();

        // Callback registration
        login_button.registerCallback(callbackManager, new FacebookCallback<LoginResult>() {
            @Override
            public void onSuccess(LoginResult loginResult) {
                // App code
            }

            @Override
            public void onCancel() {
                // App code
            }

            @Override
            public void onError(FacebookException exception) {
                // App code
            }
        });

        LoginManager.getInstance().registerCallback(callbackManager,
                new FacebookCallback<LoginResult>() {
                    @Override
                    public void onSuccess(LoginResult loginResult) {
                        // App code
                    }

                    @Override
                    public void onCancel() {
                        // App code
                    }

                    @Override
                    public void onError(FacebookException exception) {
                        // App code
                    }
                });
    }

    @Override
    public void onClick(View view) {
        if (view.getId() == R.id.rl_facebook_invite) {
            //Facebook App invites friends
            appLinkUrl = "your app link url";
            previewImageUrl = "preview image url";

//                Uri targetUrl = AppLinks.getTargetUrlFromInboundIntent(SocialMediaLoginActivity.this, getIntent());
//                if (targetUrl != null) {
//                    Log.i("Activity", "App Link Target URL: " + targetUrl.toString());
//                }

            if (AppInviteDialog.canShow()) {
                AppInviteContent content = new AppInviteContent.Builder()
                        .setApplinkUrl(appLinkUrl)
                        .setPreviewImageUrl(previewImageUrl)
//                    .setPromotionDetails("Example Promotional Message", "EXAMPLEPROMO ")
                        .build();
                AppInviteDialog.show(FaceBookLoginActivity.this, content);
            }
        }
    }

}

ExpandableListView Demo

Android ExpandableListViewAndroid ExpandableListView is a view that shows items in a vertically scrolling two-level list. It differs from a ListView by allowing two levels which are groups that can be easily expanded and collapsed by touching to view and their respective children items.


==> activity_expandablelistview.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimary"
        android:titleTextColor="@color/white"
        app:titleTextColor="@color/white"></android.support.v7.widget.Toolbar>

    <ExpandableListView
        android:id="@+id/lvExp"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />


</LinearLayout>


==>list_item.xml (Listview Item Row)

<?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="wrap_content"
    android:layout_gravity="left"
    android:background="#ffffff"
    android:orientation="horizontal" >

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

        <TextView
            android:id="@+id/tv_event"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="3dp"
            android:text="TextView"
            android:textColor="#000000"
            android:textSize="16dp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/tv_date"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:padding="4dp"
            android:text="TextView" />

    </LinearLayout>


</LinearLayout>

==> ExpandableListAdapter.java

import java.util.HashMap;
import java.util.List;

import android.content.Context;
import android.graphics.Typeface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.TextView;


public class ExpandableListAdapter extends BaseExpandableListAdapter {

    private Context _context;
    private List<String> _listDataHeader; // header titles
    // child data in format of header title, child title
    private HashMap<String, List<String>> _listDataChild;

    public ExpandableListAdapter(Context context, List<String> listDataHeader,
                                 HashMap<String, List<String>> listChildData) {
        this._context = context;
        this._listDataHeader = listDataHeader;
        this._listDataChild = listChildData;
    }

    @Override
    public Object getChild(int groupPosition, int childPosititon) {
        return this._listDataChild.get(this._listDataHeader.get(groupPosition))
                .get(childPosititon);
    }

    @Override
    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    @Override
    public View getChildView(int groupPosition, final int childPosition,
                             boolean isLastChild, View convertView, ViewGroup parent) {

        final String childText = (String) getChild(groupPosition, childPosition);

        if (convertView == null) {
            LayoutInflater infalInflater = (LayoutInflater) this._context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = infalInflater.inflate(R.layout.list_item, null);
        }

        TextView txtListChild = (TextView) convertView
                .findViewById(R.id.tv_event);//lblListItem

        txtListChild.setText(childText);
        return convertView;
    }

    @Override
    public int getChildrenCount(int groupPosition) {
        return this._listDataChild.get(this._listDataHeader.get(groupPosition))
                .size();
    }

    @Override
    public Object getGroup(int groupPosition) {
        return this._listDataHeader.get(groupPosition);
    }

    @Override
    public int getGroupCount() {
        return this._listDataHeader.size();
    }

    @Override
    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    @Override
    public View getGroupView(int groupPosition, boolean isExpanded,
                             View convertView, ViewGroup parent) {
        String headerTitle = (String) getGroup(groupPosition);
        if (convertView == null) {
            LayoutInflater infalInflater = (LayoutInflater) this._context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = infalInflater.inflate(R.layout.list_group, null);
        }

        TextView lblListHeader = (TextView) convertView
                .findViewById(R.id.lblListHeader);
        lblListHeader.setTypeface(null, Typeface.BOLD);
        lblListHeader.setText(headerTitle);

        return convertView;
    }

    @Override
    public boolean hasStableIds() {
        return false;
    }

    @Override
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;
    }

}

==> ExpandableListViewActivity.java

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.widget.ExpandableListView;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;


public class ExpandableListViewActivity extends AppCompatActivity {

    ExpandableListAdapter listAdapter;

    @BindView(R.id.lvExp)
    ExpandableListView expListView;

    @BindView(R.id.toolbar)
    Toolbar toolbar;

    List<String> listDataHeader;
    HashMap<String, List<String>> listDataChild;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_expandablelistview);
        ButterKnife.bind(this);
        setSupportActionBar(toolbar);
        getSupportActionBar().setTitle("Expandable Listview");
        prepareListData();

        listAdapter = new ExpandableListAdapter(this, listDataHeader, listDataChild);

        // setting list adapter
        expListView.setAdapter(listAdapter);
    }

    private void prepareListData() {
        listDataHeader = new ArrayList<String>();
        listDataChild = new HashMap<String, List<String>>();

        // Adding child data
        listDataHeader.add("Top 250");
        listDataHeader.add("Now Showing");
        listDataHeader.add("Coming Soon..");

        // Adding child data
        List<String> top250 = new ArrayList<String>();
        top250.add("The Shawshank Redemption");
        top250.add("The Godfather");
        top250.add("The Godfather: Part II");
        top250.add("Pulp Fiction");
        top250.add("The Good, the Bad and the Ugly");
        top250.add("The Dark Knight");
        top250.add("12 Angry Men");

        List<String> nowShowing = new ArrayList<String>();
        nowShowing.add("The Conjuring");
        nowShowing.add("Despicable Me 2");
        nowShowing.add("Turbo");
        nowShowing.add("Grown Ups 2");
        nowShowing.add("Red 2");
        nowShowing.add("The Wolverine");

        List<String> comingSoon = new ArrayList<String>();
        comingSoon.add("2 Guns");
        comingSoon.add("The Smurfs 2");
        comingSoon.add("The Spectacular Now");
        comingSoon.add("The Canyons");
        comingSoon.add("Europa Report");

        listDataChild.put(listDataHeader.get(0), top250); // Header, Child data
        listDataChild.put(listDataHeader.get(1), nowShowing);
        listDataChild.put(listDataHeader.get(2), comingSoon);
    }

}