多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內(nèi)最全IT社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > php開源 > 綜合技術(shù) > 【Android】從源碼分析PagerAdapter/FragmentPagerAdapter調(diào)用notifydataSetChanged()刷新的原理

【Android】從源碼分析PagerAdapter/FragmentPagerAdapter調(diào)用notifydataSetChanged()刷新的原理

來源:程序員人生   發(fā)布時間:2015-05-13 08:19:58 閱讀次數(shù):5642次

相信譽過viewpager的同學(xué)都會遇到調(diào)用notifydataSetChanged()后不刷新或不符合預(yù)期的問題,今天就來分析分析這里的來龍去脈。這1切還得從viewpager的setAdapter說起:

/** * Set a PagerAdapter that will supply views for this pager as needed. * * @param adapter Adapter to use */ public void setAdapter(PagerAdapter adapter) { ...(省略若干行,下同) ... final PagerAdapter oldAdapter = mAdapter; mAdapter = adapter; mExpectedAdapterCount = 0; if (mAdapter != null) { if (mObserver == null) { mObserver = new PagerObserver(); } mAdapter.registerDataSetObserver(mObserver); ... ... } ... }

mAdapter.registerDataSetObserver(mObserver)這里用到了視察者模式,mObserver是PagerObserver的1個實例,而PagerObserver是ViewPager的1個內(nèi)部類,其聲明以下:

private class PagerObserver extends DataSetObserver { @Override public void onChanged() { //這里調(diào)用了viewpager的dataSetChanged()方法,下同 dataSetChanged(); } @Override public void onInvalidated() { dataSetChanged(); } }

所以當(dāng)mAdapter數(shù)據(jù)有變化調(diào)用notifydatasetchanged()刷新時就會調(diào)用到PagerObserver 的onChanged方法,繼而調(diào)用到了viewpager的dataSetChanged()方法:

void dataSetChanged() { // This method only gets called if our observer is attached, so mAdapter is non-null. final int adapterCount = mAdapter.getCount(); mExpectedAdapterCount = adapterCount; boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1 && mItems.size() < adapterCount; int newCurrItem = mCurItem; boolean isUpdating = false; 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; ... } ... ... } ... if (needPopulate) { ... ... setCurrentItemInternal(newCurrItem, false, true); requestLayout(); } }

這里看到,調(diào)用mAdapter.getItemPosition,如果返回的值是POSITION_UNCHANGED(PagerAdapter的默許實現(xiàn)),則needPopulate為false,就不會調(diào)用到setCurrentItemInternal(里面間接調(diào)用到instantiateItem(),后面講到),所以就不會刷新視圖。反之,如果返回值是POSITION_NONE,則needPopulate為true,就會調(diào)用到setCurrentItemInternal:

void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) { ... populate(item); ... }

而populate(item)里面會調(diào)用到addNewItem:

ItemInfo addNewItem(int position, int index) { ItemInfo ii = new ItemInfo(); ii.position = position; ii.object = mAdapter.instantiateItem(this, position); ii.widthFactor = mAdapter.getPageWidth(position); if (index < 0 || index >= mItems.size()) { mItems.add(ii); } else { mItems.add(index, ii); } return ii; }


這里看到調(diào)用到了mAdapter.instantiateItem(this, position);而PagerAdapter的instantiateItem里甚么都沒做。

所以如果我們用的是PagerAdapter,我們需要復(fù)寫instantiateitem,例如我們可以這么寫:

@Override public Object instantiateItem(ViewGroup view, int position) { view.addView(mList.get(position)); return mList.get(position); }

而對FragmentPagerAdapter,它復(fù)寫了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; }

其中,getItemId的默許實現(xiàn):

public long getItemId(int position) { return position; }
也就是item對應(yīng)的下標(biāo)就是item的id。另外makeFragmentName的實現(xiàn):

private static String makeFragmentName(int viewId, long id) { return "android:switcher:" + viewId + ":" + id; }
這里makeFragmentName相當(dāng)于為這個fragment組裝成1個標(biāo)識Tag,如果之前沒添加過這個fragment,也就是mFragmentManager.findFragmentByTag(name)返回null,那末就調(diào)用 getItem(position);獲得fragment,然后把這個fragment添加進去。

反之,也就是之前已添加過這個fragment了,則不會調(diào)用 getItem(position)了,而是直接attach上這個fragment。


參考

http://www.cnblogs.com/dancefire/archive/2013/01/02/why-notifydatasetchanged-does-not-work.html









生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 国产精品3| 亚洲一区二区三区精品影院 | vvideos欧美极度另类 | 激性欧美激情在线播放16页 | 亚洲第一a | 俄罗斯高清freexxxx性 | 那里有黄色网址 | 中文乱码一二三四有限公司 | 一区二区三区在线视频播放 | 三级小说第一页 | 亚洲成人福利 | 尤物精品 | 欧美18一19sex性hd | 一级片免费 | 久久精品国产亚洲麻豆 | 亚洲久久网站 | 请看一下欧美一级毛片 | 伊人久久婷婷 | 波多野结衣精品一区二区三区 | 亚洲欧美日韩精品久久久 | 国产成人精品综合久久久 | 羞羞免费观看网站 | 国产jizz美国jizz免费看 | 2021天天躁夜夜躁狠狠躁 | 国产亚洲欧美久久精品 | 丁香综合五月 | 国内久久久久影院精品 | 国产精品免费视频一区一 | 欧美午夜影院 | 亚洲欧美国产另类视频 | 欧美肥老太肥50 60 70 | 在线观看噜噜噜私人影院 | 久久99热成人精品国产 | 国产成人一区二区三区高清 | 亚洲大片在线观看 | 天天综合久久 | 久久ri精品高清一区二区三区 | 日本欧美在线观看 | 全国男人天堂网 | 欧美一级片网 | 91美女福利视频 |