see my application view here
I have 3 Fragments that I switch between with three Toolbar buttons. When I go from 1st fragment to 2nd fragment onPause() or onStop() methods are not called and android sees that fragment as still running I guess, but when I go from 1st fragment to 3rd, they are called. I want it to be called when I go from 1st to 2nd one, so I can call onResume() function when I go back to 1st fragment, so I can trigger some functions. What causes it and how can I solve?
Fragment's LifeCycle methods( onPause() and onStop() etc.) Dependent on Activity's Life cycle Methods.
It means if your Activity's onPause() and onStop() called then your fragment's onPause() and onStop() will be called
If you want to notify your fragment that it is visible or not then you can use.
Override this method in your fragments.
#Override
public void setUserVisibleHint(boolean isVisibleToUser)
{
super.setUserVisibleHint(isVisibleToUser);
if (visible)
{
// Control will be here if fragment is visible.
//Do whatever you want.
}
}
These are fragments inside ViewPager. so, on stop or onpause wont call
there is a interface in fragment named as
#Override
public void setMenuVisibility(final boolean visible) {
super.setMenuVisibility(visible);
if (visible) {
// ...
}
}
using this method u can get to know the visibility of fragment
else you can use the setOffscreenPageLimit(value);
example
mViewPager.setOffscreenPageLimit(1);
Related
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.
I'm making an Android App, that uses BottomNavigationViewEx to have a Bottom Navigation widget with 5 sections/fragments, I manage them using a viewpager, but one of this fragment (fragment #3) also uses a tab layout to nest another 2 fragments and I need to keep the selected tab when the user navigates to other fragment using the BottomNavigation icons.
The problem is that I need save the state of the fragment #3 (juts to keep it simple, I call them in this post fragment #), that is the fragment that holds the tablayout.
Inside fragment #3 I'm calling:
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putInt("currentDirectoryFragmentId",tabLayout!!.selectedTabPosition)
}
but the method is never being called, and makes sense, because I really never destroy the parent activity, but onDestroy() is being called inside each fragment correctly.
So, How can I save the state of a fragment when the user navigates between fragments that are children of a same activity?
As stated in the comments. You can accomplish this by using a variable inside the parent activity and referring to and setting this variable inside the fragments' onPause() & onResume() methods.
Inside Parent Activity
public static int position = -1;
Inside Child Fragment
#Override
public void onPause() {
super.onPause();
MainActivity.position = viewPager.getCurrentItem();
}
#Override
public void onResume() {
viewPager.setCurrentItem(MainActivity.position);
super.onResume();
}
Explaining my problem :
I spend much time but I can not get this to work.I have view pager in main activty that contains three fragments using (Tabhost).My ViewPagerAdapter class extend FragmentStatePagerAdapter.
The problem I'm facing that my OnResume() Method is not called when I swipe the View .And I want to update the view of viewpager's fragment on swipe.
My OnResume() method is only called when i click on the ListView item and back again . but when I press OnLongClick on the ListView other fragments are not refreshed .
Note : I know that this question was asking before but none of those solutions helped me .
Note 2: When my phone goes to sleep then after unlocking phone 2nd fragment calling onResume()
My OnResume() Method in the first tab :
#Override
public void onResume() {
super.onResume();
adapterLogin.notifyDataSetChanged();
}
My OnResume() Method in the second Tab:
#Override
public void onResume() {
super.onResume();
adapterLogin.UpdateView(databaseHelper.getAllVoitureFavourite(1,username));
adapterLogin.notifyDataSetInvalidated();
adapterLogin.notifyDataSetChanged();
}
My UpdateView() Method in the BaseAdapter :
public void UpdateView(List<Voiture> items) {
this.voitureList = items;
notifyDataSetInvalidated();
notifyDataSetChanged();
}
Screen shot of my App for more understanding mu issue :
Any help will be appreciated.
Use setUserVisibleHint(boolean isVisibleToUser).
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
// Do your stuff here
}
}
The behavior you describe is how ViewPager works, there is nothing wrong with it.
Also, if you check the source code of the ViewPager class you will notice that the minimum offscreenPageLimit is 1. Setting it to 0 simply does nothing as it falls back to the default value 1.
What you can do is to add a TabHost.OnTabChangeListener so that on each swipe have the appropriate method called.
mTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
#Override
public void onTabChanged(String tabId) {
switch (mTabHost.getCurrentTab()) {
case 0:
//fragment 1 update()
break;
case 1:
//fragment 2 update()
break;
case 2:
//fragment 3 update()
break;
}
}
});
if you set offscreen page limit = 0 then this on swipe onviewcreate or onviewcreated method also call again and again this may disturb the flow of your app best approach which I use is using interface method override in your fragment and on page change invoke this override method that will work fine for you
If your ViewPager only has 2 pages, then neither of the fragments will pause during a swipe, and onResume() will never be called.
I believe that it always retains the neighbor pages by default, meaning it has a page limit of 1.
You could try setting the number of pages that it retains to 0.
mViewPager = (ViewPager)findViewById(R.id.pager);
mViewPager.setOffscreenPageLimit(0);
I have a below situation:
An activity, with a Fragment-A.
On user input, a new Fragment (lets call it Fragment-B)is added, by using below code:
ft.add(R.id.content_frame, fragmentB);
Now, when I press back, the fragment-B is destroyed as expected.
As fragment-B was added(and not replaced) there is no callback to onResume() of Fragment A.
I need to set focus of fragment-A as soon as fragment-B is destroyed.
I use below code to set the Focus:
getView().setFocusableInTouchMode(true);
getView().requestFocus();
Is there any way to achieve this?
For those developers who are struggling to get the "callback" in Fragment( when fragments are added and NOT Replaced ), can try below method:
Use addOnBackStackChangedListener which adds a new listener for changes to the fragment back stack.
I added this addOnBackStackChangedListener in onCreate() method of my Fragment-A, as below:
getFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if (getView()!=null){
getView().setFocusableInTouchMode(true);
getView().requestFocus();
}
}
});
Now As soon as Fragment-B is destroyed, onBackStackChanged is called and I was able to set the focus.
Of course, you can write whatever code you want to execute inside onBackStackChanged when Fragment is destroyed.
Create an interface:
public interface DestructionListener {
void onDestroyed();
}
Now in your FragmentB class put an implementation of Subject:
private DestructionListener listener;
public void setDestructionListener(DestructionListener listener) {
this.listener = listener;
}
Still in the same fragment, apply such change:
#Override
public void onDestroy() {
...
if(listener != null)
listener.onDestroyed();
super.onDestroy();
}
Now you have Listener pattern implemented - you can listen for an event which occurs when FragmentB is being destroyed. In your activity, just put:
fragmentB.setDestructionListener(new DestructionListener() {
void onDestroyed() {
// Request focus here
}
});
and you're good to go.
You can simply hide the fragment(in which you dont want focus) and show the one u want focus since you are adding fragments and not replacing.
In my application, I have a ViewPager which holds many swipeable Tabs with Fragments inside. Is there a method like onResume which is called every time the fragment comes to the screen? onResume, onCreateView and so on are called after the Fragment is created and not if it comes to the screen, so they do not work for me. Which method can I use for my problem?
You can use setUserVisibleHint method in your fragment:
#Override
public void setUserVisibleHint(boolean isVisibleToUser){
super.setUserVisibleHint(isVisibleToUser);
if(isVisibleToUser){
// Your fragment is visible
}
}