{"id":19611,"date":"2015-05-20T17:04:30","date_gmt":"2015-05-20T11:34:30","guid":{"rendered":"http:\/\/www.tothenew.com\/blog\/?p=19611"},"modified":"2015-05-20T17:04:30","modified_gmt":"2015-05-20T11:34:30","slug":"recyclerview-in-android","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/recyclerview-in-android\/","title":{"rendered":"RecyclerView in Android"},"content":{"rendered":"<p class=\"p1\">Android\u00a0<a href=\"https:\/\/developer.android.com\/reference\/android\/support\/v7\/widget\/RecyclerView.html\"><span class=\"s1\">RecyclerView<\/span><\/a>\u00a0\u00a0was introduced in <a href=\"http:\/\/www.android.com\/versions\/lollipop-5-0\/\"><span class=\"s1\">Android\u00a05.0 Lollipop<\/span><\/a>. It is much faster and memory efficient than Android <a href=\"http:\/\/developer.android.com\/guide\/topics\/ui\/layout\/listview.html\"><span class=\"s1\">ListView<\/span><\/a>.<\/p>\n<p class=\"p1\">You can download sample application source code for this tutorial from <a href=\"https:\/\/github.com\/noorintelli\/RecyclerViewDemoApp\"><strong>here<\/strong><\/a>.<\/p>\n<p class=\"p1\"><a href=\"\/blog\/wp-ttn-blog\/uploads\/2015\/05\/recyclerViewDemoAppScreen.png\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-19763 aligncenter\" src=\"\/blog\/wp-ttn-blog\/uploads\/2015\/05\/recyclerViewDemoAppScreen.png\" alt=\"recyclerViewDemoAppScreen\" width=\"457\" height=\"800\" \/><\/a><\/p>\n<p class=\"p1\">A RecyclerView can cache previously used view for a specific adapter position for later reuse to display same type of data again later. This improves the performance of the RecyclerView drastically by skipping initial layout inflation or construction.<\/p>\n<p class=\"p1\">We would have to learn about the following classes in order to use RecyclerView\u00a0in our apps:<\/p>\n<p class=\"p1\"><strong>1.\u00a0<a href=\"https:\/\/developer.android.com\/reference\/android\/support\/v7\/widget\/RecyclerView.Adapter.html\">RecyclerView.Adapter<\/a>: \u00a0<\/strong>It provides access to data sets items, creates views for items and binds items info to item view<strong>.\u00a0<\/strong>It is a placeholder for ListView Adapter classes. Just like \u00a0ListView adapter, it provides views to be fed to the RecyclerView. In <a href=\"https:\/\/developer.android.com\/reference\/android\/support\/v7\/widget\/RecyclerView.Adapter.html#onCreateViewHolder(android.view.ViewGroup,%20int)\">onCreateViewHolder()<\/a>, we inflate \u00a0xml view\u00a0resources and wrap it inside a RecyclerView.ViewHolder instances and return it.<\/p>\n<p>[sourcecode language=&#8221;java&#8221; wraplines=&#8221;false&#8221; collapse=&#8221;false&#8221;]<br \/>\n@Override<br \/>\n    public ListItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {<br \/>\n        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycler_view, parent, false);<br \/>\n        return new ListItemViewHolder(itemView);<br \/>\n    }<br \/>\n[\/sourcecode]<\/p>\n<p>In <a href=\"https:\/\/developer.android.com\/reference\/android\/support\/v7\/widget\/RecyclerView.Adapter.html#onBindViewHolder(VH,%20int)\">onBindViewHolder()<\/a>\u00a0we put the data in views. We access the views from ViewHolder supplied here:<\/p>\n<p>[sourcecode language=&#8221;java&#8221; wraplines=&#8221;false&#8221; collapse=&#8221;false&#8221;]<br \/>\n   @Override<br \/>\n    public void onBindViewHolder(ListItemViewHolder holder, int position) {<br \/>\n        DataModel model = mDataModels.get(position);<br \/>\n        holder.title.setText(model.getTitle());<br \/>\n    }<br \/>\n[\/sourcecode]<\/p>\n<p><strong>2.\u00a0<a href=\"https:\/\/developer.android.com\/reference\/android\/support\/v7\/widget\/RecyclerView.ViewHolder.html\">RecyclerView.ViewHolder<\/a><\/strong>: ViewHolder class wraps the view instances inside it from where we can get child views directly. In this way we don&#8217;t need to inflate the view over and again every time we scroll the recycler view. It saves memory and make the scrolling fast and smooth. Here is the implementation of ViewHolder class which I subclassed:<\/p>\n<p>[sourcecode language=&#8221;java&#8221; wraplines=&#8221;false&#8221; collapse=&#8221;false&#8221;]<br \/>\n    public class ListItemViewHolder extends ViewHolder {<\/p>\n<p>    ImageView imgView;<br \/>\n    TextView title;<\/p>\n<p>    public ListItemViewHolder(View itemView) {<br \/>\n        super(itemView);<br \/>\n        title = (TextView) itemView.findViewById(R.id.textview_title);<br \/>\n        imgView = (ImageView) itemView.findViewById(R.id.imageview_icon);<br \/>\n    }<br \/>\n}<\/p>\n<p>  [\/sourcecode]<\/p>\n<p><strong>3.\u00a0<a href=\"https:\/\/developer.android.com\/reference\/android\/support\/v7\/widget\/RecyclerView.LayoutManager.html\">RecyclerView.LayoutManager<\/a><\/strong>: \u00a0It is responsible for measuring and positioning item views within a RecyclerView. It is responsible for recycling out of screen views during scrolling. \u00a0 \u00a0 \u00a0 \u00a0 \u00a0RecyclerView.LayoutManager has three\u00a0subclasses.<\/p>\n<ul>\n<li>\n<p class=\"p1\"><span class=\"s1\"><a href=\"https:\/\/developer.android.com\/reference\/android\/support\/v7\/widget\/LinearLayoutManager.html\">LinearLayoutManager<\/a><\/span>: It provides similar functionality to a standard ListView. We can create a Vertical Scrolling List as well as Horizontal Scrolling List using this manager by specifying the scroll type in its constructor while creating its \u00a0instance.<\/p>\n<\/li>\n<li>\n<p class=\"p1\"><span class=\"s1\"><a href=\"https:\/\/developer.android.com\/reference\/android\/support\/v7\/widget\/GridLayoutManager.html\">GridLayoutManager<\/a><\/span>: Implementation of layout manager that lays out items in a grid. It provides only vertical scrolling.<\/p>\n<\/li>\n<li>\n<p class=\"p1\"><span class=\"s1\"><a href=\"https:\/\/developer.android.com\/reference\/android\/support\/v7\/widget\/StaggeredGridLayoutManager.html\">StaggeredGridLayoutManager<\/a><\/span>: Lays out all items in a staggered grid formation, supports horizontal and vertical layouts and is able to lay out items in reverse. It can layout irregular sized items in a vertical or horizontal scrolling grid view<\/p>\n<\/li>\n<\/ul>\n<p><strong>4.<\/strong>\u00a0<strong><a href=\"https:\/\/developer.android.com\/reference\/android\/support\/v7\/widget\/RecyclerView.ItemAnimator.html\">RecyclerView.ItemAnimator<\/a>:<\/strong>\u00a0This class defines the animations that take place on items as changes are made to the adapter for example adding items, removing items and reordering items. Android provides a default item animator called <a href=\"https:\/\/developer.android.com\/reference\/android\/support\/v7\/widget\/DefaultItemAnimator.html\">DefaultItemAnimator<\/a>. We set the animator to the RecyclerView by calling \u00a0<a href=\"https:\/\/developer.android.com\/reference\/android\/support\/v7\/widget\/RecyclerView.html#setItemAnimator(android.support.v7.widget.RecyclerView.ItemAnimator)\"><span class=\"sympad\">setItemAnimator<\/span> <span class=\"normal\">(RecyclerView.ItemAnimator\u00a0animator)<\/span><\/a>\u00a0method on RecyclerView object<\/p>\n<p><strong>5.\u00a0<a href=\"https:\/\/developer.android.com\/reference\/android\/support\/v7\/widget\/RecyclerView.ItemDecoration.html\">RecyclerView.ItemDecoration<\/a>:<\/strong>\u00a0An ItemDecoration allows the application to add a special drawing and layout offset to specific item views from the adapter&#8217;s data set. No default ItemDecoration implementation is provided by the Android. Here is sample code for ItemDecoration implementation found at <a href=\"https:\/\/gist.github.com\/alexfu\/0f464fc3742f134ccd1e\">github.com<\/a>.<\/p>\n<p>[sourcecode language=&#8221;java&#8221; wraplines=&#8221;false&#8221; collapse=&#8221;false&#8221;]<br \/>\n    \/*<br \/>\n * Copyright (C) 2014 The Android Open Source Project<br \/>\n *<br \/>\n * Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);<br \/>\n * you may not use this file except in compliance with the License.<br \/>\n * You may obtain a copy of the License at<br \/>\n *<br \/>\n *      http:\/\/www.apache.org\/licenses\/LICENSE-2.0<br \/>\n *<br \/>\n * Unless required by applicable law or agreed to in writing, software<br \/>\n * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,<br \/>\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.<br \/>\n * See the License for the specific language governing permissions and<br \/>\n * limitations under the License.<br \/>\n *\/<br \/>\npublic class DividerItemDecoration extends RecyclerView.ItemDecoration {<\/p>\n<p>    private static final int[] ATTRS = new int[]{<br \/>\n            android.R.attr.listDivider<br \/>\n    };<\/p>\n<p>    public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;<\/p>\n<p>    public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;<\/p>\n<p>    private Drawable mDivider;<\/p>\n<p>    private int mOrientation;<\/p>\n<p>    public DividerItemDecoration(Context context, int orientation) {<br \/>\n        final TypedArray a = context.obtainStyledAttributes(ATTRS);<br \/>\n        mDivider = a.getDrawable(0);<br \/>\n        a.recycle();<br \/>\n        setOrientation(orientation);<br \/>\n    }<\/p>\n<p>    public void setOrientation(int orientation) {<br \/>\n        if (orientation != HORIZONTAL_LIST &amp;&amp; orientation != VERTICAL_LIST) {<br \/>\n            throw new IllegalArgumentException(&quot;invalid orientation&quot;);<br \/>\n        }<br \/>\n        mOrientation = orientation;<br \/>\n    }<\/p>\n<p>    @Override<br \/>\n    public void onDraw(Canvas c, RecyclerView parent) {<br \/>\n        if (mOrientation == VERTICAL_LIST) {<br \/>\n            drawVertical(c, parent);<br \/>\n        } else {<br \/>\n            drawHorizontal(c, parent);<br \/>\n        }<br \/>\n    }<\/p>\n<p>    public void drawVertical(Canvas c, RecyclerView parent) {<br \/>\n        final int left = parent.getPaddingLeft();<br \/>\n        final int right = parent.getWidth() &#8211; parent.getPaddingRight();<\/p>\n<p>        final int childCount = parent.getChildCount();<br \/>\n        for (int i = 0; i &lt; childCount; i++) {<br \/>\n            final View child = parent.getChildAt(i);<br \/>\n            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child<br \/>\n                    .getLayoutParams();<br \/>\n            final int top = child.getBottom() + params.bottomMargin;<br \/>\n            final int bottom = top + mDivider.getIntrinsicHeight();<br \/>\n            mDivider.setBounds(left, top, right, bottom);<br \/>\n            mDivider.draw(c);<br \/>\n        }<br \/>\n    }<\/p>\n<p>    public void drawHorizontal(Canvas c, RecyclerView parent) {<br \/>\n        final int top = parent.getPaddingTop();<br \/>\n        final int bottom = parent.getHeight() &#8211; parent.getPaddingBottom();<\/p>\n<p>        final int childCount = parent.getChildCount();<br \/>\n        for (int i = 0; i &lt; childCount; i++) {<br \/>\n            final View child = parent.getChildAt(i);<br \/>\n            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child<br \/>\n                    .getLayoutParams();<br \/>\n            final int left = child.getRight() + params.rightMargin;<br \/>\n            final int right = left + mDivider.getIntrinsicHeight();<br \/>\n            mDivider.setBounds(left, top, right, bottom);<br \/>\n            mDivider.draw(c);<br \/>\n        }<br \/>\n    }<\/p>\n<p>    @Override<br \/>\n    public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {<br \/>\n        if (mOrientation == VERTICAL_LIST) {<br \/>\n            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());<br \/>\n        } else {<br \/>\n            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);<br \/>\n        }<br \/>\n    }<br \/>\n}  <\/p>\n<p>[\/sourcecode]<\/p>\n<p>Here is the the complete implementation of the RecyclerView.Adapter class in the sample project:<\/p>\n<p>[sourcecode language=&#8221;java&#8221; wraplines=&#8221;false&#8221; collapse=&#8221;false&#8221;]<br \/>\npackage com.demo.recyclerview;<\/p>\n<p>import android.os.Bundle;<br \/>\nimport android.support.v4.app.Fragment;<br \/>\nimport android.support.v7.widget.DefaultItemAnimator;<br \/>\nimport android.support.v7.widget.GridLayoutManager;<br \/>\nimport android.support.v7.widget.LinearLayoutManager;<br \/>\nimport android.support.v7.widget.RecyclerView;<br \/>\nimport android.support.v7.widget.StaggeredGridLayoutManager;<br \/>\nimport android.view.LayoutInflater;<br \/>\nimport android.view.View;<br \/>\nimport android.view.ViewGroup;<\/p>\n<p>import java.util.ArrayList;<\/p>\n<p>\/**<br \/>\n * Created by noor on 05\/05\/15.<br \/>\n *\/<br \/>\npublic class PlaceholderFragment extends Fragment {<\/p>\n<p> \/*Number of columns in the grid view*\/<br \/>\n private static final int NUM_OF_COLUMNS = 2;<br \/>\n \/*Total number of items in the RecyclerView*\/<br \/>\n private static final int NUM_OF_ITEMS = 100;<\/p>\n<p> public PlaceholderFragment() {<br \/>\n }<\/p>\n<p> @Override<br \/>\n public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {<br \/>\n View rootView = inflater.inflate(R.layout.fragment_main, container, false);<br \/>\n RecyclerView recyclerView = (RecyclerView)rootView.findViewById(R.id.recyclerview);<\/p>\n<p> RecyclerView.LayoutManager layoutManager = null;<br \/>\n String type = getArguments().getString(MainActivity.TYPE);<br \/>\n if( type.equals(MainActivity.TYPE_VERTICAL_LIST)){<br \/>\n \/*LinearLayoutManager to show a vertical list view*\/<br \/>\n layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);<br \/>\n }else if(type.equals(MainActivity.TYPE_HORIZONTAL_LIST)){<br \/>\n \/*LinearLayoutManager to show a horizontal list view*\/<br \/>\n layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false);<br \/>\n }else if(type.equals(MainActivity.TYPE_GRID_VIEW)){<br \/>\n \/*LinearLayoutManager to show a grid view. We can specify number of columns in the grid.*\/<br \/>\n layoutManager = new GridLayoutManager(getActivity(), NUM_OF_COLUMNS);<\/p>\n<p> }else if(type.equals(MainActivity.TYPE_HORIZONTAL_GRID_VIEW_STAGGERED)){<br \/>\n \/*LinearLayoutManager to show a staggered grid view. We can specify number of columns in the grid.*\/<br \/>\n \/\/spanCount: If orientation is vertical, spanCount is number of columns. If orientation is horizontal, spanCount is number of rows.<br \/>\n \/\/orientation: StaggeredGridLayoutManager.HORIZONTAL or StaggeredGridLayoutManager.HORIZONTAL<br \/>\n layoutManager = new StaggeredGridLayoutManager(3\/*span count*\/, StaggeredGridLayoutManager.HORIZONTAL\/* orientation*\/);<\/p>\n<p> }else if(type.equals(MainActivity.TYPE_VERTICAL_GRID_VIEW_STAGGERED)){<br \/>\n \/*LinearLayoutManager to show a staggered grid view. We can specify number of columns in the grid.*\/<br \/>\n \/\/spanCount: If orientation is vertical, spanCount is number of columns. If orientation is horizontal, spanCount is number of rows.<br \/>\n \/\/orientation: StaggeredGridLayoutManager.HORIZONTAL or StaggeredGridLayoutManager.HORIZONTAL<br \/>\n layoutManager = new StaggeredGridLayoutManager(2\/*span count*\/, StaggeredGridLayoutManager.VERTICAL\/* orientation*\/);<\/p>\n<p> }<\/p>\n<p> recyclerView.setLayoutManager(layoutManager);<br \/>\n RecyclerViewAdapter recyclerViewAdapter = new RecyclerViewAdapter(getDataModelList(), type);<\/p>\n<p> \/*Third party ItemDecoration found from https:\/\/gist.github.com\/alexfu\/0f464fc3742f134ccd1e*\/<br \/>\n RecyclerView.ItemDecoration verticalDivider = new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST);<br \/>\n RecyclerView.ItemDecoration horizontalDivider = new DividerItemDecoration(getActivity(), DividerItemDecoration.HORIZONTAL_LIST);<br \/>\n recyclerView.addItemDecoration(horizontalDivider);<br \/>\n recyclerView.addItemDecoration(verticalDivider);<\/p>\n<p> \/\/ this is the default;<br \/>\n \/\/ this call is actually only necessary with custom ItemAnimators<br \/>\n recyclerView.setItemAnimator(new DefaultItemAnimator());<\/p>\n<p> recyclerView.setAdapter(recyclerViewAdapter);<br \/>\n return rootView;<br \/>\n }<\/p>\n<p> \/** Creates and returns the data items to be shown in the Recycler View*\/<br \/>\n private ArrayList&lt;DataModel&gt; getDataModelList(){<br \/>\n ArrayList&lt;DataModel&gt; dataModels = new ArrayList&lt;&gt;();<\/p>\n<p> for (int i = 0; i &lt; NUM_OF_ITEMS; i++) {<br \/>\n dataModels.add(new DataModel(&quot;Title:&quot;+i));<br \/>\n }<\/p>\n<p> return dataModels;<br \/>\n }<\/p>\n<p>}<br \/>\n[\/sourcecode]<\/p>\n<p>You can learn more by tweaking the source code of the provided\u00a0sample application\u00a0<a href=\"https:\/\/github.com\/noorintelli\/RecyclerViewDemoApp\">here<\/a>.<\/p>\n<p>This is all what I learned from my personal study regarding RecyclerView.<\/p>\n<p>Feel free to provide your feedback regarding this discussion.<\/p>\n<p>Happy coding&#8230;.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Android\u00a0RecyclerView\u00a0\u00a0was introduced in Android\u00a05.0 Lollipop. It is much faster and memory efficient than Android ListView. You can download sample application source code for this tutorial from here. A RecyclerView can cache previously used view for a specific adapter position for later reuse to display same type of data again later. This improves the performance of [&hellip;]<\/p>\n","protected":false},"author":150,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":2},"categories":[518,1],"tags":[4851,1778],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/19611"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/150"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=19611"}],"version-history":[{"count":0,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/19611\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=19611"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=19611"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=19611"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}