本文主要解決應用ViewPager和PagerAdapter時,調用ViewPager中的getAdapter()方法,獲取Adapter對象之後調用notifyDataSetChanged()方法如何達到更新數據的目的。先不考慮FragmentStatePagerAdapter和FragmentPagerAdapter這兩個基於PagerAdpter的衍生類
- 首先一張圖來看下ViewPager和PagerAdapter裏面會涉及到的東西
主要類的簡單介紹
- ViewPager
這是一個用於翻頁展示的類,裏面包含了用於展示的相關信息
- ViewPager
static class ItemInfo {
Object object;//每次用於展示的對象
int position;//每個Item的在ViewPager中的位置
boolean scrolling;//是否在滾動
float widthFactor;//表示加載的頁面佔ViewPager所佔的比例[0~1](默認返回1)
float offset;//偏移量
}
private class PagerObserver extends DataSetObserver {
@Override
public void onChanged() {
dataSetChanged();
}
@Override
public void onInvalidated() {
dataSetChanged();
}
}
這是一個對數據集(DataSet)進行觀察的類,當數據集改變時,會調用他的onChanged()或者onInvalidated()方法。這個對象需要在PagerAdapter()中的被觀察者(DataSetObservable)中進行註冊
對於setAdapter()方法:
public void setAdapter(PagerAdapter adapter) {
if (mAdapter != null) {
mAdapter.unregisterDataSetObserver(mObserver);
mAdapter.startUpdate(this);//註銷觀察者
for (int i = 0; i < mItems.size(); i++) {
final ItemInfo ii = mItems.get(i);
mAdapter.destroyItem(this, ii.position, ii.object);
//使得在ViewPager中調用PagerAdapter裏面的方法成爲了可能
}
mAdapter.finishUpdate(this);
mItems.clear();
removeNonDecorViews();
mCurItem = 0;
scrollTo(0, 0);
}
//省略....
if (mAdapter != null) {
if (mObserver == null) {
mObserver = new PagerObserver();
}
mAdapter.registerDataSetObserver(mObserver);//註冊觀察者
//以下省略...
}
//以下省略...
}
setAdapter()方法建立了ViewPager和PagerAdapter的聯繫,通過註冊觀察者,讓ViewPager能夠接收到數據變化時,重新加載數據的請求
- PagerAdapter類
主要作用是爲了給ViewPager提供需要展示的內容,這是一個內容生成器。需要說明的是這是一個抽象類,需要在繼承時實現裏面的
- instantiateItem():在這裏面初始化Item的內容
- destroyItem() : 銷燬Item
- getCount() : 返回Item的數目
- isViewFromObject()。標識一個視圖是否和給定的Key對象相關[1]
3 . 當數據變化時的流程
首先在activity中會調用 ViewPager.getAdapter().notifyDataSetChanged()方法,通知數據發生改變
public void notifyDataSetChanged() {
mObservable.notifyChanged();
//然後去調用DataSetObservable類中的方法
}
DataSetObservable類中:
public void notifyChanged() {
synchronized(mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
//通知所有觀察者數據發生變化,其中包括已經在setAdapter()時註冊的PagerObserver
}
}
}
在ViewPager內部類PagerObserver中接收到通知(這是觀察者模式的應用)並調用其中的onChanged()方法裏面的dataSetChanged()方法,我們看到這個方法的內容:
void dataSetChanged() {
// This method only gets called if our observer is attached, so mAdapter is non-null.
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) {
mItems.remove(i);
i--;
if (!isUpdating) {
mAdapter.startUpdate(this);
isUpdating = true;
}
mAdapter.destroyItem(this, ii.position, ii.object);
needPopulate = true;
//這裏是對PagerAdapter.getItemPosition()方法的返回值進行判斷:
//POSITION_NONE時進行數據更新,
//POSITION_UNCHANGED時,標識符 needPopulate=false 不更新數據
.
.
.
if (needPopulate) {
.
.
.
setCurrentItemInternal(newCurrItem, false, true);
//這裏會去調用populate()方法(這個方法的主要作用就是加載和渲染頁面)
//重新做了加載數據的操作
requestLayout();
}
}
到此數據更新完成。
4 .參考:
a.http://www.cnblogs.com/dancefire/archive/2013/01/02/why-notifydatasetchanged-does-not-work.html
b.http://blog.csdn.net/u011494050/article/details/45366763
c.http://www.jianshu.com/p/85afaf9e8f6e
d.http://blog.csdn.net/u011494050/article/details/45366763
[1].http://blog.csdn.net/dmk877/article/details/50060745