ViewPager+Fragment的模式再常見不過了征峦,以國民應(yīng)用微信為例,假設(shè)微信也是ViewPager+Fragment的實(shí)現(xiàn)方式消请,那表現(xiàn)形式上就是一個(gè)ViewPager管理了四個(gè)Fragment栏笆,左右滑動(dòng)來回切換。但是ViewPager有一個(gè)奇葩的特性叫:預(yù)加載臊泰,比如打開微信蛉加,首先看到的是第一個(gè)Tab(微信),但事實(shí)上第二個(gè)Tab(通訊錄)已經(jīng)加載好了缸逃。當(dāng)選擇第二個(gè)Tab(通訊錄)七婴,第三個(gè)Tab(發(fā)現(xiàn))已經(jīng)加載好了蜕劝,以此類推嘹狞。
但上訴ViewPager+Fragment的這種組合并不完美有勾,因?yàn)槲蚁M脩暨x擇了哪個(gè)Tab再去加載哪個(gè)Tab的數(shù)據(jù),而不要去做預(yù)加載贺辰,假如當(dāng)前頁面和預(yù)加載頁面都有大量的網(wǎng)絡(luò)請求,可能就會(huì)比較慢嵌施,有很多請求在排隊(duì)饲化。關(guān)于這個(gè)問題,也有很偏激的做法吗伤,比如棄用ViewPager吃靠,自己手動(dòng)管理Fragment,或者直接禁掉ViewPager預(yù)加載足淆。有一種比較合適的方案是保持ViewPager預(yù)加載的特性巢块,但是只初始化View,選擇當(dāng)前Tab的時(shí)候再進(jìn)行網(wǎng)絡(luò)請求巧号。關(guān)于這一方案的實(shí)現(xiàn)族奢,也是眾說紛紜,千奇百怪丹鸿。最后越走,還是選擇男神Stay的方案。
直接上代碼靠欢。
public abstract class BasePageFragment extends Fragment {
protected boolean isViewInitiated;
protected boolean isVisibleToUser;
protected boolean isDataInitiated;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
isViewInitiated = true;
prepareFetchData();
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
this.isVisibleToUser = isVisibleToUser;
prepareFetchData();
}
public abstract void fetchData();
public boolean prepareFetchData() {
return prepareFetchData(false);
}
public boolean prepareFetchData(boolean forceUpdate) {
if (isVisibleToUser && isViewInitiated && (!isDataInitiated || forceUpdate)) {
fetchData();
isDataInitiated = true;
return true;
}
return false;
}
}
這是一個(gè)父類廊敌,看代碼這里只有一個(gè)setUserVisibleHint需要說下,這是一個(gè)相當(dāng)生僻的方法门怪,我們可以用這個(gè)方法來判斷當(dāng)前UI是否可見骡澈,所以在prepareFetchData方法里我們做如下判斷:就是當(dāng)前UI可見,并且fragment已經(jīng)初始化完畢掷空,如果網(wǎng)絡(luò)數(shù)據(jù)未加載秧廉,那么請求數(shù)據(jù)伞广,或者需要強(qiáng)制刷新頁面,那么也去請求數(shù)據(jù)疼电,So easy嚼锄。子Fragment只需要繼承父類,實(shí)現(xiàn)抽象方法蔽豺,在fetchData()里做網(wǎng)絡(luò)請求或者其他耗時(shí)操作即可区丑。再在寫個(gè)子類吧。
public class PageFragment extends BasePageFragment {
public static PageFragment newInstance(String title){
PageFragment fragment = new PageFragment();
Bundle args = new Bundle();
args.putString("key_fragment_title", title);
fragment.setArguments(args);
return fragment;
}
private String title;
private TextView tv;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
title = getArguments().getString("key_fragment_title");
Trace.d(title + ":onCreate");
}
@Override
public void onResume() {
super.onResume();
Trace.d(title + ":onResume");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Trace.d(title + ":onCreateView");
tv = new TextView(getActivity());
return tv;
}
@Override
public void fetchData() {
tv.setText(title);
/** * 在這里請求網(wǎng)絡(luò)修陡。 */
}
}
如果你也有這樣的需求或者煩惱沧侥,保證藥到病除。
有同學(xué)說實(shí)踐過程中遇到了些問題魄鸦,比如Fragment只刷新一次宴杀,這個(gè)問題只要手動(dòng)調(diào)用prepareFetchData(),傳true即可強(qiáng)制刷新了拾因。還有同學(xué)質(zhì)疑setUserVisibleHint()和onActivityCreated()的執(zhí)行先后的問題旺罢。關(guān)于這個(gè)請看下圖。