PagerAdapter刷新问题
一、PagerAdapter介绍
PagerAdapter简介
ListView 大家应该都很熟悉吧!ListView 一般都需要一个 Adapter 来填充数据,如 ArrayAdapter、SimpleAdapter。PagerAdapter 就是 ViewPager 的 Adapter,与 ListView 的 Adapter 作用一样。
ViewPager->PageAdapter == ListView->BaseAdapter
先看下官方介绍
官方介绍
PageAdapter 继承自 Object,继承结构参考意义不大,那老实看文档。文档上没有提供示例代码,只是说了下要自定义 PageAdapter 需要实现下面四个方法:
- instantiateItem(ViewGroup container, int position):该方法的功能是创建指定位置的页面视图。适配器有责任增加即将创建的 View 视图到这里给定的 container 中,这是为了确保在 finishUpdate(viewGroup) 返回时 this is be done!
返回值:返回一个代表新增视图页面的 Object(Key),这里没必要非要返回视图本身,也可以这个页面的其它容器。其实我的理解是可以代表当前页面的任意值,只要你可以与你增加的 View 一一对应即可,比如 position 变量也可以做为 Key - destroyItem(ViewGroup container, int position, Object object):该方法的功能是移除一个给定位置的页面。适配器有责任从容器中删除这个视图,这是为了确保在 finishUpdate(viewGroup) 返回时视图能够被移除
- getCount():返回当前有效视图的数量
- isViewFromObject(View view, Object object):该函数用来判断 instantiateItem() 函数所返回来的 Key 与一个页面视图是否是代表的同一个视图(即它俩是否是对应的,对应的表示同一个 View)
返回值:如果对应的是同一个View,返回 true,否则返回 false
上面对 PageAdapter 的四个抽象方法做了简要说明,下面看看如何使用
简单使用
mContentVP.setAdapter(new PagerAdapter() {
@Override
public int getCount() {
return dataList.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view = View.inflate(SimpleDemoActivity.this, R.layout.item_vp_demopageradapter, null);
TextView pageNumTV = (TextView) view.findViewById(R.id.tv_pagenum);
pageNumTV.setText("" + dataList.get(position));
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
});
可以看到实现 PagerAdapter 与 BaseAdapter 很类似,只是 PagerAdapter 的 isViewFromObject() 与 instantiateItem() 方法需要好好理解下。
PagerAdapter 刷新的问题
提出问题
在使用 ListView 的时候,我们往往习惯了更新 Adapter 的数据源,然后调用 Adapter 的 notifyDataSetChanged() 方法来刷新列表(有没有点 MVC 的感觉)。
PagerAdapter 也有 notifyDataSetChanged() 方法,那我们按照这个流程来试试,看有没有什么问题。(ListView 的示例就不在这里演示了,感兴趣的可以自己去试试,非常简单)
那么我的问题是:“ViewPager 的 PagerAdapter 在数据源更新后,能否自动刷新视图?”
带着问题,我们做一些实验,下面实验的思路是:修改数据源,然后通知 PagerAdapter 更新,查看视图的变化。
实验环境准备
看看实验环境,上代码:
private void initData() {
// 数据源
mDataList = new ArrayList<>(5);
mDataList.add("Java");
mDataList.add("Android");
mDataList.add("C&C++");
mDataList.add("OC");
mDataList.add("Swift");
// 很简单的一个 PagerAdapter
this.mContentVP.setAdapter(mPagerAdapter = new PagerAdapter() {
@Override
public int getCount() {
return mDataList.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view = View.inflate(SimpleDemoActivity.this, R.layout.item_vp_demopageradapter, null);
TextView pageNumTV = (TextView) view.findViewById(R.id.tv_pagenum);
pageNumTV.setText("DIY-PageNum-" + mDataList.get(position));
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
});
}
PagerAdapter 刷新实验
1、更新数据源中的某项
对应代码:
private void refresh() {
mDataList.set(0, "更新数据源测试");
mPagerAdapter.notifyDataSetChanged();
}
问题描述:在演示动画中可以看到,更新数据源之后视图并没有立即刷新,多滑动几次再次回到更新的 Item 时才更新(这里先看问题,下面会细说)。
2、往数据源中添加数据
对应代码:
private void add() {
mDataList.add("这是新添加的Item");
mPagerAdapter.notifyDataSetChanged();
}
问题描述:没什么问题,数据源添加数据后通知 PagerAdapter 刷新,ViewPager 中就多了一个 Item。
3、从数据源中删除数据
private void delete() {
mDataList.remove(0);
mPagerAdapter.notifyDataSetChanged();
}
问题描述:这个问题就较多了,首先,如果是删除当前 Item,那么会看到没有任何反应;其次,如果删除的不是当前 Item,会发现出现了数据错乱,并且后面有 Item 滑不过去,但是按住往后滑的时候可以看到后面的 Item。
4、将数据源清空
private void clean() {
mDataList.clear();
mPagerAdapter.notifyDataSetChanged();
}
问题描述:从上面的动图可以看到,清空数据源之后,会残留一个 Item。
说明:先不要计较上面所写的 PagerAdapter 是否有问题,这里只是想引出问题来,下面会针对 PagerAdapter、FragmentPagerAdapter 以及 FragmentStatePagerAdapter 来分析问题原因和给出解决方案。
二、PagerAdapter
从上面的实验可以看出 ViewPager 不同于 ListView,如果单纯的调用 ViewPager.getAdapter().notifyDataSetChanged() 方法(即 PagerAdapter 的 notifyDataSetChanged()方法)页面并没有刷新。
PagerAdapter 用于 ViewPager 的 Item 为普通 View的情况,这个相对简单,所以最先介绍。
相信很多同学都搜过类似的问题 —— “PagerAdapter 的 notifyDataSetChanged() 不刷新?”。有的说这是 bug,有的则认为 Google 是特意这样设计的,个人倾向后一种观点(我觉得这是 Google 为了 ViewPager 性能考虑而设计的,毕竟 ViewPager 需要显示“很多大的”视图,而且要防止用户滑动时觉得卡顿)。
ViewPager 刷新分析
先来了解下 ViewPager 的刷新过程:
1、刷新的起始
ViewPager 的刷新是从调用其 PagerAdapter 的 notifyDataSetChanged() 方法开始的,那先看看该方法的源码(在源码面前一切无所遁形...):
/**
* This method should be called by the application if the data backing this adapter has changed
* and associated views should update.
*/
public void notifyDataSetChanged() {
synchronized (this) {
if (mViewPagerObserver != null) {
mViewPagerObserver.onChanged();
}
}
mObservable.notifyChanged();
}
2、DataSetObservable 的 notifyChanged()
上面的方法中出现了两个关键的成员变量:
private final DataSetObservable mObservable = new DataSetObservable();
private DataSetObserver mViewPagerObserver;
观察者模式,有没有?先不着急分析这个是不是观察者模式,来看看 mObservable.notifyChanged() 做了些什么工作:
/**
* Invokes {@link DataSetObserver#onChanged} on each observer.
* Called when the contents of the data set have changed. The recipient
* will obtain the new contents the next time it queries the data set.
*/
public void notifyChanged() {
synchronized(mObservers) {
// since onChanged() is implemented by the app, it could do anything, including
// removing itself from {@link mObservers} - and that could cause problems if
// an iterator is used on the ArrayList {@link mObservers}.
// to avoid such problems, just march thru the list in the reverse order.
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
notifyChanged() 方法中是很典型的观察者模式中遍历所有的 Observer,通知 变化发生了的代码。代码很简单,那关键是这个 mObservers 包含哪些 Observer 呢?
3、DataSetObserver
直接从 mObservers 点进去你会发现这个:
protected final ArrayList<T> mObservers = new ArrayList<T>();
-_-',这是个泛型,坑了!还好 DataSetObservable 的 notifyChanged() 的注释中写了这些 Observer 是 DataSetObserver。那去看看 DataSetObserver:
public abstract class DataSetObserver {
/**
* This method is called when the entire data set has changed,
* most likely through a call to {@link Cursor#requery()} on a {@link Cursor}.
*/
public void onChanged() {
// Do nothing
}
/**
* This method is called when the entire data becomes invalid,
* most likely through a call to {@link Cursor#deactivate()} or {@link Cursor#close()} on a
* {@link Cursor}.
*/
public void onInvalidated() {
// Do nothing
}
}
一个抽象类,里面两个空方法,这个好办,找他的子类(AndroidStudio 中 将光标放到类名上,按 F4):
总算找到你了,就是用红线框出来的那条,双击,定位过去。
4、PagerObserver 内部类
PagerObserver 是 ViewPager 中的一个内部类,实现也很简单,就是调用了 ViewPager 中的 dataSetChanged() 方法,真正的关键来了。
private class PagerObserver extends DataSetObserver {
@Override
public void onChanged() {
dataSetChanged();
}
@Override
public void onInvalidated() {
dataSetChanged();
}
}
5、ViewPager 的 dataSetChanged()
这个方法的实现较长,里面的逻辑看上去挺复杂的,这里就不展示全部的源码了,列下关键点:
...
for (int i = 0; i < mItems.size(); i++) {
final ItemInfo ii = mItems.get(i);
final int newPos = mAdapter.getItemPosition(ii.object);
if (newPos == PagerAdapter.POSITION_UNCHANGED) {
continue;
}
if (newPos == PagerAdapter.POSITION_NONE) {
...
continue;
}
...
}
...
上面截取的代码中 for 循环里面有两个 continue 语句,这可能是比较关键的代码,幸好不用我们继续深入了,官方给出了解释:
Called when the host view is attempting to determine if an item's position has changed. Returns POSITION_UNCHANGED if the position of the given item has not changed or POSITION_NONE if the item is no longer present in the adapter.The default implementation assumes that items will never change position and always returns POSITION_UNCHANGED.
大致的意思是:
如果 Item 的位置如果没有发生变化,则返回
POSITION_UNCHANGED。如果返回了 POSITION_NONE,表示该位置的 Item 已经不存在了。默认的实现是假设 Item
的位置永远不会发生变化,而返回 POSITION_UNCHANGED。
上面在源码里面跟了一大圈是不是还是感觉没有明朗,因为还有一个很关键的类 —— PagerAdapter 没有介绍,再给点耐心,继续。
6、PagerAdapter 的工作流程
其实就是 PagerAdapter 中方法的执行顺序:
PagerAdapter 作为 ViewPager 的适配器,无论 ViewPager 有多少页,PagerAdapter
在初始化时也只初始化开始的2个 View,即调用2次instantiateItem 方法。而接下来每当 ViewPager
滑动时,PagerAdapter 都会调用 destroyItem 方法将距离该页2个步幅以上的那个 View 销毁,以此保证
PagerAdapter 最多只管辖3个 View,且当前 View 是3个中的中间一个,如果当前 View 缺少两边的 View,那么就
instantiateItem,如里有超过2个步幅的就 destroyItem。
简易图示:
*
------+---+---+---+------
... 0 | 1 | 2 | 3 | 4 ...
------+---+---+---+------
当前 View 为2号 View,所以 PagerAdapter 管辖1、2、3三个 View,接下来向左滑动-->
*
------+---+---+---+------
... 1 | 2 | 3 | 4 | 5 ...
------+---+---+---+------
滑动后,当前 View 变为3号 View,PagerAdapter 会 destroyItem 0号View,instantiateItem 5号 View,所以 PagerAdapter 管辖2、3、4三个 View。
总结一下: Viewpager 的刷新过程是这样的,在每次调用 PagerAdapter 的 notifyDataSetChanged() 方法时,都会激活 getItemPosition(Object object) 方法,该方法会遍历 ViewPager 的所有 Item(由缓存的 Item 数量决定,默认为当前页和其左右加起来共3页,这个可以自行设定,但是至少会缓存2页),为每个 Item 返回一个状态值(POSITION_NONE/POSITION_UNCHANGED),如果是 POSITION_NONE,那么该 Item 会被 destroyItem(ViewGroup container, int position, Object object) 方法 remove 掉,然后重新加载,如果是 POSITION_UNCHANGED,就不会重新加载,默认是 POSITION_UNCHANGED,所以如果不重写 getItemPosition(Object object),修改返回值,就无法看到 notifyDataSetChanged() 的刷新效果。
临时解决方法
那就是直接一刀切:重写 PagerAdapter 的 getItemPosition(Object object) 方法,将返回值固定为 POSITION_NON
上代码:
@Override
public int getItemPosition(Object object) {
// 最简单解决 notifyDataSetChanged() 页面不刷新问题的方法
return POSITION_NONE;
}
该方案的缺点:有个很明显的缺陷,那就是会刷新所有的 Item,这将导致系统资源的浪费,所以这种方式不适合数据量较大的场景。
注意:
这种方式还有一个需要注意的地方,就是重写 destoryItem() 方法:
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
// 把 Object 强转为 View,然后将 view 从 ViewGroup 中清除
container.removeView((View) object);
}
方案的优化
这里提供一个思路,毕竟场景太多,相信大家理解了思路要实现就很简单了,闲话不多说。
思路:在 instantiateItem() 方法中给每个 View 添加 tag(使用 setTag() 方法),然后在 getItemPosition() 方法中通过 View.getTag() 来判断是否是需要刷新的页面,是就返回 POSITION_NONE,否就返回 POSITION_UNCHANGED。
注意:这里有一点要注意的是,当清空数据源的时候需要返回 POSITION_NONE,可用如下代码:
if (mDataList != null && mDataList.size()==0) {
return POSITION_NONE;
}
关于 PagerAdapter 的介绍就到这里了,虽然 FragmentPagerAdapter 与 FragmentStatePagerAdapter 都是继承自 PagerAdapter。但是,这两个是专门为以 Fragment 为 Item 的 ViewPager 所准备的,所以有其特殊性。且看下面的介绍。
三、FragmentPagerAdapter
简介
上面通过使 getItemPosition() 方法返回 POSITION_NONE 到达数据源变化(也就是调用 notifyDataSetChanged())时,刷新视图的目的。但是当我们使用 Fragment 作为 ViewPager 的 Item 时,就需要多考虑一些了,而且一般是使用 FragmentPagerAdapter 或者 FragmentStatePagerAdapter。
这里不展开讨论 FragmentPagerAdapter 与 FragmentStatePagerAdapter 的异同和使用场景了,感兴趣的可以看看这篇文章:FragmentPagerAdapter与FragmentStatePagerAdapter区别。
下面先来看看使用 FragmentPagerAdapter 时,如何在数据源发生变化时,刷新 Fragment 或者动态改变 Items 的数量。
方案:清除 FragmentManager 中缓存的 Fragment
实现上图效果的关键代码:
private void refresh() {
if (checkData()) return;
mDataList.set(0, 7); // 修改数据源
mPagerAdapter.updateData(mDataList); // 通知 Adapter 更新
}
private void add() {
mDataList.add(7);
mPagerAdapter.updateData(mDataList);
}
private void delete() {
if (checkData()) return;
mDataList.remove(0);
mPagerAdapter.updateData(mDataList);
}
private void clear() {
if (checkData()) return;
mDataList.clear();
mPagerAdapter.updateData(mDataList);
}
2、FPagerAdapter1.java
public class FPagerAdapter1 extends FragmentPagerAdapter {
private ArrayList<Fragment> mFragmentList;
private FragmentManager mFragmentManager;
public FPagerAdapter1(FragmentManager fm, List<Integer> types) {
super(fm);
this.mFragmentManager = fm;
mFragmentList = new ArrayList<>();
for (int i = 0, size = types.size(); i < size; i++) {
mFragmentList.add(FragmentTest.instance(i));
}
setFragments(mFragmentList);
}
public void updateData(List<Integer> dataList) {
ArrayList<Fragment> fragments = new ArrayList<>();
for (int i = 0, size = dataList.size(); i < size; i++) {
Log.e("FPagerAdapter1", dataList.get(i).toString());
fragments.add(FragmentTest.instance(dataList.get(i)));
}
setFragments(fragments);
}
private void setFragments(ArrayList<Fragment> mFragmentList) {
if(this.mFragmentList != null){
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
for(Fragment f:this.mFragmentList){
fragmentTransaction.remove(f);
}
fragmentTransaction.commit();
mFragmentManager.executePendingTransactions();
}
this.mFragmentList = mFragmentList;
notifyDataSetChanged();
}
@Override
public int getCount() {
return this.mFragmentList.size();
}
public int getItemPosition(Object object) {
return POSITION_NONE;
}
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
}
3、思路分析
上面的代码思路很简单,就是当数据源发生变化时,先将 FragmentManger 里面所有缓存的 Fragment 全部清除,然后重新创建,这样达到刷新视图的目的。
但是,这样做有一个缺点,那就是会造成不必要的浪费,会影响性能。还有就是必须使用一个 List 缓存所有的 Fragment,这也得占用不少内存...
思路挺简单,这里不再赘述,那看看有没有什么可以优化的。
优化:通过 Tag 获取缓存的 Fragment
从上面的动图上可以看到,更新某一个 Fragment 没有问题,清空数据源的时候也没有,添加当然也没什么问题;请注意删除的效果,虽然,目的 Fragment 确实从 ViewPager 中移除了,但是滑动后面的页面会发现出现了数据错乱。
分析一下优化的思路:
先来了解 FragmentPagerAdapter 中是如何管理 Fragment 的,这里涉及到 FragmentPagerAdapter 中的 instantiateItem() 方法:
@Override
public Object instantiateItem(ViewGroup container, int position) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
final long itemId = getItemId(position);
// Do we already have this fragment?
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
mCurTransaction.attach(fragment);
} else {
fragment = getItem(position);
if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), itemId));
}
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
}
return fragment;
}
从源码中可以看到在从 FragmentManager 中取出 Fragment 时调用了 findFragmentByTag() 方法,而这个 Tag 是由 makeFragmentName() 方法生成的。继续往下可以看到每一个 Fragment 都打上了一个标签(在 mCurTransaction.add() 方法中)。
也就是说是 FragmentManager 通过 Tag 找相应的 Fragment,从而达到缓存 Fragment 的目的。如果可以找到,就不会创建新的 Fragment,Fragment 的 onCreate()、onCreateView() 等方法都不会再次调用。
那优化的思路就有了:
首先,需要缓存所有 Fragment 的 Tag,代码如下:
private List<String> mTagList; // 用来存放所有的 Tag
// 生成 Tag
// 直接从 FragmentPageAdapter 源码里拷贝 Fragment 生成 Tag 的方法
private String makeFragmentName(int viewId, int index) {
return "android:switcher:" + viewId + ":" + index;
}
// 将 Tag 缓存到 List 中
@Override
public Object instantiateItem(ViewGroup container, int position) {
mTagList.add(position, makeFragmentName(container.getId(),
(int) getItemId(position)));
return super.instantiateItem(container, position);
}
其次,在更新 Fragment 时,使用相应的 Tag 去 FragmentManamager 中找相应的 Fragment,如果存在,就直接更新,代码如下:
public void update(int position, String str) {
Fragment fragment = mFragmentManager.findFragmentByTag(mTagList.get(position));
if (fragment == null) return;
if (fragment instanceof FragmentTest) {
((FragmentTest)fragment).update(str);
}
notifyDataSetChanged();
}
该方法需要自行在 Fragment 中提供。
最后,对于动态改变 ViewPager 中 Fragment 的数量,如果是添加,那没什么要注意的;但是删除有点棘手。
在上面的动态上看到,删除一个 Fragment 后会出现混乱,这里没有进一步去研究了,这里仅提供一个示例供参考
public void remove(int position) {
mDataList.remove(position);
isDataSetChange = true;
Fragment fragment = mFragmentManager.findFragmentByTag(mTagList.get(position));
mTagList.remove(position);
if (fragment == null) {
notifyDataSetChanged();
return;
}
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
fragmentTransaction.remove(fragment);
fragmentTransaction.commit();
mFragmentManager.executePendingTransactions();
notifyDataSetChanged();
}
注意:
这个”优化“示例,仅仅适用于在只需要更新某个 Fragment 的场景,关于动态删除 Fragment,该”优化“方案并不适用,也不推荐使用。
四、FragmentStatePagerAdapter
简介
FragmentStatePagerAdapter
与 FragmentPagerAdapter 类似,这两个类都继承自 PagerAdapter。但是,和
FragmentPagerAdapter 不一样的是,FragmentStatePagerAdapter
只保留当前页面,当页面离开视线后,就会被消除,释放其资源;而在页面需要显示时,生成新的页面(这和 ListView
的实现一样)。这种方式的好处就是当拥有大量的页面时,不必在内存中占用大量的内存。
FragmentStatePagerAdapter 的实现与 FragmentPagerAdapter 有很大区别,如果照搬上述
FragmentPagerAdapter 刷新数据的方式,你会发现没有什么问题。
另一种思路
如果,你也是这样使用 FragmentStatePagerAdapter 来动态改变 ViewPager 中 Fragment,并且在
remove Fragment 时遇到了
IllegalStateException。那么,你可以考虑使用下面的方式,先看代码(FSPagerAdapter .java):
public class FSPagerAdapter extends FragmentStatePagerAdapter {
private ArrayList<Fragment> mFragmentList;
public FSPagerAdapter(FragmentManager fm, List<Integer> types) {
super(fm);
updateData(types);
}
public void updateData(List<Integer> dataList) {
ArrayList<Fragment> fragments = new ArrayList<>();
for (int i = 0, size = dataList.size(); i < size; i++) {
Log.e("FPagerAdapter1", dataList.get(i).toString());
fragments.add(FragmentTest.instance(dataList.get(i)));
}
setFragmentList(fragments);
}
private void setFragmentList(ArrayList<Fragment> fragmentList) {
if(this.mFragmentList != null){
mFragmentList.clear();
}
this.mFragmentList = fragmentList;
notifyDataSetChanged();
}
@Override
public int getCount() {
return this.mFragmentList.size();
}
public int getItemPosition(Object object) {
return POSITION_NONE;
}
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
}
上面的代码挺简单,稍微解释一下实现思路:
1、缓存所有的 Fragment
使用一个 List 将数据源对应的 Fragment 都缓存起来
2、更新数据源,刷新 Fragment
当有数据源更新的时候,从 List 中取出相应的 Fragment,然后刷新 Adapter
3、删除数据时,删除 List 中对应的 Fragment
当数据源中删除某项时,将 List 中对应的 Fragment 也删除,然后刷新 Adapter
小结
关于 ViewPager 数据源刷新比较麻烦的地方是从数据源中删除数据的情况,这和 ViewPager 的实现方式有关,我们在解决该问题的时候要分具体情况来采取不同的方案。
上面提供的方案也不是完美的;这里主要是探讨关于 ViewPager 数据源刷新的问题,关于 ViewPager 的详细使用不是本文重点,这里就不涉及了。
PagerAdapter刷新问题的更多相关文章
- Android - ViewPager实现Gallery效果
RelativeLayout viewPagerContainer = (RelativeLayout) headerView.findViewById(R.id.content_pager_layo ...
- Android Viewpager PagerAdapter update data 刷新界面数据
最近做的项目涉及到ViewPager数据刷新,网上的资料挺多,但是和现在做的这个不太相同,所以并没有找到有效的. 折腾了大半天,整理一下思路: 问题1: 后台刷新数据次数过多后,界面出现卡顿现象,判断 ...
- ViewPager 重新加载 及 PagerAdapter 使用
PagerAdapter 简介 PagerAdapter是android.support.v4包中的类,它的子类有FragmentPagerAdapter, FragmentStatePagerAda ...
- 转载---ViewPager,PagerAdapter,FragmentPagerAdapter和FragmentStatePagerAdapter的分析对比
转载:http://blog.csdn.net/dreamzml/article/details/9951577 ViewPager ViewPager 如其名所述,是负责翻页的一个 View.准确说 ...
- android 项目学习随笔十一(ListView下拉刷新提示)
1. 设置mHeaderView.setPadding TOPPADING为负值,隐藏刷新提示头布局 在onTouchEvent事件中进行头布局显示隐藏切换 import java.text.Simp ...
- Android ViewPager刷新解析
ViewPager刷新解析 原本以为PagerAdapter类似于BaseAdapter 但是使用起来发现刷新还是有区别的 解析如下 先上Demo PagerAdapter的四大函数 getCount ...
- Android viewPage notifyDataSetChanged无刷新
转载 http://www.67tgb.com/?p=624 最近项目结束,搞了一次代码分享.其中一位同学分享了一下自己在解决问题过程中的一些心得体会,感觉受益匪浅.整理出来,分享给大家. 建议使用自 ...
- android124 zhihuibeijing 新闻中心-新闻 -北京页签 下拉刷新
缓存工具类:以url为key,json数据为value, package com.itheima.zhbj52.utils; import com.itheima.zhbj52.global.Glob ...
- FragmentStatePagerAdapter.notifyDataSetChanged不刷新页面的解决的方法
公司做医疗产品的,显示操作用的是android.所以我就用上下两个部分大致是固定的,仅仅有中间会有6个页面的切换,当中会有两个用户的切换.即普通用户和管理员用户,图片能够大致展示一下 其他页面是同样的 ...
随机推荐
- python 理解高阶函数
高阶函数 高阶函数英文叫Higher-order function.什么是高阶函数? 变量可以指向函数 以Python内置的求绝对值的函数abs()为例,调用abs(): >>> a ...
- grep 参数
功能说明:查找文件里符合条件的字符串. 语 法:grep [-abcEFGhHilLnqrsvVwxy][-A<显示列数>][-B<显示列数>][-C<显示列数>] ...
- matlab学习之绘制参数曲线,添加辅助线以及颜色设置
粘贴代码 % 插入参数曲线h % 插入辅助线h1 % 并设置颜色,包括画布颜色和曲线颜色 t=-pi:0.1:pi; x=cos(t)-sin(3*t); y=sin(t).*cos(t)-cos(3 ...
- uva 10910(子集和问题)
Marks Distribution Time limit: 3.000 seconds In an examination one student appeared in N subjects an ...
- 【kd-tree】hdu5992 Finding Hotels
比较裸的kd-tree,但是比较考验剪枝. 貌似除了经典的矩形距离剪枝之外, 还必须加个剪枝是某个矩形内的最小价格如果大于价格限制的话,则剪枝. #include<cstdio> #inc ...
- [NOIp2016提高组]蚯蚓
题目大意: 给你n个不同长度蚯蚓,每秒从里面取出最长的砍下u/v变成两只,又把剩下的加长q. 问你在m之前的t,2t,3t...的时间上,砍的蚯蚓长度, 以及m秒后剩下所有的蚯蚓长度. 思路: 很容易 ...
- 第一个程序-Hello world
创建HelloWorld项目 1.在Android Studio的欢迎界面点击Start a new Android Studio project 2.填写Application name(表示应用名 ...
- java中interface的完整表述
我用一个工具:java Decompiler反编译工具查看jar包源码的时候,出现了以下代码: public abstract interface AbsITest{} 在网上搜索了一下: 我对这种情 ...
- ucenter创始人密码忘记了,修改方法
简单的:1.在UCenter/data/下找到config.inc.php,打开找到下面2行代码: define('UC_FOUNDERPW', '3858cdf66b0794bfd435af8c0c ...
- Spring注解@Primary的意思
@Primary:在众多相同的Bean中,优先使用@Primary注解的Bean. 这个和@Qualifier有点区别,@Qualifier指的是使用哪个Bean进行注入. 参考: http://bl ...