Vòng đời của mảnh - phương thức nào được gọi khi hiển thị / ẩn?


99

Tôi đang sử dụng phương pháp sau để chuyển đổi giữa các Phân đoạn (trong NavigationDrawer của tôi) bằng cách hiển thị / ẩn chúng.

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

Điều tôi không rõ là phương thức nào của vòng đời Fragment được gọi khi tôi hiển thị hoặc ẩn nó? (vì không có phương thức nào như onShow () hoặc onHide () nên tôi không chắc nên dùng gì). Tôi muốn thực hiện các hành động cụ thể khi hiển thị và ẩn một Fragment nhất định.


khi bạn gọi Fragment.show () sau đó tại một số điểm sau, trigger mảnh onCreate(), tiếp theo onCreateDialog(), tiếp theoonCreateView()
Có người Một nơi nào đó

Câu trả lời:


122

Tương tự như vòng đời hoạt động, Android gọi onStart () khi phân đoạn hiển thị. onStop()thường được gọi khi phân mảnh trở nên vô hình, nhưng nó cũng có thể được gọi sau đó.

Tùy thuộc vào bố cục của bạn, Android có thể gọi onStart()ngay cả khi Fragment của bạn chưa hiển thị, nhưng nó thuộc về vùng chứa mẹ có thể nhìn thấy. Ví dụ, điều này hợp lệ để android.support.v4.view.ViewPageryêu cầu bạn ghi đè Fragment.setUserVisibleHint()phương thức. Trong mọi trường hợp, nếu bạn cần đăng ký / hủy đăng ký BroadcastReceivers hoặc các trình nghe khác, bạn có thể sử dụng an toàn onStart()onStop()các phương thức vì chúng sẽ luôn được gọi.

Lưu ý: Một số vùng chứa phân mảnh có thể bắt đầu phân mảnh vô hình. Để xử lý tình huống này, bạn có thể ghi đè Fragment.onHiddenChanged(boolean hidden). Theo tài liệu , một phân đoạn phải được khởi động và hiển thị (không ẩn) , để người dùng nhìn thấy.

Cập nhật: Nếu bạn sử dụng android.support.v4.widget.DrawerLayoutthì một phân đoạn bên dưới ngăn vẫn bắt đầu và hiển thị ngay cả khi ngăn kéo đang mở. Trong trường hợp này, bạn cần sử dụng DrawerLayout.setDrawerListener()và nghe onDrawerClosed()onDrawerOpened()gọi lại.


14
onStoponPausekhông được gọi khi một phân mảnh trở nên vô hình bằng giao dịch. Tuy nhiên onHiddenChangedđược mệnh danh là gợi ý câu trả lời s1rius
Yoann Hercouet

Điều này không hoạt động trong NavigationDrawer. onHiddenChanged không được gọi trên lib hỗ trợ v4 / v11. onStart và onResume cũng sẽ không phải lúc nào cũng được gọi, khi bố cục ngăn kéo mở ra.
drdrej

@drdrej Vấn đề là ngăn kéo không ẩn hoàn toàn phân đoạn bên dưới. Nếu bạn sử dụng DrawerLayout từ thư viện hỗ trợ, bạn cần sử dụng DrawerListener.
sergej shafarenka

69

Tôi @ Ghi đè phương pháp này và giải quyết sự cố của mình:

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

1
Cố gắng không quyết tâm nhưng sử dụng setUserVisibleHintnhư trong stackoverflow.com/a/18375436/1815624 công trình
CrandellWS

36

tất nhiên bạn có thể @Override phương thức sau để làm như vậy:

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

Và người ta có thể dễ dàng biết nếu đoạn được hiển thị cho người sử dụng hay không bằng cách gọigetUserVisibleHint()
Arif

2
setUserVbrokenHint hoạt động với chế độ xem pager nhưng không hoạt động với vùng chứa phân mảnh thông thường.
MikeL

Nhờ giải quyết vấn đề này của tôi :)
RAJESH KUMAR Arumugam

Điều này đã làm việc cho tôi trên ViewPager. onHiddenChanged không hoạt động.
live-love

Đã giải quyết vấn đề của tôi!
Jad Chahine

3

Hành vi của máy nhắn tin phân mảnh trong chế độ xem khác với vùng chứa phân mảnh thông thường.

Hãy thử mã này:

    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

Hãy thử mã này:

@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

Bạn có thể sử dụng 'onCreateView' (hoặc 'onActivityCreate') và 'onHiddenChanged'. Sử dụng 'onCreateView' cho lần hiển thị đầu tiên và sử dụng "onHiddenChanged" cho lần sau. 'setMenuVisibility' không được gọi trong kiểm soát giao dịch.

@Override
public View OnCreateView() {
   // fragment will show first
}

@Override
public void onHiddenChanged(boolean hidden) {
    if (!hidden) {
        // fragment will show 
    }
    else {
        // fragment will hide
    }
}

onHiddenChanged () không được gọi với mảnh của tôi
matdev

1

Chỉ cần thử điều này trong setUserVosystemHint () của bạn

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

Và tạo mã này trong onCreateView () :

public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
  if(!isActive){
      init();
  }
}

isVisibleToUser && getView() != nulllàm việc hoàn hảo cho tôi!
bobby

1

Một cách khác để gọi phương thức phân mảnh khi phân mảnh có thể nhìn thấy và bạn sử dụng viewpager trong hoạt động.

// trước hết bạn tạo một giao diện

public interface ShowFragmentVisible{
      public void showFragment();}

// Sau đó giao diện này thực hiện bên trong Fragment như vậy

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

// Bây giờ chuyển sang Activity của bạn, sau đó tạo đối tượng của giao diện và gọi bên trong khi 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

setUserVisibleHintgọi trước onCreateView. và bạn không thể cập nhật bất kỳ Chế độ xem nào bên trong setUserVbrokenHint tôi sử dụng

public void setMenuVisibility(final boolean visible)

cho khả năng hiển thị và onHiddenChanged () đã không gọi lần đầu tiên . nó gọi khi trạng thái ẩn thay đổi. bởi vì a fragment is visible by default. Để đạt được phương pháp này lần đầu tiên bạn phải gọi mFragmentTransaction.hide(oldFragment)sau đó nó sẽ hoạt động

Ghi chú

nếu bạn muốn sử dụng gợi ý setUserVbroken và cập nhật Chế độ xem Sử dụng phương pháp này


0

Tất nhiên bạn có thể ghi đè setUserVisibleHinthoặc setMenuVisibilitynhưng nếu bạn cần truy cập Contexthoặc Activity, chúng sẽ vô hiệu ở đó! Có một phương pháp kháconStart luôn có sẵn ngữ cảnh, nhưng nó sẽ chỉ được gọi một lần khi tạo ra phân mảnh và nếu bạn bắt đầu di chuyển giữa các phân mảnh của mình trong một máy nhắn tin, bạn sẽ thấy rằng nó sẽ không được gọi trong chế độ xem thứ hai và sau đó .

Vậy phải làm gì bây giờ?

Cách giải quyết này khá dễ dàng, sử dụng onStartcho lần truy cập đầu tiên và setMenuVisibilitycho những lần sau. Mã của bạn có thể sẽ giống như bên dưới:

Lớp phân mảnh:

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

Cách này Contextsẽ luôn có sẵn cho doSth()phương pháp.


0

Chỉ điều này làm việc cho tôi !! và setUserVisibleHint(...)hiện không được dùng nữa (tôi đã đính kèm tài liệu ở cuối), có nghĩa là một số câu trả lời khác không được dùng nữa ;-)

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

Đã thử nghiệm và hoạt động NaviagationDrawertốt, isMenuVisible()sẽ luôn có trả lại true(và onResume()có vẻ như đủ, nhưng chúng tôi cũng muốn hỗ trợ ViewPager).

setUserVisibleHintkhông được dùng nữa. Nếu ghi đè phương thức này, hành vi được triển khai khi chuyển vào truesẽ được chuyển đến Fragment.onResume()và hành vi được thực hiện khi chuyển vào falsephải được chuyển đến Fragment.onPause().

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.