我正在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);
}
答案 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();
}
}