วงจรชีวิตของแฟรกเมนต์ - เมธอดใดถูกเรียกเมื่อแสดง / ซ่อน


99

ฉันใช้วิธีการต่อไปนี้เพื่อสลับระหว่าง Fragments (ใน 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()
บางคน

คำตอบ:


122

คล้ายกับวงจรชีวิตของกิจกรรม Android เรียกใช้onStart ()เมื่อส่วนย่อยปรากฏขึ้น onStop()โดยปกติจะเรียกเมื่อส่วนที่มองไม่เห็น แต่สามารถเรียกได้ในภายหลัง

ขึ้นอยู่กับเลย์เอาต์ของคุณที่ Android สามารถโทรonStart()ได้แม้ว่า Fragment ของคุณจะยังมองไม่เห็น แต่มันเป็นของคอนเทนเนอร์หลักที่มองเห็นได้ ตัวอย่างเช่นสิ่งนี้ถูกต้องandroid.support.v4.view.ViewPagerซึ่งคุณต้องแทนที่Fragment.setUserVisibleHint()วิธีการ ไม่ว่าในกรณีใดหากคุณจำเป็นต้องลงทะเบียน / ยกเลิกการลงทะเบียน BroadcastReceivers หรือผู้ฟังอื่น ๆ คุณสามารถใช้onStart()และonStop()วิธีการได้อย่างปลอดภัยเพราะจะถูกเรียกใช้เสมอ

หมายเหตุ:คอนเทนเนอร์แฟรกเมนต์บางส่วนสามารถทำให้ส่วนที่มองไม่เห็นเริ่มทำงานได้ เพื่อจัดการกับสถานการณ์นี้คุณสามารถลบล้างFragment.onHiddenChanged(boolean hidden)ได้ ตามเอกสารประกอบชิ้นส่วนจะต้องเริ่มต้นและมองเห็นได้ (ไม่ซ่อน)เพื่อให้ผู้ใช้มองเห็นได้

อัปเดต:หากคุณใช้android.support.v4.widget.DrawerLayoutชิ้นส่วนด้านล่างลิ้นชักจะยังคงเริ่มทำงานและมองเห็นได้แม้ลิ้นชักจะเปิด ในกรณีนี้คุณต้องใช้DrawerLayout.setDrawerListener()และรับฟังonDrawerClosed()และonDrawerOpened()โทรกลับ


14
onStopและonPauseจะไม่ถูกเรียกเมื่อส่วนที่มองไม่เห็นโดยใช้ธุรกรรม อย่างไรก็ตามonHiddenChangedเรียกว่าเป็นคำตอบ s1rius ที่แนะนำ
Yoann Hercouet

สิ่งนี้ใช้ไม่ได้ใน NavigationDrawer onHiddenChanged ไม่ถูกเรียกบน v4 / v11 support lib onStart และ onResume จะไม่ถูกเรียกทุกครั้งเมื่อเค้าโครงลิ้นชักเปิดขึ้น
drdrej

@drdrej ปัญหาคือลิ้นชักไม่ซ่อนส่วนด้านล่างอย่างสมบูรณ์ หากคุณใช้ DrawerLayout จากไลบรารีสนับสนุนคุณจำเป็นต้องใช้ DrawerListener
sergej shafarenka

70

ฉัน @ แทนที่วิธีนี้และแก้ไขปัญหาของฉัน:

@Override
public void onHiddenChanged(boolean hidden) {
    super.onHiddenChanged(hidden);
    if (hidden) {
        //do when hidden
    } else {
       //do when show
    }
}

1
พยายามแก้ไขไม่ได้ แต่ใช้setUserVisibleHintตามที่แสดงในstackoverflow.com/a/18375436/1815624 ได้ผล
CrandellWS

36

แน่นอนคุณสามารถ @Override วิธีการต่อไปนี้:

@Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isVisibleToUser) {
            // Do your Work
        } else {
            // Do your Work
        }
    }

และสามารถทราบได้อย่างง่ายดายว่าชิ้นส่วนนั้นสามารถมองเห็นได้โดยผู้ใช้หรือไม่โดยโทรgetUserVisibleHint()
ARiF

2
setUserVisibleHint ทำงานร่วมกับเพจเจอร์มุมมอง แต่ไม่ใช่กับแฟรกเมนต์คอนเทนเนอร์ปกติ
MikeL

ขอบคุณสิ่งนี้ช่วยแก้ปัญหาของฉัน :)
RAJESH KUMAR ARUMUGAM

สิ่งนี้ใช้ได้ผลกับฉันใน ViewPager onHiddenChanged ไม่ทำงาน
live-love

แก้ปัญหาของฉัน!
Jad Chahine

3

แฟรกเมนต์ในมุมมองพฤติกรรมเพจเจอร์แตกต่างกับแฟรกเมนต์คอนเทนเนอร์ปกติ

ลองใช้รหัสนี้:

    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;
    }

2

ลองใช้รหัสนี้:

@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
}

2

คุณสามารถใช้ '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 () ไม่ได้ถูกเรียกด้วยส่วนของฉัน
matdev

1

ลองใช้สิ่งนี้ใน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ทำงานได้สมบูรณ์แบบสำหรับฉัน!
bobby

1

อีกวิธีหนึ่งในการเรียกเมธอด Fragment เมื่อมองเห็น Fragment และคุณใช้ viewpager ในกิจกรรม

// ก่อนอื่นคุณสร้างอินเทอร์เฟซ

public interface ShowFragmentVisible{
      public void showFragment();}

// หลังจากนั้นอินเทอร์เฟซนี้จะใช้งานภายใน Fragment เช่นนั้น

      public class MyFragment extends Fragment implements 
         ShowFragmentVisible {
            @Override
public void showFragment() {
}

// ไปที่กิจกรรมของคุณจากนั้นสร้างวัตถุของอินเทอร์เฟซและเรียกใช้เมื่อ 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

0

setUserVisibleHintโทรมาก่อนonCreateView. และคุณไม่สามารถอัปเดต View ภายใน setUserVisibleHint ที่ฉันใช้

public void setMenuVisibility(final boolean visible)

สำหรับการมองเห็นและ onHiddenChanged () ไม่ได้โทรมาเป็นครั้งแรก มันเรียกเมื่อสถานะที่ซ่อนอยู่เปลี่ยนไป เพราะกfragment is visible by default. เพื่อให้บรรลุวิธีนี้เป็นครั้งแรกที่คุณต้องเรียกmFragmentTransaction.hide(oldFragment)มันจึงจะได้ผล

บันทึก

หากคุณต้องการใช้คำใบ้ setUserVisible และอัปเดต View ใช้วิธีนี้


0

แน่นอนว่าคุณสามารถลบล้างได้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()วิธีการเสมอ


0

แค่นี้ก็ใช้ได้แล้ว !! และ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()มา

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.