最近實(shí)現(xiàn)了一個界面功能蚜锨,其實(shí)很簡單就是一個Tab,下面三個可滑動的view氏堤。使用TabLayout+ViewPager可以實(shí)現(xiàn)這樣的效果沙绝。一開始ViewPager中我放入的是一個view,但是功能實(shí)現(xiàn)完了之后鼠锈,感覺界面滑動不太順暢闪檬,生命周期什么的都不好控制,后來直接索性就換了Fragment 加載布局购笆。但是ViewPager有預(yù)加載機(jī)制粗悯,即是設(shè)置了預(yù)加載頁數(shù)為0,這個方法是不失效的同欠。因?yàn)樵谠摲椒ㄖ凶隽伺袛嘌辽贂虞d一頁。那么在這個activity剛創(chuàng)建的時候就變成需要初始化大量資源铺遂。所以采用懶加載的方式來處理衫哥。
重點(diǎn)Fragment里的setUserVisibleHint這個方法
官方api 介紹
Set a hint to the system about whether this fragment's UI is currently visible to the user. This hint defaults to true and is persistent across fragment instance state save and restore.
An app may set this to false to indicate that the fragment's UI is scrolled out of visibility or is otherwise not directly visible to the user. This may be used by the system to prioritize operations such as fragment lifecycle updates or loader ordering behavior.
Parameters
大概意思是這樣的:有道~~~
設(shè)置一個系統(tǒng)提示是否這個片段的UI是目前用戶可見的。這提示默認(rèn)為正確并持續(xù)在片段實(shí)例保存和恢復(fù)狀態(tài)襟锐。
應(yīng)用程序可以設(shè)置為false,以表明片段的UI是滾動的可見性或另有用戶不能直接看到撤逢。這可能是使用的系統(tǒng)優(yōu)化操作,比如片段的生命周期更新或加載程序命令的行為。
參數(shù)
isVisibleToUser真實(shí)如果這個片段的UI目前可見的用戶(默認(rèn)),如果它不是空的。
代碼 Fragment V4包下的
public class abstract BaseFragment extends Fragment {
/*
* 當(dāng)前界面是否呈現(xiàn)給用戶的狀態(tài)標(biāo)志
*/
protected boolean isVisible;
/**
* 重寫Fragment父類生命周期方法蚊荣,在onCreate之前調(diào)用該方法初狰,實(shí)現(xiàn)Fragment數(shù)據(jù)的緩加載.
* @param isVisibleToUser 當(dāng)前是否已將界面顯示給用戶的狀態(tài)
*/
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(getUserVisibleHint()) {
isVisible = true;
onVisible();
} else {
isVisible = false;
onInvisible();
}
}
/**
* 當(dāng)界面呈現(xiàn)給用戶,即設(shè)置可見時執(zhí)行妇押,進(jìn)行加載數(shù)據(jù)的方法
* 在用戶可見時加載數(shù)據(jù)跷究,而不在用戶不可見的時候加載數(shù)據(jù),是為了防止控件對象出現(xiàn)空指針異常
*/
protected void onVisible(){
setlazyLoad();
}
/**
* 當(dāng)界面還沒呈現(xiàn)給用戶敲霍,即設(shè)置不可見時執(zhí)行
*/
protected void onInvisible(){
}
/**
* 加載數(shù)據(jù)方法俊马,必須由子類實(shí)現(xiàn)。
*/
protected abstract void setlazyLoad()肩杈;
}
子類實(shí)現(xiàn)
public class OpenResultFragment extends BaseFragment {
// 標(biāo)志位柴我,標(biāo)志已經(jīng)初始化完成。
private boolean isPrepared;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(LOG_TAG, "onCreateView");
View view = inflater.inflate(R.layout.fragment_open_result, container, false);
.........XXX初始化view的各控件
isPrepared = true; // 對標(biāo)識符進(jìn)行賦值動作
lazyLoad();
return view;
}
@Override
protected void lazyLoad() {
if(!isPrepared || !isVisible) {
return;
}
//填充各控件的數(shù)據(jù)扩然,請求網(wǎng)絡(luò)數(shù)據(jù)
}
}
子類中增加了一個標(biāo)志位isPrepared艘儒,用于標(biāo)志是否初始化完成。然后在我們所需要的初始化操作完成之后調(diào)用夫偶,如上面的例子當(dāng)中界睁,在初始化view之后,設(shè)置 isPrepared為true兵拢,同時調(diào)用lazyLoad()方法翻斟。而在lazyLoad()當(dāng)中,判斷isPrepared和isVisible只要有一個不為true就不往下執(zhí)行说铃。也就是僅當(dāng)初始化完成访惜,并且可見的時候才繼續(xù)加載,這樣的避免了未初始化完成就使用而帶來的問題腻扇。
Fragment中調(diào)用getActivity為null的問題
今天在測試的時候债热,也發(fā)現(xiàn)了一個問題,F(xiàn)ragment基于Activity上幼苛,快速切換界面窒篱,或者什么情況下,會導(dǎo)致Activity銷毀舶沿,這種情況下舌剂,在Fragment中g(shù)etActivity獲取上下文,這樣后果就是應(yīng)用程序直接崩掉了暑椰,并且報空指針霍转。因?yàn)椋珹ctivity不存在了一汽,獲取一個不存在的東西避消,肯定是報error的低滩。
度娘了一把~~~~
解決方式1
查閱一下Fragment的生命周期:
在onAttach() 與 onDetach()方法之間 getActivity方法是存在,反之為null岩喷,因此恕沫,如果我正在做某些操作聯(lián)網(wǎng),在等待過程中點(diǎn)擊Back鍵返回纱意,使得這個Fragment被銷毀了婶溯,這時Fragment就會和Activity解除附著(onDetach),當(dāng)再試圖彈出Toast的時候偷霉,再次通過getActivity方法獲取上下文迄委,就報null了。
解決方式2
創(chuàng)建變量类少,保存實(shí)例叙身。
在Fragment附著在Activity上時用一個變量保存引用,即:
@Override
public void onAttach(Activity activity){
this.mContext = activity;
}
解決方式3
獲取全局上下文硫狞,因?yàn)槿稚舷挛牡氖呛蛻?yīng)用程序的生命周期一致的信轿,不必?fù)?dān)心為null
Android程序中Application、Service和Activity都實(shí)現(xiàn)了Context残吩,但只有Application才能保證在程序運(yùn)行期間一直存在并且具有唯一性财忽,因此在程序中可以使用Application來獲得Context而不用擔(dān)心空指針。