轉載請標明出處:juejin.im/post/5a30c5… ,謝謝。html
最近在開發過程當中遇到了若干問題,好比android
在Activity中這些能夠很簡單的達到目的,可是若是頁面中有Fragment,那就沒法像Activity那樣簡單的實現,下面針對Fragment不一樣的使用方法進行分析。bash
這種狀況是最簡單的,也就是在Activity使用XML引入,或者使用FragmentManager 的addFragment或者replaceFrament 動態載入。在這種狀況下,只要監聽Fragment的onResume和onPause方法就可以判斷其顯隱。在onResume和onPause中間是對用戶可見的。app
@Override
public void onResume() {
super.onResume();
// TODO now it's visible to user } @Override public void onPause() { super.onPause(); // TODO now it's invisible to user
}
複製代碼
FragmentManager除了addFragment和replaceFragment以外還有showFragment和hideFragment來作Fragment的顯隱,這樣能夠提生頁面切換的速度,是一種用空間換時間的方式。可是這樣使用的Fragment在被hide的時候是不會調用onPause方法的。由於它只是在屏幕中不可見了,可是沒有Pause。這時候咱們須要監聽onHiddenChanged方法。ide
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
if (!hidden) {
// TODO now it's visible to user } else { // TODO now it's invisible to user
}
}
複製代碼
如今不少app都會作tab頁,而tab頁基本都是經過android自帶的ViewPager實現的。ViewPager有這樣一個特色,當滑到某一個Tab時,它會同時加載這個tab的左右兩個tab頁,好比我從1頁面切換到了2頁面,那麼3頁面的onResume也被調用了,可是3頁面其實對用戶是不可見的。這時候咱們就須要監聽setUserVisibleHint來判斷到底對用戶是否可見。佈局
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
// TODO now it's visible to user } else { // TODO now it's invisible to user
}
}
複製代碼
在如下幾種操做狀況下:post
只要用戶進行了以上操做,那麼上述列出的全部使用方法中,只要是處於同一個Activity中的Fragment,那麼無論是否顯示,都會且只會調用onResume或onPause方法。ui
在一個Activity中分別有Fragment A、B,其中在Fragment A中內嵌了Fragment a、b。this
正是由於上述問題的存在,因此須要onHiddenChanged、setUserVisibleHint、onResume、onPause四個方法相互結合一塊兒來判斷。spa
public abstract class BaseFrameFragment extends Fragment {
public BaseFrameActivity activity;
private boolean isFirstCreate;// 是不是第一次建立
private boolean isVisibleToUser;// 當前可見狀態
private boolean isLastVisibleToUser;// 最後一次可見狀態(onPause前的最後一次狀態)
@Override
public void onAttach(Context context) {
super.onAttach(context);
LogUtil.i("onAttach:" + getFragmentName());
FragmentActivity activity = getActivity();
if (activity instanceof BaseFrameActivity) {
this.activity = (BaseFrameActivity) activity;
} else {
throw new IllegalArgumentException("Activity 必須繼承 BaseFrameActivity");
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
LogUtil.i("onCreateView:" + getFragmentName());
View layout_root = View.inflate(activity, getContentViewResourceId(), null);
initData(getArguments());
initView(layout_root);
loadData();
setListener();
isFirstCreate = true;
return layout_root;
}
/**
* 使用showFragment和hideFragment來作Fragment的顯隱時判斷Fragment是否可見
*
* @param hidden 是否隱藏
*/
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
LogUtil.i("onHiddenChanged:" + getFragmentName() + " " + hidden);
isLastVisibleToUser = !hidden;
onVisibleToUser(isLastVisibleToUser);
setChildVisibleToUser(isLastVisibleToUser);
}
/**
* 使用ViewPager來作Fragment的顯隱時判斷Fragment是否可見
*
* @param isVisibleToUser 是否可見
*/
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (activity == null) {
LogUtil.i("setUserVisibleHint:" + isVisibleToUser);
return;
}
LogUtil.i("setUserVisibleHint:" + getFragmentName() + " " + isVisibleToUser);
isLastVisibleToUser = isVisibleToUser;
onVisibleToUser(isLastVisibleToUser);
setChildVisibleToUser(isLastVisibleToUser);
}
/**
* 在Activity使用XML引入,或者使用FragmentManager 的addFragment或者replaceFragment 動態載入時判斷Fragment是否可見
* startActivity切換頁面或者Home鍵切入後臺後回到原頁面也會調用此方法
*/
@Override
public void onResume() {
super.onResume();
LogUtil.i("onResume:" + getFragmentName());
// 第一次建立且顯示給用戶(ViewPager) 或 回到原頁面前可見狀態且ParentFragment isLastVisibleToUser狀態
if ((isFirstCreate && getUserVisibleHint()) || (isLastVisibleToUser && getParentFragmentLastVisibleToUser())) {
onVisibleToUser(true);
}
}
/**
* 在Activity使用XML引入,或者使用FragmentManager 的addFragment或者replaceFragment 動態載入時判斷Fragment是否可見
* startActivity切換頁面或者Home鍵切入後臺也會調用此方法
*/
@Override
public void onPause() {
super.onPause();
LogUtil.i("onPause:" + getFragmentName());
if (isLastVisibleToUser) {
onVisibleToUser(false);
}
}
/**
* 獲取ParentFragment isLastVisibleToUser狀態(沒有則爲true)
*
* @return ParentFragment isLastVisibleToUser
*/
private boolean getParentFragmentLastVisibleToUser() {
Fragment parentFragment = getParentFragment();
if (parentFragment != null) {
if (parentFragment instanceof BaseFrameFragment) {
BaseFrameFragment frameFragment = (BaseFrameFragment) parentFragment;
return frameFragment.isLastVisibleToUser;
}
}
return true;
}
/**
* 設置子Fragment顯示狀態
*
* @param isVisibleToUser isVisibleToUser
*/
private void setChildVisibleToUser(boolean isVisibleToUser) {
List<Fragment> fragmentList = getChildFragmentManager().getFragments();
if (!BaseUtils.isEmptyList(fragmentList)) {
for (Fragment fragment : fragmentList) {
if (fragment instanceof BaseFrameFragment) {
BaseFrameFragment frameFragment = (BaseFrameFragment) fragment;
if (frameFragment.isLastVisibleToUser) {
frameFragment.onVisibleToUser(isVisibleToUser);
}
}
}
}
}
public abstract String getFragmentName();
/**
* 獲取根佈局ResourceId
*
* @return 根佈局ResourceId
*/
public abstract int getContentViewResourceId();
/**
* 初始化數據,主要包括拆包從activity傳遞過來的參數,適配器初始化,集合初始化等,不可進行view的操做
*
* @param arguments 接收到的從其餘地方傳遞過來的參數
*/
public abstract void initData(Bundle arguments);
/**
* 初始化View
*
* @param layout_root Fragment View
*/
public abstract void initView(View layout_root);
/**
* 加載數據,在onCreateView方法中調用能夠直接理解爲加載數據,方法中能夠進行view的操做
*/
public abstract void loadData();
/**
* 設置監聽
*/
public abstract void setListener();
/**
* 對用戶可見/不可見時執行的操做(相似Activity的onResume/onPause方法)
*
* @param isVisibleToUser 是否對用戶顯示可見
*/
public void onVisibleToUser(boolean isVisibleToUser) {
if (this.isVisibleToUser == isVisibleToUser) {
return;
}
LogUtil.i("onVisibleToUser:" + getFragmentName() + " " + isVisibleToUser);
this.isVisibleToUser = isVisibleToUser;
isFirstCreate = false;
if (isVisibleToUser) {
isLastVisibleToUser = true;
}
}
}
複製代碼
public class A_TempFragment extends BaseFrameFragment {
@Override
public String getFragmentName() {
return getString(R.string.app_name);
}
@Override
public int getContentViewResourceId() {
return R.layout.activity_base;
}
@Override
public void initData(Bundle arguments) {
}
@Override
public void initView(View layout_root) {
ButterKnife.bind(this, layout_root);
}
@Override
public void loadData() {
}
@Override
public void setListener() {
}
@Override
public void onVisibleToUser(boolean isVisibleToUser) {
super.onVisibleToUser(isVisibleToUser);
if (isVisibleToUser) {
// TODO now it's visible to user } else { // TODO now it's invisible to user
}
}
}
複製代碼
目前在Activity嵌入Fragment,Fragment內嵌ViewPager+Fragment使用中,一切正常 歡迎一塊兒討論