Fragment.isVisible() returns false even when Fragment added and visible
Asked Answered
S

5

6

I am perplexed by how Fragment.isVisible() is supposed to work. Even though I have a fragment added in Activity.create(), Fragment.isVisible() returns false even when FragmentManager.commitNow() is used.

Fragment.isVisible() returns false even in onResume(). However, when a UI button gets clicked the returned value is correct.

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

public final static String TAG = "HideFragmentOnChange";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ((Button)findViewById(R.id.my_button)).setOnClickListener(this);

    if(savedInstanceState == null){
        Fragment fragmentA = new FragmentA();

        Log.d(TAG, "onCreate: Before FragmentTransaction FragA: " + (fragmentA.isVisible() ? "visible" : "not visible"));

        getSupportFragmentManager().beginTransaction()
                .add(R.id.fragment_container, fragmentA, "fragA")
                .commitNow();

        Log.d(TAG, "onCreate: After FragmentTransaction FragA: " + (fragmentA.isVisible() ? "visible" : "not visible"));

    }

    this.runOnUiThread(new Runnable(){
        @Override
        public void run() {
            Fragment fragA = getSupportFragmentManager().findFragmentByTag("fragA");
            Log.d(TAG, "runOnUiThread after onCreate(): FragA: " + (fragA.isVisible() ? "visible" : "not visible"));
        }
    });
}

@Override
protected void onResume() {
    super.onResume();

    Fragment fragA = getSupportFragmentManager().findFragmentByTag("fragA");
    Log.d(TAG, "onResume: FragA: " + (fragA.isVisible() ? "visible" : "not visible"));

    this.runOnUiThread(new Runnable(){
        @Override
        public void run() {
            Fragment fragA = getSupportFragmentManager().findFragmentByTag("fragA");
            Log.d(TAG, "runOnUiThread after onResume(): FragA: " + (fragA.isVisible() ? "visible" : "not visible"));
        }
    });
}

@Override
public void onClick(View v) {
    Fragment fragmentA = getSupportFragmentManager().findFragmentByTag("fragA");
    Log.d(TAG, "onClick(): FragA: " + (fragmentA.isVisible() ? "visible" : "not visible"));
}

}

I initially thought that perhaps it is because the main thread has not had the chance to run yet and the FragmentTransaction does not fully and properly commit until a later point. However, calling runOnUiThread does not change the return value of isVisible().

I am attaching the log for reference.

03-15 17:22:34.978 14094-14094/ D/HideFragmentOnChange: onCreate: Before FragmentTransaction FragA: not visible
03-15 17:22:34.990 14094-14094/ D/HideFragmentOnChange: onCreate: After FragmentTransaction FragA: not visible
03-15 17:22:34.991 14094-14094/ D/HideFragmentOnChange: runOnUiThread after onCreate(): FragA: not visible
03-15 17:22:34.996 14094-14094/ D/HideFragmentOnChange: onResume: FragA: not visible
03-15 17:22:34.996 14094-14094/ D/HideFragmentOnChange: runOnUiThread after onResume(): FragA: not visible
03-15 17:22:56.683 14094-14094/ D/HideFragmentOnChange: onClick(): FragA: visible

Why does Fragment.isVisible() seem to return the correct value with such a big delay?

I am using support library 25.2 and support library Fragments although native fragments produced the same behavior.

Sihunn answered 15/3, 2017 at 15:42 Comment(0)
M
5

There is a method for Fragments :

     getUserVisibleHint();

You can find more information in official document.

It gives "true" when fragment is visible to user and "false" when it is invisible.

Enjoy!

Meanie answered 27/7, 2017 at 9:51 Comment(0)
C
1

You can use setUserVisibleHint

Form the Documentation

Set a hint to the system about whether this fragment's UI is currently visible to the user. This hint defaults to true and is persistent across fragment instance state save and restore.

To use it:

    private static boolean isVisible;

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

    if (isVisible) { 
        Log.d("TAG", "this fragment is visible");
    } else {  
        Log.d("TAG", "this fragment is invisible");
    }
}
Cassaba answered 15/3, 2017 at 15:54 Comment(0)
G
0

You have to keep in mind that the Fragment also has his own lifecycle. You are basically calling it way too early. A Fragment is deemed visible if

Fragment#isVisible

Return true if the fragment is currently visible to the user. This means it: (1) has been added, (2) has its view attached to the window, and (3) is not hidden.

See this SO post about the lifecycle of the Activity/Fragment When is onAttach called during the Fragment LifeCycle?

Geotectonic answered 15/3, 2017 at 15:53 Comment(0)
D
0

I noticed that on opening a fragment and going through all the lifecycle (onAttach, onCreate, onStart etc..), calling isVisible() from onResume() will return false. However, if you only stop the fragment (i.e pressing the home button), isVisible() will return true. Conclusion: Keep a class boolean flag:

   private mFirstTimeVisible = true;

and use it in the following onResume check:

   @Override
   public void onResume() {
       super.onResume();
       if (mFistTimeVisible || isVisible()) { 
          //your code...
       }
       mFistTimeVisible = false;
    }
Diastrophism answered 28/10, 2017 at 13:36 Comment(0)
B
0

I found a workaround, just call isVisible by some delay

 @Override
       public void onResume() {
           new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.d("ONRESUME", isVisible() );
            }
        }, 100);
           
 }
Bellbella answered 26/6, 2020 at 18:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.