두 장면에서 Fragment 게으름뱅이 로드를 해냈어요.

16742 단어 android
전언
게으름뱅이에 대한 나의 정의는 데이터의 마운트는 페이지가 사용자에게 보일 때까지 기다려야 한다. 그렇지 않으면 사용자의 데이터를 낭비할 것이다.인터넷에서 게으름뱅이를 실현하는 방안은 매우 많지만 대부분은 내가 다음에 말한 장면 1의 게으름뱅이를 해결했고 본고는 장면 2의 게으름뱅이 방식을 해결했다.
아래의 분석을 보지 않으려면 이 클래스를 프로젝트에 직접 가져오려면 게으른 Fragment가 이 클래스를 계승하고 해당하는 방법을 다시 쓰면 됩니다: 전송문.
장면 1: Viewpager + Tablayout + Fragment
뭐?Viewpager를 사용할 줄 모르니 이 입문 시리즈를 보십시오: ViewPager 상해 (1) - 기본 입문입니다.
장면1은 많은 사람들이 겪었던 상황일 것이다. 인터페이스는 전체적으로 Viewpager+Tablayout+Fragment 조합을 사용하고 좌우로 인터페이스를 움직여서 사용자에게 데이터를 보여주고 다음 페이지로 미끄러질 때 Fragment는 데이터가 있다. 그러나 이럴 때 나는 데이터가 있는 것이 아니라 데이터를 불러오기를 원한다.특히 Viewpager의 어댑터가 FragmentPagerAdapter를 사용할 때 이 어댑터는 인접한 Fragment 페이지를 미리 불러오기 때문에 이 미리 불러오는 수량은 다음과 같이 설정할 수 있습니다.
viewPager.setOffscreenPageLimit(0);

그러면 위의 코드는 미리 불러오는 수량을 0으로 설정하지 않았습니까?이렇게 하면 Fragment가 미리 불러오지 않는다. 이렇게 생각하면 너무 순진하다. set OffscreenPage Limit의 원본 코드를 보면 입력한 수치가 1보다 적으면 ViewPager는 미리 불러오는 수량을 기본값으로 설정하고 기본값은 1이다. 따라서 0을 불러와도 ViewPager는 현재 페이지의 좌우 두 개의 Fragment 페이지를 미리 불러온다.
로딩 게으름 원리
그럼 어떻게 해결할까요?이 때 Fragment의 함수 중 하나를 알아야 합니다: setUserVisibleHint (boolean isVisibleTouser):
setUserVisibleHint 메서드는 Fragment의 콜백 함수입니다.현재 Fragment가 사용자에게 보일 때 setUserVisibleHint() 리셋, 그 중에서 매개 변수인 isVisibleTouser=true, 현재 Fragment가 보이지 않거나 실례화될 때 setUserVisibleHint() 리셋, 그 중에서 매개 변수인 isVisibleTouser=false가 리셋됩니다.
Fragment 라이프 사이클에서 이 메서드가 호출되는 시기를 살펴보겠습니다.
  • 1. Fragment가 실례화될 때 Fragment가 ViewPager 어댑터에 불러오고 setUserVisibleHint()->onAttach()->onCreate()->onCreateView()->onViewCreated()->onActivityCreate()->onStart()->onResume().setUserVisibleHint()의 매개변수는 false입니다.
  • 2. Fragmente가 보일 때, 즉 ViewPager가 현재 페이지로 미끄러질 때: setUserVisibleHint().setUserVisibleHint 방법만 호출됩니다. 미리 불러왔기 때문에 Fragment는 이전 생명주기가 onResume () 에 도달했습니다.setUserVisibleHint()의 매개변수가 true입니다.
  • 3. Fragment에서 볼 수 있는 것에서 보이지 않는 것으로 바뀐다. 즉, ViewPager가 현재 페이지에서 다른 페이지로 미끄러진다. setUserVisibleHint().현재 페이지의 미리 불러오는 과정을 유지해야 하기 때문에 setUserVisibleHint () 의 매개 변수가false입니다.
  • 4, 클릭하여 TabLayout에서 미리 불러오지 않은 페이지로 이동합니다. 이때 생명주기의 리셋 과정: setUserVisibleHint()-> setUserVisibleHint()-> onAttach()-> onCreateView()-> onViewCreated()-> onActivityCreate()-> onStart()-> onResume().setUserVisibleHint () 를 두 번 리셋했습니다. 한 번은 초기화할 때false이고, 한 번은 보일 때true입니다.

  • 이 때 setUserVisibleHint의 호출 시기는 항상 초기화할 때 호출되고, 보일 때 호출되며, 보일 때 호출되며, 보이지 않을 때 호출됩니다.
    생각을 실현하다
    다음은 장경1의 게으른 로드 실현 방향을 설명한다. 우리는 보통Fragment의onActivityCreated에 데이터를 로드한다. 이때 우리는 이때Fragment가 사용자에게 보이는지 판단하고fragment를 호출할 수 있다.getUserVisibleHint () 는 isVisibleToUser의 값을 얻을 수 있습니다.true로 표시되면 데이터를 불러오고, 보이지 않으면 데이터를 불러오지 않습니다. 코드는 다음과 같습니다.
      @Override
        public void onActivityCreated(@Nullable Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            if(isFragmentVisible(this) && this.isAdded()){
                if (this.getParentFragment() == null || isFragmentVisible(this.getParentFragment())) {
                    onLazyLoadData();
                    isLoadData = true;
                    //...
                }
            }
        }
    

    Fragment가 사용자에게 isFragmentVisible 방법에 봉인되어 있는지 확인하십시오.onLazyLoadData () 는 하위 클래스에서 다시 쓰는 방법으로 데이터를 불러옵니다. 데이터를 불러온 후에 isLoadData를true로 설정하여 데이터를 불러왔음을 표시합니다.
    위에서 Fragment가 보이지 않을 때 데이터를 불러오지 않는 것을 제어했고 이때Fragment의 생명주기도 onResume에 이르렀다. 그러면 내가 이 Fragment에 미끄러질 때 setUserVisibleHint 방법만 호출할 것이다. 그러면 setUserVisibleHint 방법에 수증을 불러와야 한다. 코드는 다음과 같다.
       @Override
        public void setUserVisibleHint(boolean isVisibleToUser) {
            super.setUserVisibleHint(isVisibleToUser);
            if(isFragmentVisible(this) && !isLoadData && isViewCreated && this.isAdded()){
                onLazyLoadData();
                isLoadData = true;
            }
        }
    

    isViewCreated 필드는 레이아웃이 초기화되었는지 여부를 나타냅니다. 이것은 onViewCreated 방법에서 다음과 같이 true로 지정됩니다.
     @Override
        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
            isViewCreated = true;
        }
    
    

    onViewCreated 방법의 리셋은 onCreateView 방법 다음에 onViewCreated 방법을 호출할 때 Fragment의 View 레이아웃이 만들어졌을 것입니다.
    setUserVisibleHint 방법으로 다시 돌아갑니다.if에서 현재 Fragment에서 볼 수 있고, 데이터를 불러오지 않았으며, 레이아웃이 만들어진 등 조건이 충족된 후에야 데이터를 불러오고, isLoadData의 값을true로 부여합니다.
    응용 예
    프로젝트에서 사용하는 경우는 다음과 같습니다.
    이 Fragment를 미끄러뜨릴 때 데이터를 불러오는 것을 볼 수 있습니다.
    시나리오 2: Fragment Manager + FragmentTransaction + Fragment
    이 장면은 몇 개의 Fragment를 Fragment Transaction의dd 방법으로dd를 Fragment Manager에 넣고 Fragment를 전환할 때 Fragment Transaction의hide와 show 방법을 결합하여 사용한다. 위챗의 메인 인터페이스와 유사하고 밑에 tab이 하나 있고 tab을 클릭한 다음tab을 눌러서 페이지를 전환한다.
    Fragment가dd에 의해 관리자에 들어갔을 때Fragment의 생명주기는onResume에 실행되었기 때문에 후속적인 Hide와 show 방법에서Fragment를 전환할 때Fragment에 데이터가 있습니다. 제 프로젝트에서 제가 원하는 효과는 이tab에 눌렀을 때 이tab가Fragment에 대한 데이터를 불러오는 것입니다. 그래서 저는 이런 상황에 대해 게으름을 피웠습니다.
    로딩 게으름 원리
    그럼 어떻게 이루어져야 하나요?장면 2를 그대로 옮기는 실현 방식은?아쉽지만, 안 됩니다. 왜냐하면 이 경우 setUserVisibleHint 방법이 호출되지 않기 때문입니다.이때 우리는 또 하나의 방법 onHiddenChanged(boolean Hidden)를 다시 알게 되었다.
    onHiddenChanged 방법은 Fragment의 숨겨진 상태 변화가 호출되었을 때, Fragment가 숨겨지지 않았을 때 show 방법을 호출하고, 현재 onHiddenChanged 리셋을 사용합니다. 그 중에서 매개 변수는 hidde=false이고, Fragment가 숨겨졌을 때 hide 방법을 호출하고, onHiddenChanged () 리셋을 사용합니다. 그 중에서 매개 변수는 hidde=true입니다.또 하나 주의해야 할 것은hide와 show를 사용할 때fragment의 모든 생명주기 방법은 온HiddenChanged () 를 제외하고는 호출되지 않는다는 것이다.
    Fragment 라이프 사이클에서 이 메서드가 호출되는 시기를 살펴보겠습니다.
  • 1. Fragment가dd에 의해 관리자에 들어갔을 때:onAttach()-> onCreate()-> onCreateView()-> onViewCreated()-> onActivityCreate()-> onHiddenChanged()-> onStart()-> onResume().이제 onHiddenChanged()의 매개변수가 false입니다.
  • 2. 하이드 방법으로 Fragment을 숨길 때: onHiddenChanged () 는 onHiddenChanged 방법만 호출합니다. 이 때 setUserVisibleHint () 의 매개 변수는true입니다.
  • 3. show 방법으로 Fragment을 표시할 때: onHiddenChanged () 는 onHiddenChanged 방법만 호출합니다. 이 때 setUserVisibleHint () 의 매개 변수는false입니다.

  • 이 때 onHiddenChanged의 호출 시기는 항상 초기화할 때 호출되고, hide일 때 호출되고, show일 때 호출되는 것을 볼 수 있습니다.
    생각을 실현하다
    장면 2는 setUserVisibleHint 방법에서 문장을 만들고 이번에는 onHiddenChanged 방법에서 문장을 만든다. 다음과 같다.
      @Override
        public void onHiddenChanged(boolean hidden) {
            super.onHiddenChanged(hidden);
            //1、onHiddenChanged   Resumed  ,      fragment add,    resumed
            if(!hidden && !this.isResumed())
                return;
            //2、  hide show ,fragment              ,  onHiddenChanged()
            if(!hidden && isFirstVisible && this.isAdded()){
                onLazyLoadData();
                isFirstVisible = false;
            }
        }
    

    먼저 주석 1을 보십시오. 왜냐하면dd가 있을 때 onHiddenChanged가 onResumed를 호출하기 전에 onResume 방법을 실행하지 않았기 때문에 사용자는 이 Fragment를 볼 수 없습니다. 만약에 데이터를 불러오면 소용이 없습니다. 이것은 사용자가 이Fragmen을 보았을 때 이미 데이터를 실행한 것입니다. 만약에 여기에 판단을 추가하려면 Fragment이 Resume가 없으면그냥 리턴, 조작 안 해.
    다음은 주석2를 보고 주석2를 실행하면 Fragment가 보일 때 Hidden 필드를 통해 로드를 늦출 수 있음을 나타낸다. Hidden은false로 show 방법을 호출했고 isFirstVisible 제어를 통해 한 번만 로드할 수 있다. 왜 isFirstVisible를 사용해야 하는가. onActivityCreate 방법에서 데이터를 로드한 적이 있기 때문에 로드한 적이 있으면 다시 로드하지 않아도 된다.이 필드는 onActivityCreate에서 다음과 같이 true로 지정됩니다.
      @Override
        public void onActivityCreated(@Nullable Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            if(isFragmentVisible(this) && this.isAdded()){
                if (this.getParentFragment() == null || isFragmentVisible(this.getParentFragment())) {
                    onLazyLoadData();
                    isLoadData = true;
                    if(isFirstVisible)
                        isFirstVisible = false;
                }
            }
        }
    

    응용 예
    프로젝트에서 사용하는 경우는 다음과 같습니다.
    이 테이블을 눌렀을 때 대응하는 Fragment에서 데이터를 불러오는 것을 볼 수 있습니다.
    결어
    이상은 바로 저의 게으름뱅이 로드 과정입니다. 지금도 일부 Fragment 라이브러리에서 이 효과를 실현할 수 있지만 그 원리도 이렇습니다. 우리는 그 이유를 알아야 합니다. 이 게으름뱅이 로드 클래스는 장면 1과 장면 2를 통합하고 간단한 몇 마디의 코드만 계승하면 두 가지 장면에서 사용할 수 있습니다.
    참고 자료:
    Fragment 지식 정리(3)
    FragmentPagerAdapter와 FragmentStatePagerAdapter의 차이점

    좋은 웹페이지 즐겨찾기