在Fragment中的onCreateView之前调用setUserVisibleHint

时间:2014-06-11 10:56:04

标签: android android-fragments callback

我正在ViewPager工作并使用Fragment在那里找到了

  

在Fragment

中的onCreateView()之前调用的setUserVisibleHint()

我正在使用支持库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);
}

12 个答案:

答案 0 :(得分:89)

// 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()方法获取数据。 :)

答案 1 :(得分:13)

我找到了最佳解决方案

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
}

这是改进版本的 fareed namrouti 的答案。 我在很多情况下对此进行了测试。这很安全。

答案 2 :(得分: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();
          }
    }
}

答案 3 :(得分:3)

以下为我工作 ....

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

    }

答案 4 :(得分:1)

我的SightFragment.java应重置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's 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) {
    }

}

答案 5 :(得分:1)

尽管大多数此类解决方案都可以使用,但您甚至不需要自己跟踪状态。

在支持库的当前版本中,有一个 isResumed() 方法,该方法可能可以完成大多数人使用isStarted标志所要达到的目标:

  

如果片段处于恢复状态,则返回true。在onResume()和onPause()期间也是如此。

然后就这么简单:

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

答案 6 :(得分:1)

该简单变体在我的代码中起作用:

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

答案 7 :(得分:0)

以下为我工作

请创建像这样的全局视图

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

答案 8 :(得分:0)

这是我找到的最佳解决方案。

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

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

答案 9 :(得分:0)

您遇到的行为在文档本身中指定。

Note: This method may be called outside of the fragment lifecycle and thus has no ordering guarantees with regard to fragment lifecycle method calls.

在这里检查。 https://developer.android.com/reference/android/app/Fragment#setUserVisibleHint(boolean)

答案 10 :(得分:0)

现在,您不再需要为 FragmentPagerAdapter 使用此方法。 它对onView Screen 使用send true,对非View Screen 使用false,而每次都调用ViewPager。

由于Android在AndroidX中发布了LifeCycle,所有的生命周期方法都会被调用到可见屏幕上。 LifeCycle 不会在 PagerAdapter 中的非可见屏幕的 onCreateView 之后运行。

这是为了: ~已弃用 setuservisiblehint

答案 11 :(得分:-1)

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