Fragment onHiddenChanged not called - android

I recently added Fragments to my applications. For a new application i'll need to get
notified as soon as my fragment is shown. So i can do some calculations as soon as my
fragment is shown again.
My Fragment is used with a TabIndicator and it's only one FragmentClass which is used
a few times.
Here's the normal standard override class:
#Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
}

I had same problem.
I used standart guideline practic work with fragment (Building a Flexible UI).
I have two fragment (ListItemsFragment and InfoItemFragment).
When used normal screen size, I replace ListItemsFragment at InfoItemFragment and
the method onHiddenChanged doesn't call automatic.
FragmentTransaction mFragmentTransaction = getFragmentManager().beginTransaction();
mFragmentTransaction.replace(R.id.container_fragment, new InfoItemFragment(), "tag_fr_infoItem");
mFragmentTransaction.addToBackStack(null);
mFragmentTransaction.commit();
I think we must called in hide method FragmentTransaction. For example:
ListItemsFragment mListItemsFragment;
FragmentTransaction mFragmentTransaction = getFragmentManager().beginTransaction();
mFragmentTransaction.replace(R.id.container_fragment, new InfoItemFragment(), "tag_fr_infoItem");
if (mListItemsFragment != null) {
mFragmentTransaction.hide(mListItemsFragment);
}
mFragmentTransaction.addToBackStack(null);
mFragmentTransaction.commit();
And now the method onHiddenChanged work fine. When user click back button mListItemsFragment again show and method onHiddenChanged called automatic.
In documentation said:
this will be called whenever the fragment changes state from that
I think we must manual change value then method will be called.

Still looking for an answer? onHiddenChanged doesn't get called the first time an fragment is shown. Only when it changes state.
From the documentation:
Called when the hidden state (as returned by isHidden()) of the fragment has changed. Fragments start out not hidden; this will be called whenever the fragment changes state from that.

You can use setUserVisibleHint method to solve some similar problem. Hope it can help you.
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
// Do some your work
} else {
// Do your Work
}
}

if you use hide() and show() to hide or show your fragment, Any lifecycle method dont't work.so is setUserVisibleHint() .

Related

Lifecycle problem when use FragmentStatePagerAdapter, Fragments

I'm using FragmentStatePagerAdapter, ViewPager.
I'm going to use onSaveInstanceState by overriding to save some states like cursor position of EditText in every fragment.
But when I choose first fragment and next choose second fragment, the onSaveInstanceState of first fragment is not called. If I choose first and next choose third fragment, then the onSaveInstanceState of the first fragment is called.
In this case of choosing first fragment and next second fragment, even the onPause of the first fragment is not called.
What's the reason? How can I solve this problem? I have researched about this problem whole day. But I haven't found solution and correct reason yet.
onSaveInstanceState has cases that it can be called, but how about onPause? Why doens't onPause be called?
I found a solution. I used setUserVisibleHint.
In fragment, I wrote save and restore logic in setUserVisibleHint.
It works well.
This is called when fragment is shown or hidden.
Also I used onViewStateRestored, onSaveInstanceState together for being destroyed cases.
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser) {
if (mInputFrom != null) {
if(isToFocus) {
mInputFrom.requestFocus();
mInputFrom.setSelection(fromCursor);
} else {
mInputOut.requestFocus();
mInputOut.setSelection(toCursor);
}
}
} else {
if (mInputFrom != null) {
fromCursor = mInputFrom.getSelectionStart();
toCursor = mInputOut.getSelectionStart();
}
}
}
setUservisibleHint was deprecated.
So other option is that we can use constructor of FragmentStatePagerAdapter(fm, BEHAVIOR_SET_USER_VISIBLE_HINT);
If we call super's constructor like above in constructor of our customized Adapter that extends FragmentStatePagerAdapter, then onPause, onResume of fragment will be called for every case of being hidden or shown.
First option is suitable for my case I think. So I used first option and has solved perfectly.

Is there any way to detect if fragment is showing to user or not?

Here are simple steps.
step1 : fragment1 was showing and it's already added to Backstack
step2 : fragment2 is added to Backstack and showing it now
step3 : fragment2 is removed from Backstack
So finally, fragment1 is showing again to user.
In this situation, is there anyway to detect if fragment1 is showing again inner fragment1?
I tried with OnResume() but it doesn't work.
Thanks for answers!
Fragment currentFragment = getFragmentManager().findFragmentById(R.id.fragment_container);
if (currentFragment instanceof YourFragment) {
if(currentFragment.this.isVisible())
{
//your code
}
}
When you add the fragment in your transaction you should use a tag.
fragTrans.replace(android.R.id.content, myFragment, "MY_FRAGMENT");
...and later if you want to check if the fragment is visible:
MyFragment myFragment = (MyFragment)getFragmentManager().findFragmentByTag("MY_FRAGMENT");
if (myFragment != null && myFragment.isVisible()) {
// add your code here
}
See also http://developer.android.com/reference/android/app/Fragment.html
I just copied this answer https://stackoverflow.com/a/9295085/7232310
because I think is what you need. Otherwise you can check the following answers on the same question.
Hope it helps!
Try onAttach(), this is to trigger if the fragment is showed.
onDetach() is to detect if the fragment is leaving the user interface.
For example: you have 3 fragment(frag1,frag2,frag3), every fragment you need to put the onAttach()
frag1
#Override
public void onAttach(Context context) {
super.onAttach(context);
Toast.makeText(context, "I'm frag 1", Toast.LENGTH_SHORT).show();
}
I think there are 2 options
Try to override this behaviour and see if it works
void onHiddenChanged (boolean hidden)
As per documented here
Or Other option is to onStart() / onResume() callback of lifecycle try to observe behaviour of fragments visibility state.
boolean isVisible ()
As per documented here

how to call a method in onCreateView only if the Fragment is displayed in screen?

I'm using viewPager to create a layout with tabs and in each tab I use a Fragment. One of them is to get all de user contacts and put it on a ListView. But I want to call de AssyncTask only if the Fragment is displayed on screen.
is there a method to do it?
TY
Start your AsyncTask in onStart which is the method called once the fragment becomes visible to the user. onCreateView will be called even if the fragment doesn't become visible.
See also: http://developer.android.com/reference/android/app/Fragment.html#onStart()
I would however recommend to use a loader instead of AsyncTask (e.g. an AsyncTaskLoader http://developer.android.com/reference/android/content/AsyncTaskLoader.html).
you can use
#Override
public void setUserVisibleHint(boolean isVisibleToUser)
{
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser)
{
//things to do when fragment is visible
}
}
Even it is called before onCreateView.
You can check to see if it's visible with .isVisible() something like this
MyFragmentClass fragment = (MyFragmentClass) getSupportFragmentManager().findFragmentByTag("fragmentTAG");
if (fragment != null && fragment.isVisible()) {
// call AsyncTask
}

Callback when Fragment is replaced and when it is visible again

I've been researching this topic but so far no luck. Basically I'm replacing a fragment (A) with another one (B) using FragmentTransaction.replace. In this other fragment (B) I have a 'Cancel' button in the toolbar which when pressed pops back to the previous transaction (A) by calling getActivity().getSupportFragmentManager().popBackStackImmediate().
The problem is I need to update the Activity toolbar to display a different title when I'm showing fragment A and fragment B. I can't seem to find a method which gets called in fragment A whenever I go from A -> B -> A to inform me that it is visible again. The idea is to set the toolbar title in this callback which I cannot seem to find.
Can anyone point me in the right direction please?
Cheers.
Edit:
Method I call to replace the fragment with another one is as follows:
public static void replaceFragment(FragmentActivity parentActivity, int fragmentToReplaceId, Fragment withFragment, Integer enterAnim, Integer exitAnim)
{
FragmentManager fragmentManager;
FragmentTransaction transaction;
fragmentManager = parentActivity.getSupportFragmentManager();
transaction = fragmentManager.beginTransaction();
if ( (null != enterAnim) &&
(null != exitAnim) )
{
transaction.setCustomAnimations(enterAnim, exitAnim);
}
transaction.replace(fragmentToReplaceId, withFragment);
transaction.addToBackStack(null);
transaction.commit();
}
You can inform by overriding method onResume() in fragment and sending the message to activity or changing the Toolbar directly.
#Override
public void onResume() {
super.onResume();
((AppCompatActivity) getActivity()).getSupportActionBar().setTitle("Title");
}
In one activity, when replace A ---> B (A and B both are fragments), can use this call-back:
#Override
public void onAttachFragment(Fragment fragment) {
}
Solved by creating a simple static method in fragment A as follows:
public static void updateActivityTitle(FragmentActivity activity)
{
activity.setTitle(kActivityTitle);
}
Then I'm calling this method in fragment B as follows:
// cancel button has been pressed
private void cancel()
{
INV_CustomersFragment.updateActivityTitle(getActivity());
getActivity().getSupportFragmentManager().popBackStackImmediate();
}
Not ideal but it gets the job done. Any other solution involving a proper callback would be better
Update:
A better solution is the one described by #Rani at Fragment's onResume() not called when popped from backstack. This is more elegant and more maintainable, in fact I implemented this solution in my project. Compared to an equivalent solution for iOS this is still messy if you ask me, still seems the way to go.

Returning back to an Activity after calling and closing a Fragment does not change my Activity's lifecycle

Given an Activity that acts as a Home page (it never closes) that launches various fragments, how to know when the Activity is visible to the user?
From what I have observed, when I open a fragment the lifecycle for the Activity never changes, onPause() is not called. And when I close the fragment, onResume() is not called on my Activity.
Here is how I am starting my fragments, I am using this method and passing the fragment I want to launch to it.
public void addFragment(int containerId, Fragment fragment, boolean addToBackStack) {
// Check if the fragment has been added already. If so, then
// don't add the fragment.
Fragment temp = mFragmentManager.findFragmentByTag(fragment.getClass().getName());
if(temp != null && temp.isAdded()) {
return;
}
FragmentTransaction ft = mFragmentManager.beginTransaction();
ft.add(containerId, fragment, fragment.getClass().getName());
if(addToBackStack)
ft.addToBackStack(null);
ft.commit();
}
What is the methodology for indicating that my Activity is visible again? Thanks in advance!
in the oncreate method of your home activity, call
mFragmentManager.addOnBackStackChangedListener(this) ;
and then define
#Override
public void onBackStackChanged() {
int backStackCount = mFragmentManager.getBackStackEntryCount();
if(backStackCount == 0) {} //back to home screen
}
Your Activity is always Visible even if thousand Fragments are showing at the same time, for the sake of understanding Fragments are just Custom-Views, and the Fragment gives a helping hand in handling your View, so onPause() on your activity does not need to called when a Fragment dies or is born,just like inflating a View.
Just like Sir #Tim Mutton said, you need to check your BackStack to know if you are back, or you can use the ViewGroup method ViewGroup.indexOfChild(View child) - this method will an int of value getChildCount()-1 which means its on top of its fellow sibblings..
Hope it helps

Categories

Resources