Android 開(kāi)發(fā)中患膛,經(jīng)常使用到 ViewPager + Fragment 的組合實(shí)現(xiàn)多頁(yè)面的的數(shù)據(jù)展示。為了保證滑動(dòng)流暢迁匠,ViewPager 引入了預(yù)加載機(jī)制剩瓶;ViewPager 通過(guò)setOffscreenPageLimt(int limit)
方法來(lái)設(shè)置預(yù)加載頁(yè)面的數(shù)量。
void setOffscreenPageLimt(int limit)
- 官方文檔描述該方法將會(huì)設(shè)置當(dāng)前頁(yè)面的兩邊各自預(yù)加載的數(shù)量城丧;并且超出這個(gè)數(shù)量的頁(yè)面將會(huì)被重新創(chuàng)建,最終創(chuàng)建的數(shù)量為
2*limit+1
延曙; - 該方法是一個(gè)可優(yōu)化的項(xiàng);如果我們提前知道展示的 pager 的數(shù)量亡哄,并且在 Pager 中加入了懶加載機(jī)制枝缔,調(diào)整這個(gè)設(shè)置保證了分頁(yè)動(dòng)畫(huà)和交互的流暢。如果我們要展示的頁(yè)面只有3-4 頁(yè)蚊惯,我們可以一次性將他們都緩存愿卸,這樣當(dāng)用戶來(lái)回滑動(dòng)的時(shí)候,布局的時(shí)間將會(huì)大大減少截型;
- 如果頁(yè)面布局比較復(fù)雜趴荸,將
limit
的值盡量設(shè)低;默認(rèn)值為1
, 即便我們將 limit的值設(shè)為0 宦焦,它也會(huì)被賦為 1发钝,查看源碼可知;
但是如果我們的頁(yè)面有大量的網(wǎng)絡(luò)請(qǐng)求波闹,特別是預(yù)加載多個(gè)頁(yè)面的情況下酝豪,就會(huì)產(chǎn)生問(wèn)題: - 并發(fā)請(qǐng)求造成堵塞,在網(wǎng)絡(luò)不良的情況下精堕,無(wú)限loading.....
- 一般來(lái)說(shuō)一個(gè)網(wǎng)絡(luò)請(qǐng)求都會(huì)用使用到一個(gè)異步線程孵淘,大量的線程創(chuàng)建、運(yùn)行歹篓、銷毀又造成了系統(tǒng)資源的浪費(fèi)瘫证;
因此在預(yù)加載的過(guò)程中 揉阎,最好先初始化 View,當(dāng)滑動(dòng)到對(duì)應(yīng)的頁(yè)面在執(zhí)行網(wǎng)絡(luò)請(qǐng)求布局;為了實(shí)現(xiàn)上述的需求痛悯,需要借用到 Fragment 的 setUserVisibleHint(boolean isVisibleToUser)
void setUserVisibleHint(boolean isVisibleToUser)
- 告訴系統(tǒng)當(dāng)前 Fragment 是否對(duì)用戶可見(jiàn)余黎,默認(rèn)值為 true , 并且在 Fragment 生命周期內(nèi)都不會(huì)改變重窟;
- 當(dāng)Fragment 不可見(jiàn)時(shí)载萌,應(yīng)用程序可能將該值設(shè)置為 false。系統(tǒng)可以用它來(lái)優(yōu)化操作巡扇;
- 該方法優(yōu)先Fragment 的生命周期調(diào)用扭仁;而且對(duì)生命周期方法的調(diào)用不會(huì)產(chǎn)生影響;
下面是實(shí)現(xiàn)懶加載的基類 BaseFragment
public abstract class BaseFragment extends Fragment {
View view;
protected boolean isPrepared = false;//布局是否加載完畢
protected boolean isVisible = false;//Fragment是否可見(jiàn)
protected boolean isDataInitd = false;
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
System.out.println(this.getClass().getName()+"---isVisibleToUser "+isVisibleToUser);
if(getUserVisibleHint()) {
System.out.println(this.getClass().getName()+"---onVisible");
isVisible =true;
onVisible();
} else {
System.out.println(this.getClass().getName()+"---onInvisible");
isVisible = false;
onInvisible();
}
}
private void onInvisible() {
}
private void onVisible() {
lazyLoad();
}
protected abstract void getData();
protected void lazyLoad() {
System.out.println(this.getClass().getName()+"---lazyLoad() ");
System.out.println(this.getClass().getName()+"---isPrepared " +isPrepared);
System.out.println(this.getClass().getName()+"---isVisible " +isVisible);
System.out.println(this.getClass().getName()+"---isDataInited " +isDataInitd);
if(!isPrepared || !isVisible || isDataInitd) {
System.out.println(this.getClass().getName()+"---我沒(méi)準(zhǔn)備好");
return;
} else {
isDataInitd = true;
System.out.println(this.getClass().getName()+"---執(zhí)行網(wǎng)絡(luò)請(qǐng)求");
getData();
}
}
}
下面是繼承自BaseFragment 的 AFragment;
public class AFramgent extends BaseFragment {
View view;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
super.onCreateView(inflater,container,savedInstanceState);
if(view == null) {
view = inflater.inflate(R.layout.a_layout,container,false);
isPrepared = true;
lazyLoad();//第一個(gè)可見(jiàn)Fragment 需要調(diào)用LazyLoad();其他不用厅翔;
}
return view;
}
@Override
protected void getData() {
System.out.println(this.getClass().getName()+"---getData " );
}
}
使用過(guò)程中乖坠,由于 setUserVisibleHint() 要先于Fragment 的生命周期方法執(zhí)行,所以要對(duì)第一個(gè)可見(jiàn)Fragment 做特殊處理刀闷,它的網(wǎng)絡(luò)請(qǐng)求發(fā)生在 OnCreateView ()的 LazyLoad() 中熊泵,而其他的 Fragment 網(wǎng)絡(luò)請(qǐng)求發(fā)生在調(diào)用setUserVisibleHint()中;具體調(diào)用如下