片段生命周期 - 在显示/隐藏时调用哪个方法?
Posted
技术标签:
【中文标题】片段生命周期 - 在显示/隐藏时调用哪个方法?【英文标题】:Fragment lifecycle - which method is called upon show / hide? 【发布时间】:2013-08-24 21:06:17 【问题描述】:我正在使用以下方法通过显示/隐藏片段(在我的 NavigationDrawer 中)在片段之间进行切换。
protected void showFragment(int container, Fragment fragment, String tag, String lastTag, boolean addToBackStack )
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
if ( lastTag != null && !lastTag.equals(""))
Fragment lastFragment = fragmentManager.findFragmentByTag( lastTag );
if ( lastFragment != null )
transaction.hide( lastFragment );
if ( fragment.isAdded() )
transaction.show( fragment );
else
transaction.add( container, fragment, tag );
if ( addToBackStack )
transaction.addToBackStack( tag );
transaction.commit();
// set the active tag
activeFragTag = tag;
我不清楚的是当我显示或隐藏它时调用 Fragments 生命周期的哪个方法?(因为没有诸如 onShow() 或 onHide() 之类的方法,我不太确定用什么)。我想在显示和隐藏某个 Fragment 时执行特定操作。
【问题讨论】:
当你调用 Fragment.show() 之后,片段会触发onCreate()
,然后是onCreateDialog()
,然后是onCreateView()
【参考方案1】:
类似于 Activity 生命周期,当片段可见时,android 会调用 onStart()。 onStop()
通常在片段不可见时调用,但也可以稍后调用。
根据您的布局,即使您的 Fragment 尚不可见,但它属于可见的父容器,Android 也可以调用 onStart()
。例如,这对 android.support.v4.view.ViewPager
有效,它要求您覆盖 Fragment.setUserVisibleHint()
方法。在任何情况下,如果您需要注册/取消注册 BroadcastReceivers 或其他侦听器,您可以安全地使用 onStart()
和 onStop()
方法,因为它们将始终被调用。
注意:一些片段容器可以保持不可见片段的启动。要处理这种情况,您可以覆盖Fragment.onHiddenChanged(boolean hidden)
。根据documentation,片段必须已启动且可见(不隐藏),才能对用户可见。
更新:如果您使用android.support.v4.widget.DrawerLayout
,那么即使抽屉打开,抽屉下方的片段也会保持启动并可见。在这种情况下,您需要使用DrawerLayout.setDrawerListener()
并监听onDrawerClosed()
和onDrawerOpened()
回调。
【讨论】:
onStop
和 onPause
当片段使用事务变得不可见时不会被调用。不过 onHiddenChanged
被称为建议 s1rius 答案
这在 NavigationDrawer 中不起作用。在 v4/v11 支持库上不调用 onHiddenChanged。当抽屉布局打开时,onStart 和 onResume 也不会每次都被调用。
@drdrej 问题是抽屉没有完全隐藏下面的片段。如果使用支持库中的 DrawerLayout,则需要使用 DrawerListener。
如前所述,这个答案完全不正确。【参考方案2】:
我@Override 这个方法并解决我的问题:
@Override
public void onHiddenChanged(boolean hidden)
super.onHiddenChanged(hidden);
if (hidden)
//do when hidden
else
//do when show
【讨论】:
尝试不解决但使用setUserVisibleHint
如***.com/a/18375436/1815624 所示工作【参考方案3】:
当然你可以@Override下面的方法来做到这一点:
@Override
public void setUserVisibleHint(boolean isVisibleToUser)
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser)
// Do your Work
else
// Do your Work
【讨论】:
通过调用getUserVisibleHint()
可以很容易地知道片段是否对用户可见
setUserVisibleHint 适用于视图寻呼机,但不适用于常规片段容器。
谢谢这解决了我的问题:)
这在 ViewPager 上对我有用。 onHiddenChanged 不起作用。
解决了我的问题!【参考方案4】:
您可以使用“onCreateView”(或“onActivityCreated”)和“onHiddenChanged”。 首次显示使用“onCreateView”,稍后使用“onHiddenChanged”。 'setMenuVisibility' 不在事务控制上调用。
@Override
public View OnCreateView()
// fragment will show first
@Override
public void onHiddenChanged(boolean hidden)
if (!hidden)
// fragment will show
else
// fragment will hide
【讨论】:
onHiddenChanged() 没有被我的片段调用【参考方案5】:视图分页器中的片段行为与常规片段容器不同。
试试这个代码:
boolean mIsVisibleToUser;
/**
* is visible to user
*/
public void show()
//do when show
/**
* is invisible to user
*/
public void hide()
//do when gone
@Override
public void onResume()
super.onResume();
if (!mIsVisibleToUser && getUserVisibleHint())
mIsVisibleToUser = true;
show();
@Override
public void onPause()
super.onPause();
if (mIsVisibleToUser && getUserVisibleHint())
mIsVisibleToUser = false;
hide();
@Override
public void setUserVisibleHint(boolean isVisibleToUser)
super.setUserVisibleHint(isVisibleToUser);
if (isResumed())
if (mIsVisibleToUser != isVisibleToUser)
mIsVisibleToUser = isVisibleToUser;
if (isVisibleToUser) show();
else hide();
public boolean isVisibleToUser()
return mIsVisibleToUser;
【讨论】:
【参考方案6】:试试这个代码:
@Override
public void setUserVisibleHint(boolean visible)
super.setUserVisibleHint(visible);
if (visible && isResumed())
onResume();
@Override
public void onResume()
super.onResume();
if (!getUserVisibleHint())
return;
//Add your code this section
【讨论】:
【参考方案7】:只需在你的 setUserVisibleHint() 中试试这个
@Override
public void setUserVisibleHint(boolean isVisibleToUser)
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser && getView() != null)
isActive = true;
init();
else if(isVisibleToUser && getView() == null)
isActive = false;
else
isActive = true;
并在 onCreateView() 中创建此代码:
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
if(!isActive)
init();
【讨论】:
isVisibleToUser && getView() != null
非常适合我!【参考方案8】:
当片段可见并且您在活动中使用 viewpager 时调用片段方法的另一种方法。
//首先你创建一个界面
public interface ShowFragmentVisible
public void showFragment();
//然后这个接口就这样在Fragment里面实现
public class MyFragment extends Fragment implements
ShowFragmentVisible
@Override
public void showFragment()
// 现在进入你的 Activity 然后创建接口对象并在 addOnViewpagerListener 时在里面调用
ShowFragmentVisible showFragmentVisible;
@Override
public void onAttachFragment(Fragment fragment)
super.onAttachFragment(fragment);
if (fragment instanceof ShowFragmentVisible)
showFragmentVisible = (ShowFragmentVisible) fragment;
//your viewpager method
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener()
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
@Override
public void onPageSelected(int position)
if (position==0)
showFragmentVisible.showFragment();
@Override
public void onPageScrollStateChanged(int state)
);
this is another alternative,but its work for me successfully
【讨论】:
【参考方案9】:只有这对我有用! setUserVisibleHint(...)
现在已弃用(我在最后附上了文档),这意味着其他一些答案已弃用;-)
public class FragmentFirewall extends Fragment
/**
* Required cause "setMenuVisibility(...)" is not guaranteed to be,
* called after "onResume()" and/or "onCreateView(...)" method.
*/
protected void didVisibilityChange()
Activity activity = getActivity();
if (isResumed() && isMenuVisible())
// Once resumed and menu is visible,
// at last our Fragment is really visible to user.
@Override
public void onResume()
super.onResume();
didVisibilityChange();
@Override
public void setMenuVisibility(boolean visible)
super.setMenuVisibility(visible);
didVisibilityChange();
经过测试并与 NaviagationDrawer
一起使用,
isMenuVisible()
将始终返回 true
(onResume()
似乎足够了,但我们也想支持 ViewPager
)。
setUserVisibleHint
已弃用。如果重写此方法,则传入true
时实现的行为应移至Fragment.onResume()
,传入false
时实现的行为应移至Fragment.onPause()
。
【讨论】:
【参考方案10】:setUserVisibleHint
在onCreateView
之前调用。并且您无法更新我使用的 setUserVisibleHint 中的任何视图
public void setMenuVisibility(final boolean visible)
为了可见性和 onHiddenChanged() 没有第一次调用。它在隐藏状态更改时调用。因为fragment is visible by default
。为了第一次实现这个方法你必须调用mFragmentTransaction.hide(oldFragment)
然后它会起作用
注意
如果你想使用 setUserVisible 提示并更新 View Use this method
【讨论】:
【参考方案11】:当然您可以覆盖setUserVisibleHint
或setMenuVisibility
,但如果您需要访问Context
或Activity
,它们将在那里为空!
还有另一种方法onStart
,它总是有可用的上下文,但它只会在创建片段时被调用一次,如果你开始在寻呼机中的片段之间移动,你会看到它不会在第二个被调用查看和之后。
那么……现在该怎么办?
解决方法很简单,第一次访问使用onStart
,以后使用setMenuVisibility
。
您的代码可能如下所示:
片段类:
public class MyFragmentClass
private boolean isCurrentVisible = false;
...
@Override
public void onStart()
super.onStart();
if (isCurrentVisible)
doSth();
@Override
public void setMenuVisibility(boolean menuVisible)
super.setMenuVisibility(menuVisible);
this.isCurrentVisible = menuVisible;
if(menuVisible && getContext() != null)
doSth();
这样Context
将始终可用于doSth()
方法。
【讨论】:
以上是关于片段生命周期 - 在显示/隐藏时调用哪个方法?的主要内容,如果未能解决你的问题,请参考以下文章