转载请注明出处:http://blog.csdn.net/mr_liabill/article/details/48749807 来自《LiaBin的博客》
ViewPager简介
ViewPager不用多说,是v4包中的一个控件,可以用来实现屏幕间的切换。
<android.support.v4.view.ViewPager />
跟listview一样,需要使用适配器,PagerAdapter
PagerAdapter
必须重写的四个函数:
boolean isViewFromObject(View arg0, Object arg1) int getCount() void destroyItem(ViewGroup container, int position,Object object) Object instantiateItem(ViewGroup container, int position)
ViewPager+Fragment配合使用
使用方法
普通实现可以通过PageAdapter中添加View来实现,android官方最推荐的一种实现方法却是使用fragment。可以使用如下两种adapter
FragmentPagerAdapter/FragmentStatePagerAdapter
都是继承自PagerAdapter,必须重写一下两个函数
存在的问题
1. 默认情况下,ViewPager会根据setOffscreenPageLimit()方法设置的大小,自动预加载
2. 还是根据setOffscreenPageLimit()方法设置的大小,会去销毁fragment视图
下面的图说明情况
滑动fragment1,此时会预加载fragment2,滑动到fragment2会预加载fragment3,但是滑动到fragment3,此时会调用fragment1的destroyview方法,销毁视图。当重新滑动到fragment1才会重新调用fragment1的oncreateview方法。注意此时并不会销毁实例,不会调用ondestroy方法
这样就存在两个问题
pagerview频繁切换,导致fragment1.fragment3在频繁的调用destroyview和oncreateview方法,重新创建视图。这样也浪费了大量的资源,用户体验不佳,虽然内存消耗比较低 因为切换到fragment1的时候,同时预加载了fragment2,如果此时fragment2也有大量的耗时网络请求要做,如果应用对启动反应速度比较敏感,所以此时做了多余的工作。能否把这些耗时的工作延迟加载,也是个问题
解决方案
1. 防止频繁的销毁视图,setOffscreenPageLimit(2)/或者重写PagerAdaper的destroyItem方法为空即可
setOffscreenPageLimit(2)
//Set the number of pages that should be retained to either side of the current page in the view hierarchy in an idle state.Pages beyond this limit will be recreated from the adapter when needed.You should keep this limit low, especially if your pages have complex layouts. This setting defaults to 1.
大概意思就是说:
设置当前page左右两侧应该被保持的page数量,超过这个限制,page会被销毁重建(只是销毁视图),onDestroy-onCreateView,但不会执行onDestroy。尽量维持这个值小,特别是有复杂布局的时候,因为如果这个值很大,就会占用很多内存,如果只有3-4page的话,可以全部保持active,可以保持page切换的顺滑
这下很好理解了,默认情况下是1,所以当前fragment左右两侧,就会被保持1页pager,所以上述切换到fragment2并不会销毁任何视图,但是到fragment1,3会。这里注意这个值,是左右两侧能够维持的page ,所以如果setOffscreenPageLimit(2),那么就不会频繁的销毁了
destroyItem()
//super.destroyItem(Container , position, object); 注释掉调用父类方法即可
2. 取消预加载,可以fragment的setUserVisibleHint 实现,具体实现参考代码示例
setUserVisibleHint
//Set a hint to the system about whether this fragment's UI is currently visible to the user. This hint defaults to true and is persistent across fragment instance state save and restore.An app may set this to false to indicate that the fragment's UI is scrolled out of visibility or is otherwise not directly visible to the user. This may be used by the system to prioritize operations such as fragment lifecycle updates or loader ordering behavior.
大概意思就是:fragment对用户可见,isVisibleToUser为true,不可见isVisibleToUser为false。对应于viewpager,当前pager,非当前pager
代码示例
主界面
界面布局
<LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="45dp" android:layout_margin="@dimen/padding_10" android:background="@drawable/tab_corner_btn_all_selector" android:orientation="horizontal" > <TextView android:id="@+id/first_item" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/tab_corner_btn_left_selector" android:gravity="center" android:text="第一个" android:textColor="@color/black" android:textSize="15sp" /> <View android:layout_width="@dimen/line" android:layout_height="match_parent" android:background="@color/orange" /> <TextView android:id="@+id/second_item" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/tab_corner_btn_center_selector" android:gravity="center" android:text="第二个" android:textColor="@color/black" android:textSize="15sp" /> <View android:layout_width="@dimen/line" android:layout_height="match_parent" android:background="@color/orange" /> <TextView android:id="@+id/third_item" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/tab_corner_btn_right_selector" android:gravity="center" android:text="第三个" android:textColor="@color/black" android:textSize="15sp" /> </LinearLayout> <android.support.v4.view.ViewPager android:id="@+id/id_vp_viewpager" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>
基类的Fragment
package com.example.viewpagertest; import android.support.v4.app.Fragment; public abstract class BaseFragment extends Fragment { protected boolean isVisible; @Override public void setUserVisibleHint( boolean isVisibleToUser) { super .setUserVisibleHint(isVisibleToUser); if (isVisibleToUser) { isVisible = true ; onVisible(); } else { isVisible = false ; onInvisible(); } } protected void onVisible() { lazyLoad(); } protected void onInvisible() { } protected abstract void lazyLoad(); }
具体fragment
FragmentPagerAdapter实现
package com.example.viewpagertest; public class ListFragmentPagerAdapter extends FragmentPagerAdapter { private static final int TAB_COUNT = 3 ; private List<Fragment> mFragmentList; public ListFragmentPagerAdapter(FragmentManager fm, List<Fragment> fragments) { super (fm); this .mFragmentList = fragments; } @Override public Fragment getItem( int position) { return (mFragmentList == null || mFragmentList.size() < TAB_COUNT) ? null : mFragmentList.get(position); } @Override public int getCount() { return mFragmentList == null ? 0 : mFragmentList.size(); } @Override public void destroyItem(ViewGroup container, int position, Object object) { super .destroyItem(container, position, object); } }