{"id":18769,"date":"2015-04-24T09:17:34","date_gmt":"2015-04-24T03:47:34","guid":{"rendered":"http:\/\/www.tothenew.com\/blog\/?p=18769"},"modified":"2016-11-30T17:33:38","modified_gmt":"2016-11-30T12:03:38","slug":"updating-viewpager-with-new-data-dynamically","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/updating-viewpager-with-new-data-dynamically\/","title":{"rendered":"Updating ViewPager With New Data Dynamically"},"content":{"rendered":"<p><a href=\"http:\/\/developer.android.com\/reference\/android\/support\/v4\/view\/ViewPager.html\">ViewPager<\/a>\u00a0is a layout manager that allows users to flip\u00a0and view pages left and right. It is used in conjunction with <a href=\"http:\/\/developer.android.com\/reference\/android\/support\/v4\/view\/PagerAdapter.html\">PagerAdapter<\/a>, \u00a0<a href=\"http:\/\/developer.android.com\/reference\/android\/support\/v4\/app\/FragmentPagerAdapter.html\">FragmentPagerAdapter<\/a>\u00a0or\u00a0<a href=\"http:\/\/developer.android.com\/reference\/android\/support\/v4\/app\/FragmentStatePagerAdapter.html\">FragmentStatePagerAdapter<\/a>. We attach adapter consisting of either <a href=\"http:\/\/developer.android.com\/reference\/android\/app\/Fragment.html\">Fragment<\/a>\u00a0objects or simple <a href=\"http:\/\/developer.android.com\/reference\/android\/view\/View.html\">View<\/a>\u00a0objects.<\/p>\n<p><strong>Note<\/strong>: You can download source code of a\u00a0sample application from <strong><a href=\"https:\/\/github.com\/noorintelli\/ViewPagerRefresh\">here<\/a>\u00a0<\/strong>to run the <a title=\"android application development service\" href=\"http:\/\/www.tothenew.com\/mobile-android-application-development-services\">android application<\/a>.<\/p>\n<p><a href=\"\/blog\/wp-ttn-blog\/uploads\/2015\/04\/ViewPagerRefresh.png\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone  wp-image-19275\" src=\"\/blog\/wp-ttn-blog\/uploads\/2015\/04\/ViewPagerRefresh.png\" alt=\"ViewPagerRefresh\" width=\"419\" height=\"651\" \/><\/a><\/p>\n<h2>Difference Between PagerAdapter, FragmentPagerAdapter and FragmentStatePagerAdapter<\/h2>\n<p><strong>\u00a0PagerAdapter:<\/strong><\/p>\n<ol>\n<li>PagerAdapter is base class for both FragmentPagerAdapter and FragmentStatePagerAdapter.<\/li>\n<li>If you have to\u00a0show custom views (not Fragments) then subclass it and override its<\/li>\n<\/ol>\n<ul>\n<li><a href=\"http:\/\/developer.android.com\/reference\/android\/support\/v4\/view\/PagerAdapter.html#instantiateItem(android.view.ViewGroup,%20int)\">instantiateItem(ViewGroup, int)<\/a><\/li>\n<li><a href=\"http:\/\/developer.android.com\/reference\/android\/support\/v4\/view\/PagerAdapter.html#destroyItem(android.view.ViewGroup,%20int, java.lang.Object)\">destroyItem(ViewGroup, int, Object)<\/a><\/li>\n<li><a href=\"http:\/\/developer.android.com\/reference\/android\/support\/v4\/view\/PagerAdapter.html#getCount()\">getCount()<\/a><\/li>\n<li><a href=\"http:\/\/developer.android.com\/reference\/android\/support\/v4\/view\/PagerAdapter.html#isViewFromObject(android.view.View,%20java.lang.Object)\">isViewFromObject(View, Object)<\/a>\u00a0<del><\/del><\/li>\n<\/ul>\n<p>In instantiateItem method we inflate our view from xml file and add it to ViewGroup parameter which is the reference of the ViewPager.<\/p>\n<p>MyPagerAdapter.java<\/p>\n<p>[sourcecode language=&#8221;java&#8221; wraplines=&#8221;false&#8221; collapse=&#8221;false&#8221;]<br \/>\n@Override<br \/>\n    public Object instantiateItem(ViewGroup container, int position) {<br \/>\n        \/\/ Inflate a new layout from our resources<br \/>\n        View view = mLayoutInflater.inflate(R.layout.photo_layout, container, false);<br \/>\n        \/\/ Retrieve a TextView from the inflated View, and update it&#8217;s text<br \/>\n        TextView titleTextView = (TextView) view.findViewById(R.id.title);<br \/>\n        Utils.DummyItem dummyItem = mDummyItems.get(position);<br \/>\n        titleTextView.setText(dummyItem.getImageTitle());<br \/>\n        ImageView imageView = (ImageView) view.findViewById(R.id.image);<br \/>\n        ImageLoaderUtil.downloadImage(dummyItem.getImageUrl(), imageView);<br \/>\n        view.setTag(dummyItem);<br \/>\n        \/\/ Add the newly created View to the ViewPager<br \/>\n        container.addView(view);<br \/>\n        Log.i(TAG, &quot;instantiateItem() [position: &quot; + position + &quot;]&quot; + &quot; childCount:&quot; + container.getChildCount());<br \/>\n        \/\/ Return the View<br \/>\n        return view;<br \/>\n    }<br \/>\n[\/sourcecode]<\/p>\n<p>3. It keeps maximum three views in memory, one which is currently visible, one which is left and one is right of the visible item. While scrolling, the pages which goes out of the screen will be destroyed in\u00a0<a href=\"http:\/\/developer.android.com\/reference\/android\/support\/v4\/view\/PagerAdapter.html#destroyItem(android.view.ViewGroup,%20int, java.lang.Object)\">destroyItem(ViewGroup, int, Object)<\/a>\u00a0method.<\/p>\n<p>MyPagerAdapter.java<\/p>\n<p>[sourcecode language=&#8221;java&#8221; wraplines=&#8221;false&#8221; collapse=&#8221;false&#8221;]<br \/>\n    \/**<br \/>\n     * Destroy the item from the {@link android.support.v4.view.ViewPager}. In our case this is simply removing the<br \/>\n     * {@link View}.<br \/>\n     *\/<br \/>\n    @Override<br \/>\n    public void destroyItem(ViewGroup container, int position, Object object) {<br \/>\n        container.removeView((View) object);<br \/>\n        Log.i(TAG, &quot;destroyItem() [position: &quot; + position + &quot;]&quot; + &quot; childCount:&quot; + container.getChildCount());<br \/>\n    }<br \/>\n[\/sourcecode]<\/p>\n<p>4.\u00a0<a href=\"http:\/\/developer.android.com\/reference\/android\/support\/v4\/view\/PagerAdapter.html#getCount()\">getCount()<\/a>\u00a0returns the number of items which will be shown in the ViewPager. \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 5.\u00a0<a href=\"http:\/\/developer.android.com\/reference\/android\/support\/v4\/view\/PagerAdapter.html#isViewFromObject(android.view.View,%20java.lang.Object)\">isViewFromObject(View, Object)<\/a>\u00a0 method checks whether the Object returned from\u00a0<a href=\"http:\/\/developer.android.com\/reference\/android\/support\/v4\/view\/PagerAdapter.html#instantiateItem(android.view.ViewGroup,%20int)\">instantiateItem(ViewGroup, int)<\/a>\u00a0method is linked to the View supplied here.<\/p>\n<p>Note: In PagerAdapter, PagerFragmentAdapter and PagerFragmentStateAdapter, the Views or Fragments are recognised by a key Object not by their index or position in the adapter.<\/p>\n<p>In simplest implementation, we return View or Fragment created in\u00a0<a href=\"http:\/\/developer.android.com\/reference\/android\/support\/v4\/view\/PagerAdapter.html#instantiateItem(android.view.ViewGroup,%20int)\">instantiateItem(ViewGroup, int)<\/a>\u00a0itself and in\u00a0<a href=\"http:\/\/developer.android.com\/reference\/android\/support\/v4\/view\/PagerAdapter.html#isViewFromObject(android.view.View,%20java.lang.Object)\">isViewFromObject(View, Object)<\/a>\u00a0method we simply compare View and Object to check the association between them.<\/p>\n<p>MyPagerAdapter.java<\/p>\n<p>[sourcecode language=&#8221;java&#8221; wraplines=&#8221;false&#8221; collapse=&#8221;false&#8221;]<br \/>\n    \/**<br \/>\n     * @return true if the value returned from {@link #instantiateItem(ViewGroup, int)} is the<br \/>\n     * same object as the {@link View} added to the {@link android.support.v4.view.ViewPager}.<br \/>\n     *\/<br \/>\n    @Override<br \/>\n    public boolean isViewFromObject(View view, Object object) {<br \/>\n        return object == view;<br \/>\n    }<br \/>\n[\/sourcecode]<\/p>\n<h2>FragmentPagerAdapter<\/h2>\n<ol>\n<li>In FragmentPagerAdapter we implement only getItem() and getCount() methods in order to get a working adapter.<\/li>\n<li>getItem() is called by the instantiateItem() internally in order to create a new fragment.<\/li>\n<li>In FragmentPagerAdapter, once a fragment has been created, it will never be destroyed throughout the life of the adapter.The fragments will be held by the FragmentManager and will be reused again whenever we will require a new fragment to show.Fragments needed again will be fetched from the FragmentManager and its view hierarchy will be created again by going through\u00a0\u00a0onCreateView(), onViewCreated(), onActivityCreated(), onViewStateRestored(), onStart(), and onResume() \u00a0methods.<\/li>\n<li>If the fragment is being created first time its onAttach(), onCreate(), onCreateView(), onViewCreated(), onActivityCreated(), onViewStateRestored(), onStart(), and onResume() methods will be called sequentially.<\/li>\n<li>If the fragment is going off the screen its onPause(), onStop(), onDestroyView() methods will be called in order. Note that the fragments onDestroy() and onDetach() methods will never be called when the fragments are going off the screen, means fragments are not being destroyed once created and will be held\u00a0by the FragmentManager.<\/li>\n<\/ol>\n<p>MyFragmentPagerAdapter.java<\/p>\n<p>[sourcecode language=&#8221;java&#8221; wraplines=&#8221;false&#8221; collapse=&#8221;false&#8221;]<br \/>\n@Override<br \/>\n    public Fragment getItem(int position) {<br \/>\n        \/\/We are doing this only for checking the total number of fragments in the fragment manager.<br \/>\n        List&lt;Fragment&gt; fragmentsList = mFragmentManager.getFragments();<br \/>\n        int size = 0;<br \/>\n        if (fragmentsList != null) {<br \/>\n            size = fragmentsList.size();<br \/>\n        }<br \/>\n        Utils.DummyItem dummyItem = mDummyItems.get(position);<br \/>\n        Log.i(TAG, &quot;********getItem position:&quot; + position + &quot; size:&quot; + size + &quot; title:&quot; + dummyItem.getImageTitle() + &quot; url:&quot; + dummyItem.getImageUrl());<\/p>\n<p>        \/\/Create a new instance of the fragment and return it.<br \/>\n        SampleFragment sampleFragment = (SampleFragment) SampleFragment.getInstance(\/*dummyItem.getImageUrl(), dummyItem.getImageTitle()*\/);<br \/>\n        \/\/We will not pass the data through bundle because it will not gets updated by calling notifyDataSetChanged()  method. We will do it through getter and setter.<br \/>\n        sampleFragment.setDummyItem(dummyItem);<br \/>\n        return sampleFragment;<br \/>\n    }<br \/>\n[\/sourcecode]<\/p>\n<p>If the number of fragments are large, it will take a lot of memory if we use FragmentPagerAdapter because it never destroys the Fragments once created. It only destroys fragments&#8217;s view hierarchy and keeps its state internally. To overcome this shortcoming we have FragmentStatePagerAdapter which we are going to discuss here.<\/p>\n<h2>FragmentStatePagerAdapter<\/h2>\n<p>FragmentStatePagerAdapter differs from the FragmentPagerAdapter only in one way that it destroys the fragments which are going off the screen. So Fragments are created, attached, destroyed and detached keeping the memory uses low. It holds\u00a0maximum three fragments and keep destroying the off screen fragments. It is suitable in the situation where the number of fragments are large. In every other aspect it is just like the FragmentPagerAdapter.<\/p>\n<h2>Updating ViewPager With New Data Dynamically:<\/h2>\n<p>If we populate or update our data collection with new data and call\u00a0notifyDataSetChanged() on adapter(PagerAdapter or FragmentPagerAdapter or FragmentStatePagerAdapter instance), adapter&#8217;s <a href=\"http:\/\/developer.android.com\/reference\/android\/support\/v4\/view\/PagerAdapter.html#getItemPosition(java.lang.Object)\">getItemPosition(Object)<\/a>\u00a0is called. It is called for all the active pages of the adapter(three maximum). If the data in the fragment present in the collection we simply return its position and if new data not found in the collection we return <a href=\"http:\/\/developer.android.com\/reference\/android\/support\/v4\/view\/PagerAdapter.html#POSITION_NONE\">POSITION_NONE<\/a>\u00a0which forces fragments to recreate its view hierarchy again with new data.<\/p>\n<p>MyFragmentPagerAdapter.java<\/p>\n<p>[sourcecode language=&#8221;java&#8221; wraplines=&#8221;false&#8221; collapse=&#8221;false&#8221;]<br \/>\n    \/**<br \/>\n     * This method is only gets called when we invoke {@link #notifyDataSetChanged()} on this adapter.<br \/>\n     * Returns the index of the currently active fragments.<br \/>\n     * There could be minimum two and maximum three active fragments(suppose we have 3 or more  fragments to show).<br \/>\n     * If there is only one fragment to show that will be only active fragment.<br \/>\n     * If there are only two fragments to show, both will be in active state.<br \/>\n     * PagerAdapter keeps left and right fragments of the currently visible fragment in ready\/active state so that it could be shown immediate on swiping.<br \/>\n     * Currently Active Fragments means one which is currently visible one is before it and one is after it.<br \/>\n     *<br \/>\n     * @param object Active Fragment reference<br \/>\n     * @return Returns the index of the currently active fragments.<br \/>\n     *\/<br \/>\n    @Override<br \/>\n    public int getItemPosition(Object object) {<br \/>\n        Utils.DummyItem dummyItem = (Utils.DummyItem) ((View) object).getTag();<br \/>\n        int position = mDummyItems.indexOf(dummyItem);<br \/>\n        if (position &gt;= 0) {<br \/>\n            \/\/ The current data matches the data in this active fragment, so let it be as it is.<br \/>\n            return position;<br \/>\n        } else {<br \/>\n            \/\/ Returning POSITION_NONE means the current data does not matches the data this fragment is showing right now.  Returning POSITION_NONE constant will force the fragment to redraw its view layout all over again and show new data.<br \/>\n            return POSITION_NONE;<br \/>\n        }<br \/>\n    }<br \/>\n[\/sourcecode]<\/p>\n<p>This method tells the adapter to force out of sync fragments to recreate its view hierarchy again(in case of FragmentPagerAdapter) or destroy fragments and recreate it(in case of FragmentStatePagerAdapter and PagerAdapter) or tells that the position and state of the active page(s) are appropriate and it doesn&#8217;t need to be updated.<\/p>\n<p>If we pass the data to the fragment using <a href=\"http:\/\/developer.android.com\/reference\/android\/app\/Fragment.html#setArguments(android.os.Bundle)\">setArgument(Bundle)<\/a>, event if we force fragment to recreate its view hierarchy, it will show the old data which we have passed earlier using setArgument() method. To overcome this problem we will supply data to the fragments using a setter while creating the fragment first time and override\u00a0instantiateItem() \u00a0method to check whether the old data and new data are different or equal. If new data is not equal to old\u00a0data, we replace the old data with new one using the same setter. Don&#8217;t forget to call super.instantiateItem(container, position) at end of the method. In this way we can update the fragment with new data.<\/p>\n<p>MyFragmentPagerAdapter.java<\/p>\n<p>[sourcecode language=&#8221;java&#8221; wraplines=&#8221;false&#8221; collapse=&#8221;false&#8221;]<\/p>\n<p> @Override<br \/>\n    public Object instantiateItem(ViewGroup container, int position) {<br \/>\n        List&lt;Fragment&gt; fragmentsList = mFragmentManager.getFragments();<br \/>\n        if (fragmentsList != null &amp;&amp; position &lt;= (fragmentsList.size() &#8211; 1)) {<br \/>\n            SampleFragment sampleFragment = (SampleFragment) fragmentsList.get(position);<br \/>\n            Utils.DummyItem dummyItem = mDummyItems.get(position);<br \/>\n            \/\/If the current data of the fragment changed, set the new data<br \/>\n            if (!dummyItem.equals(sampleFragment.getDummyItem())) {<br \/>\n                sampleFragment.setDummyItem(dummyItem);<br \/>\n                Log.i(TAG, &quot;********instantiateItem position:&quot; + position + &quot; FragmentDataChanged&quot;);<br \/>\n            }<br \/>\n        } else {<br \/>\n            \/\/No fragment instance available for this index, create a new fragment by calling getItem() and show the data.<br \/>\n            Log.i(TAG, &quot;********instantiateItem position:&quot; + position + &quot; NewFragmentCreated&quot;);<br \/>\n        }<\/p>\n<p>        return super.instantiateItem(container, position);<br \/>\n    }<br \/>\n[\/sourcecode]<\/p>\n<p>For equality checking we must have to override equal method of our model data class.<\/p>\n<p>Inside the Utils.java, DummyItem class<\/p>\n<p>[sourcecode language=&#8221;java&#8221; wraplines=&#8221;false&#8221; collapse=&#8221;false&#8221;]<br \/>\npublic static class DummyItem{<br \/>\n        private String imageUrl;<br \/>\n        private String imageTitle;<\/p>\n<p>        public DummyItem(String imageUrl, String imageTitle) {<br \/>\n            this.imageUrl = imageUrl;<br \/>\n            this.imageTitle = imageTitle;<br \/>\n        }<\/p>\n<p>        public String getImageUrl() {<br \/>\n            return imageUrl;<br \/>\n        }<\/p>\n<p>        public String getImageTitle() {<br \/>\n            return imageTitle;<br \/>\n        }<\/p>\n<p>        @Override<br \/>\n        public boolean equals(Object obj) {<br \/>\n            if (obj == null) {<br \/>\n                return false;<br \/>\n            }<br \/>\n            if(getClass() != obj.getClass()){<br \/>\n                return false;<br \/>\n            }<\/p>\n<p>            final DummyItem other = (DummyItem) obj;<br \/>\n            if (!this.imageUrl.equals(other.imageUrl)) {<br \/>\n                return false;<br \/>\n            }<br \/>\n            if (!this.imageTitle.equals(other.imageTitle)) {<br \/>\n                return false;<br \/>\n            }<\/p>\n<p>            \/*if(obj == this){<br \/>\n                return true;<br \/>\n            }*\/<br \/>\n            return true;<br \/>\n        }<\/p>\n<p>        \/\/The hashCode() method of objects is used when you insert them into a HashTable, HashMap or HashSet.<br \/>\n        \/\/Since we are using these objects to store in List, we are not going to override it.<br \/>\n        \/*@Override<br \/>\n        public int hashCode() {<br \/>\n            return super.hashCode();<br \/>\n        }*\/<br \/>\n    }<br \/>\n[\/sourcecode]<\/p>\n<p>In case of FragmentStatePagerAdapter we will only override getItemPosition() method in the same way as we just did in the FragmentPagerAdapter. We will not override onInstantiateItem() method in FragmentStatePagerAdapter\u00a0since FragmentStatePagerAdapter destroys the fragments which go off the screen and creates a new fragment every time it needs one all over again. FragmentManager does not hold the fragments which are going off the screen and simply destroys it. In this way new fragments gets new data from the object collection directly.<\/p>\n<p>Same thing is true for PagerAdapter as well and we only override getItemPosition() in order to update the view with new data because FragmentPager also destroys the views going off the screen.<\/p>\n<p>For better understanding of the process, please download the sample source code from <a href=\"https:\/\/github.com\/noorintelli\/ViewPagerRefresh\"><strong>here<\/strong><\/a>\u00a0, run the <a title=\"android application development services\" href=\"http:\/\/www.tothenew.com\/mobile-android-application-development-services\">android application<\/a> and go through the code.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>ViewPager\u00a0is a layout manager that allows users to flip\u00a0and view pages left and right. It is used in conjunction with PagerAdapter, \u00a0FragmentPagerAdapter\u00a0or\u00a0FragmentStatePagerAdapter. We attach adapter consisting of either Fragment\u00a0objects or simple View\u00a0objects. Note: You can download source code of a\u00a0sample application from here\u00a0to run the android application. Difference Between PagerAdapter, FragmentPagerAdapter and FragmentStatePagerAdapter \u00a0PagerAdapter: PagerAdapter [&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":99},"categories":[518],"tags":[4845,3385],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/18769"}],"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=18769"}],"version-history":[{"count":0,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/18769\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=18769"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=18769"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=18769"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}