{"id":26569,"date":"2016-07-12T11:45:50","date_gmt":"2016-07-12T18:45:50","guid":{"rendered":"https:\/\/blog.xamarin.com\/?p=26569"},"modified":"2019-04-04T09:04:11","modified_gmt":"2019-04-04T16:04:11","slug":"recyclerview-highly-optimized-collections-for-android-apps","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/xamarin\/recyclerview-highly-optimized-collections-for-android-apps\/","title":{"rendered":"RecyclerView: Highly Optimized Collections for Android Apps"},"content":{"rendered":"<p>\t\t\t\tI&#8217;ve spent hours of development time trying to optimize Android&#8217;s ListView to make scrolling through items smooth, followed by similar amounts of time attempting to optimize and configure Android&#8217;s GridView if I wanted to display more than one column of data at a time. These days of struggling to remember the correct pattern (and copy and paste the code from adapter to adapter) are now over, thanks to the introduction of Android&#8217;s <a href=\"https:\/\/developer.xamarin.com\/guides\/android\/user_interface\/recyclerview\/\">RecyclerView<\/a>. The RecyclerView has been around for a while now, having been introduced in Support Library v7 as an <a href=\"https:\/\/www.nuget.org\/packages\/Xamarin.Android.Support.v7.RecyclerView\/\">NuGet package<\/a> so you can use it in all of the applications you&#8217;re currently developing. Today, we&#8217;ll take a look at integrating the RecyclerView into an app with some similar paradigms of the ListView.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/44\/2019\/03\/04-view-recycling-sml.png\" alt=\"RecyclerView Recycling\" width=\"600\" height=\"358\" class=\"aligncenter size-full wp-image-26570\" \/><\/p>\n<h2>Adding the NuGet<\/h2>\n<p>The first step is to add the <a href=\"https:\/\/www.nuget.org\/packages\/Xamarin.Android.Support.v7.RecyclerView\/\">NuGet package<\/a> to your Android project. This will give you direct access to the widget in code and for Android XML.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/44\/2019\/03\/NuGetRecyclerView.png\" alt=\"NuGetRecyclerView\" width=\"999\" height=\"298\" class=\"aligncenter size-full wp-image-26572\" \/><\/p>\n<h2>Integrate Widget<\/h2>\n<p>Just like any other Android widget, you can simply add the RecyclerView directly into your existing Android XML or even replace your ListView with a RecyclerView:<\/p>\n<pre class=\"lang:xml decode:true\">\n\n\n    <!-- Additional widgets -->\n    \n\n<\/pre>\n<h2>Item Layout<\/h2>\n<p>For this app, I&#8217;m displaying a list of images that are inside of a CardView to add a nice drop shadow:<\/p>\n<pre class=\"lang:xml decode:true\">\n\n\n    \n        \n            \n            \n        \n    \n\n<\/pre>\n<h2>Bringing It All Together<\/h2>\n<p>With the main layout and item layout all set up, it&#8217;s time to bring them together and start displaying items. The RecyclerView has three required classes that need to be implemented for each:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/44\/2019\/03\/03-recyclerview-diagram.png\" alt=\"03-recyclerview-diagram\" width=\"400\" class=\"aligncenter size-full wp-image-26571\" \/><\/p>\n<ul>\n<li><b>RecyclerView.ViewHolder<\/b>: Caches references to the views in your item layout file so that resource lookups are not repeated unnecessarily.<\/li>\n<li><b>RecyclerView.Adapter<\/b>: Provides a binding from your app&#8217;s data set (which is specific to your app) to item views that are displayed within the RecyclerView.<\/li>\n<li><b>RecyclerView.LayoutManager<\/b>: Positions items within the RecyclerView.<\/li>\n<\/ul>\n<h2>RecyclerView ViewHolder &amp; Adapter<\/h2>\n<p>The ViewHolder seem familiar if you have <a href=\"https:\/\/blog.xamarin.com\/creating-highly-performant-smooth-scrolling-android-listviews\/\">optimized ListViews<\/a> in the past. This class must be a subclass of <b>RecyclerView.ViewHolder<\/b> and has one job, which is to cache all views by finding them by their ID.<\/p>\n<pre class=\"lang:csharp decode:true\">\n    public class ImageAdapterViewHolder : RecyclerView.ViewHolder\n    {\n        public ImageView Image { get; private set; }\n        public TextView Caption { get; private set; }\n\n        public ImageAdapterViewHolder(View itemView) : base(itemView)\n        {\n            Image = itemView.FindViewById(Resource.Id.imageView);\n            Caption = itemView.FindViewById(Resource.Id.textView);\n        }\n    }\n<\/pre>\n<p>This ViewHolder is used in the main adapter, which actually inflates the view and sets the properties on each widget. It must inherit from <b>RecyclerView.Adapter<\/b> and then  implement three methods to handle layout inflating, binding, and the count of items that are to be displayed.<\/p>\n<pre class=\"lang:csharp decode:true\">\n    class ImageAdapter : RecyclerView.Adapter\n    {\n        Image[] images;\n        Activity activity;\n\n        public ImageAdapter(Activity activity, Image[] images)\n        {\n            this.images = images;\n            this.activity = activity;\n        }\n\n        \/\/ Create new views (invoked by the layout manager)\n        public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)\n        {\n            \/\/Setup and inflate your layout here\n            var id = Resource.Layout.item;\n            var itemView = LayoutInflater.From(parent.Context).Inflate(id, parent, false);\n\n            return new ImageAdapterViewHolder(itemView);\n        }\n\n        \/\/ Replace the contents of a view (invoked by the layout manager)\n        public override void OnBindViewHolder(RecyclerView.ViewHolder viewHolder, int position)\n        {\n            var item = images[position];\n\n            \/\/ Replace the contents of the view with that element\n            var holder = viewHolder as ImageAdapterViewHolder;\n            holder.Caption.Text = item.Title;\n            Picasso.With(activity).Load(item.ImageLink).Into(holder.Image);\n        }\n\n        public override int ItemCount =&gt; images.Count;\n    }\n<\/pre>\n<p>With the adapter in place, it&#8217;s time to tie it together with the RecyclerView in the Main Activity:<\/p>\n<pre class=\"lang:csharp decode:true\">\n    [Activity(Label = \"Image Search\", MainLauncher = true, Icon = \"@drawable\/icon\")]\n    public class MainActivity : AppCompatActivity\n    {\n        RecyclerView recyclerView;\n        RecyclerView.LayoutManager layoutManager;\n        ImageAdapter adapter;\n        Image[] images;\n\n        protected override int LayoutResource\n        {\n            get { return Resource.Layout.main; }\n        }\n        int count = 1;\n\n        protected override void OnCreate(Bundle bundle)\n        {\n            base.OnCreate(bundle);\n            SetContentView(Resource.Id.main);\n\n            \/\/Create Images here\n            images = new [] { new Image { Caption = \"Baboon\", Image = \"http:\/\/upload.wikimedia.org\/wikipedia\/commons\/thumb\/9\/96\/Portrait_Of_A_Baboon.jpg\/314px-Portrait_Of_A_Baboon.jpg\" } };\n\n            \/\/Setup RecyclerView\n            adapter = new ImageAdapter(this, images);\n\n            recyclerView = FindViewById(Resource.Id.recyclerView);\n\n            recyclerView.SetAdapter(adapter);\n        }\n    }\n<\/pre>\n<h2>Managing the Layout<\/h2>\n<p>The last part is to set the LayoutManager. This allows complete customization of how items in the list are laid out. Built into the RecylerView library are a few default layout managers to get started, including the LinearLayoutManager and the GridLayoutManager.<\/p>\n<h3>LinearLayoutManager<\/h3>\n<p>This manager will layout items either horizontally or vertically:<\/p>\n<pre class=\"lang:csharp decode:true\">\nlayoutManager = new LinearLayoutManager(this, LinearLayoutManager.Vertical, false);\nrecyclerView.SetLayoutManager(layoutManager);\n<\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/44\/2019\/03\/LinearLayoutManager.png\" alt=\"LinearLayoutManager\" width=\"300\" class=\"aligncenter size-full wp-image-26574\" \/><\/p>\n<h3>GridLayoutManager<\/h3>\n<p>This manager allows a set number of columns in a list, which is great for displaying multiple images in a list:<\/p>\n<pre class=\"lang:csharp decode:true\">\nlayoutManager = new GridLayoutManager(this, 2);\nrecyclerView.SetLayoutManager(layoutManager);\n<\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/44\/2019\/03\/GridLayoutManager.png\" alt=\"GridLayoutManager\" width=\"300\" class=\"aligncenter size-full wp-image-26573\" \/><\/p>\n<p>The beautiful part of the LayoutManager is that you can change them at any time for customization depending on the type of device the app is running on.<\/p>\n<h2>Learn More<\/h2>\n<p>This is just the beginning of what&#8217;s possible with the RecyclerView and its immense power. Be sure to read through our <a href=\"https:\/\/developer.xamarin.com\/guides\/android\/user_interface\/recyclerview\/\">complete documentation<\/a> on how to customize the item decoration, add click handlers, and a lot more. You can find the source code for this example on my <a href=\"https:\/\/github.com\/jamesmontemagno\/app-imagesearch-cogs\">GitHub <\/a>page.\t\t<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve spent hours of development time trying to optimize Android&#8217;s ListView to make scrolling through items smooth, followed by similar amounts of time attempting to optimize and configure Android&#8217;s GridView if I wanted to display more than one column of data at a time. These days of struggling to remember the correct pattern (and copy [&hellip;]<\/p>\n","protected":false},"author":544,"featured_media":26573,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2],"tags":[5,4],"class_list":["post-26569","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-developers","tag-android","tag-xamarin-platform"],"acf":[],"blog_post_summary":"<p>I&#8217;ve spent hours of development time trying to optimize Android&#8217;s ListView to make scrolling through items smooth, followed by similar amounts of time attempting to optimize and configure Android&#8217;s GridView if I wanted to display more than one column of data at a time. These days of struggling to remember the correct pattern (and copy [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/26569","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/users\/544"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/comments?post=26569"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/posts\/26569\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/media?parent=26569"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/categories?post=26569"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/xamarin\/wp-json\/wp\/v2\/tags?post=26569"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}