SetUserVisibleHint вызывается перед onCreateView в фрагменте

Я работаю над ViewPager и используя Fragment, там я нашел

setUserVisibleHint(), вызываемый перед onCreateView() в фрагменте

Я использую Fragment из библиотеки поддержки android.support.v4.app.Fragment

Это проблема с библиотекой?

Как я могу избавиться от него?

ИЗМЕНИТЬ

Я переопределяю setUserVisibleHint() и не вызываю super, чтобы избавиться от него.

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    //FIXED: setUserVisibleHint() called before onCreateView() in Fragment causes NullPointerException
    //super.setUserVisibleHint(isVisibleToUser);
}

Ответ 1

// create boolean for fetching data
private boolean isViewShown = false;

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (getView() != null) {
        isViewShown = true;
        // fetchdata() contains logic to show data when page is selected mostly asynctask to fill the data
        fetchData();
    } else {
        isViewShown = false;
    }
} 

Используйте переменную экземпляра isViewShown, чтобы решить, следует ли извлекать данные в onCreateView() или в setUserVisibleHint().

Ниже код содержит логику для onCreateView():

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.main_layout, container, false);

   // view initialization steps.......

   if (!isViewShown) {
        fetchData();
   } 
   // do other stuff
}

Этот код решит вашу проблему. Поскольку он решил мою проблему.:)

Этот трюк будет извлекать данные в onCreateView() для прямого перехода с одной страницы на другую, тогда как при прокрутке представления он будет извлекать данные из метода setUserVisibleHint().:)

Ответ 2

вы можете использовать эту логику, также вы можете отключить viewDidAppear в любое время, установив isVisible = false

public class MyFragment extends Fragment {
    private Boolean isStarted = false;
    private Boolean isVisible = false;

    @Override
    public void onStart() {
        super.onStart();
        isStarted = true;
        if (isVisible && isStarted){
            viewDidAppear();
        }
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        isVisible = isVisibleToUser;
        if (isStarted && isVisible) {
            viewDidAppear();
        }
    }

    public void viewDidAppear() {
       // your logic
    }
}

Ответ 3

Я нашел лучшее решение

private boolean isVisible;
private boolean isStarted;

@Override
public void onStart() {
    super.onStart();
    isStarted = true;
    if (isVisible)
        sendRequest(); //your request method
}

@Override
public void onStop() {
    super.onStop();
    isStarted = false;
}

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    isVisible = isVisibleToUser;
    if (isVisible && isStarted)
        sendRequest(); //your request method
}

Это улучшенная версия пропущенного ответа намбуути. Я тестировал это на многих условиях. Это безопасно.

Ответ 4

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment, container, false);

    if (getUserVisibleHint()) {
         sendRequest();
    }

    return view;
}

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if (isVisibleToUser) {
        if (isResumed()){ 
             sendRequest();
          }
    }
}

Ответ 5

Ниже работали для меня....

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState)
{
    //// create class member variable to store view
    viewFrag =inflater.inflate(R.layout.fragment_main_favorite, container, false);

    // Inflate the layout for this fragment
    return viewFrag;
}

и используйте этот

 @Override
    public void setUserVisibleHint(boolean visible)
    {
        super.setUserVisibleHint(visible);


            if (visible)
            {

                View v =  viewFrag ;
                if (v == null) {
                    Toast.makeText(getActivity(), "ERROR ", Toast.LENGTH_LONG ).show();
                    return;
                }
            }

    }

Ответ 6

My SightFragment.java здесь должен reset флаги в onDestroyView():

package cc.cubone.turbo.core.app;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.View;

/**
 * Fragment for handling view after it has been created and visible to user for the first time.
 *
 * <p>Specially in {@link android.support.v4.view.ViewPager}, the page will be created beforehand
 * but not be visible to user.
 *
 * <p>Call {@link android.support.v4.view.ViewPager#setOffscreenPageLimit(int)} to set the number of
 * pages that should be retained.
 *
 * Reference:
 * <ul>
 * <li><a href="http://stackoverflow.com/questions/10024739/how-to-determine-when-fragment-becomes-visible-in-viewpager">
 * How to determine when Fragment becomes visible in ViewPager</a>
 * </ul>
 */
public class SightFragment extends Fragment {

    private boolean mUserSeen = false;
    private boolean mViewCreated = false;

    public SightFragment() {
    }

    /*public boolean isUserSeen() {
        return mUserSeen;
    }

    public boolean isViewCreated() {
        return mViewCreated;
    }*/

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (!mUserSeen && isVisibleToUser) {
            mUserSeen = true;
            onUserFirstSight();
            tryViewCreatedFirstSight();
        }
        onUserVisibleChanged(isVisibleToUser);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        // Override this if you want to get savedInstanceState.
        mViewCreated = true;
        tryViewCreatedFirstSight();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        mViewCreated = false;
        mUserSeen = false;
    }

    private void tryViewCreatedFirstSight() {
        if (mUserSeen && mViewCreated) {
            onViewCreatedFirstSight(getView());
        }
    }

    /**
     * Called when the new created view is visible to user for the first time.
     */
    protected void onViewCreatedFirstSight(View view) {
        // handling here
    }

    /**
     * Called when the fragment UI is visible to user for the first time.
     *
     * <p>However, the view may not be created currently if in {@link android.support.v4.view.ViewPager}.
     */
    protected void onUserFirstSight() {
    }

    /**
     * Called when the visible state to user has been changed.
     */
    protected void onUserVisibleChanged(boolean visible) {
    }

}

Ответ 7

Хотя большинство этих решений работает, вам даже не нужно отслеживать состояние самостоятельно.

В текущих версиях библиотеки поддержки есть метод isResumed() который, вероятно, делает то, чего большинство из вас пытаются достичь, используя флаг isStarted:

Верните true, если фрагмент находится в возобновленном состоянии. Это верно и для продолжительности onResume() и onPause().

И тогда это так же просто, как:

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isResumed()) {
            updateUi(isVisibleToUser);
        }
    }

Ответ 8

НИЖЕ РАБОТАЛ ДЛЯ МЕНЯ

Пожалуйста, создайте глобальное представление, как это

private View view; 

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        //Inflate view layout
        view =inflater.inflate(R.layout.your_fragment, container, false);

        // return view
        return view;
    }

и использовать это

@Override
    public void setUserVisibleHint(boolean isUserVisible)
    {
        super.setUserVisibleHint(isUserVisible);
       //When fragment is visible to user and view is not null then enter here.
            if (isUserVisible && view != null)
            {
               // do your stuff here.
            }
    }

Ответ 9

public class MyFragment extends Fragment {

private boolean manageVisibility;


public MyFragment() {
    // Required empty public constructor
}

public static CommunityFragment newInstance() {

    Bundle args = new Bundle();

    CommunityFragment fragment = new CommunityFragment();
    fragment.setArguments(args);
    return fragment;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    manageVisibility = true;
    return inflater.inflate(R.layout.fragment_community, container, false);
}


@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);

    if (manageVisibility && isVisibleToUser) {
       // fragment is visible
        }
    } else if (manageVisibility) {
       // fragment is invisible
        }
    }
  } 
}

Ответ 10

Это лучшее решение, которое я нашел.

    @Override
    public void onCreateView() {
        super.onStart();
        if (getUserVisibilityHint()){
            //do stuff
        }
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (isResumed() && isVisibleToUser) {
            //do stuff
        }
    }

Ответ 11

Этот простой вариант работает в моем коде:

@Override
public void onStart() {
    super.onStart();

    if (getUserVisibleHint()) {
        updateUI(); // your logic
    }
}

а также

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);

    if (isResumed() && isVisibleToUser) {
       updateUI(); // your logic
    }
}

Ответ 12

Создайте этот код в setUserVisibleHint():

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