Using onSaveInstanceState in BottomNavigationView's fragment replacing - android

I am trying to use onSaveInstanceState method to minimize the server capacity in my app. I am trying to avoid accessing the server everytime the user changes his/her bottom navigation view(now inferred to bnv).
(I only could find the examples of onSaveInstanceState when its rotating the phone)
I followed every fragment's lifecycle methods but onSaveInstanceState would not be called. I also figured out that when I replace the fragment in BottomNavigationView, let's say, fragmentA to fragmentB, fragmentA reaches onDestroyView when it is replaced. So why won't onSaveInstanceState be called??
I am stuck with this problem for days.. Could anyone give some advice?
My MainActivity codes.
public static final String TAG = "LifeCycles";
FragmentManager manager;
FragmentA fragmentA;
FragmentB fragmentB;
FragmentC fragmentC;
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_home:
manager.beginTransaction().replace(R.id.testFrame, fragmentA).commit();
return true;
case R.id.navigation_dashboard:
manager.beginTransaction().replace(R.id.testFrame, fragmentB).commit();
return true;
case R.id.navigation_notifications:
manager.beginTransaction().replace(R.id.testFrame, fragmentC).commit();
return true;
}
return false;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.w(TAG, "----- Activity: onCreate ------");
manager = getSupportFragmentManager();
fragmentA = new FragmentA();
fragmentB = new FragmentB();
fragmentC = new FragmentC();
BottomNavigationView navigation = findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
manager.beginTransaction().add(R.id.testFrame, fragmentA).commit();
findViewById(R.id.toActivity).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, SemiActivity.class));
}
});
}

Related

How to change the title of fragment when press back?

I have 3 fragments, Home, Menu and orders they can be loaded by bottomnavigtioview items and the title shown by it as well
once navigate from Home to Orders then if you want to go back to Home From Orders the title still "Orders"
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment;
switch (item.getItemId()) {
case R.id.navigation_home:
toolbar.setTitle(getResources().getString(R.string.title_home));
fragment = new HomeFragment();
loadFragment(fragment);
return true;
case R.id.navigation_menu:
toolbar.setTitle(getResources().getString(R.string.fragment_title_menu));
fragment = new ProductFragment();
loadFragment(fragment);
return true;
case R.id.navigation_orders:
toolbar.setTitle(getResources().getString(R.string.title_orders));
fragment = new OrdersFragment();
loadFragment(fragment);
return true;
}
return false;
}
};
private void loadFragment(Fragment fragment) {
// load fragment
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_container, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
navigation = findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
// attaching bottom sheet behaviour - hide / show on scroll
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) navigation.getLayoutParams();
layoutParams.setBehavior(new BottomNavigationBehavior());
toolbar.setTitle(getResources().getString(R.string.title_home));
Fragment f = HomeFragment.newInstance();
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_container, f)
.commit();
}`
I have Also Tried this but its not working
`
fragmentmanger.addOnBackStackChangedListener -> public void onBackStackChanged() {
}`
Instead of calling toolbar.setTitle in your onNavigationItemSelected method, move it to onCreateView of each fragment. When you navigate back to a Fragment, onCreateView is executed again.
It worked for me when calling it in onResume like this in each fragment:
if(getActivity()!=null) {
((MainActivity)getActivity()).setActionBarTitle
(context.getResources().getString(R.string.YOUR_TITLE));
this is the function setActionBarTitle in MainActivity
public void setActionBarTitle(String title) {
toolbar.setTitle(title);
}

Prevent fragment refreshing with bottom navbar

I have the following bottom navbar code to switch between 3 fragments:
public class MainActivity extends AppCompatActivity {
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment = null;
switch (item.getItemId()) {
case R.id.navigation_home:
fragment = new HomeFragment();
break;
case R.id.navigation_dashboard:
fragment = new DashboardFragment();
break;
case R.id.navigation_notifications:
fragment = new NotificationsFragment();
break;
}
return loadFragment(fragment);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadFragment(new HomeFragment());
BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
}
private boolean loadFragment(Fragment fragment) {
//switching fragment
if (fragment != null) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, fragment)
.commit();
return true;
}
return false;
}
}
In the fragments there are RecyclerViews with lists. Every time I switch between the tabs (between fragments), it looks like the fragment is reloaded, and the lists jump to the top. I want to prevent that reloading so that the user stays on the same place in the list he viewed before switching fragments
The problem is that you are creating a new instance every time. You can cache the instance like:
private Fragment mHomeFragment = new HomeFragment();
private Fragment mDashboardFragment = new DashboardFragment();
private Fragment mNotificationsFragment = new NotificationsFragment();
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment fragment = null;
switch (item.getItemId()) {
case R.id.navigation_home:
fragment = mHomeFragment;
break;
case R.id.navigation_dashboard:
fragment = mDashboardFragment;
break;
case R.id.navigation_notifications:
fragment = mNotificationsFragment;
break;
}
return loadFragment(fragment);
}
As we could see, you are always replace your fragment when clicks on bottom navigation, replace means previous fragment removes and state cleans. The solution is do not create your fragment each time and use attach/detach method for showing actual fragment. Here is already described about these methods.

Clear an activity on moving from activity to fragment

i have an home activity with icons at bottom navigation bar. On clicking the icons it moves to respective fragments. But the problem is the home activity stacks over all the fragments. What might be the problem here.
I tried finish(); after calling the fragment. But that closes all activities and goes to main activity. I need help.
Main Activity->HomeActivity-> attendance fragment
This is the home activity
Home Activity
On clicking the Attendance fragment below
Attendance fragment
Here is the code of home activity
public class FHome extends AppCompatActivity {
public static Activity fa;
private Toolbar toolbar;
private ListView listView;
public static SharedPreferences sharedPreferences;
public static String SEL_DAY;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fhome);
setupUIViews();
initToolbar();
setupListView();
fa = this;
BottomNavigationView bottomNavigationView = (BottomNavigationView)
findViewById(R.id.navigation);
bottomNavigationView.setOnNavigationItemSelectedListener
(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
Fragment selectedFragment = null;
switch (item.getItemId()) {
case R.id.action_item1:
selectedFragment = FAttendance.newInstance();
break;
case R.id.action_item2:
selectedFragment = FPost.newInstance();
break;
case R.id.action_item3:
selectedFragment = FUpdate.newInstance();
break;
}
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, selectedFragment);
transaction.commit();
return true;
}
});
//Manually displaying the first fragment - one time only
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, FPost.newInstance());
transaction.commit();
}
Help me out :(

How to keep fragments state like Instagram in Android?

I need to implement the UI of my app, like the Instagram one. I need to switch from different fragments, with the usage of the bottom navigation view, but I need to keep state of the fragments, like I left them. How Can I achieve this?
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
item.setChecked(true);
switch (item.getItemId()) {
case R.id.action_formation:
if (homeFragment == null) {
homeFragment = new HomeFragment();
}
displayFragment(homeFragment);
break;
case R.id.action_result:
if (introResultFragment == null) {
introResultFragment = new IntroResultFragment();
}
displayFragment(introResultFragment);
break;
case R.id.action_market:
displayFragment(new MarketFragment());
break;
}
return false;
}
public void displayFragment(final Fragment fragment) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
fragmentTransaction.replace(R.id.container, fragment, fragment.getClass().toString());
fragmentTransaction.commit();
}
It's been a long time but I want to offer my open source library in github which implements the same UX of Youtube and Instagram:
https://github.com/ZachBublil/ZNavigator
You got to add this dependency to your gradle:
compile 'com.zach.znavigator:znavigator:1.0.0'
The only thing you have to do is to pass the list of fragments you want to be in the BottomNavigationView:
public class SampleActivity extends NavigationActivity {
private BottomNavigationView navigationView;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
navigationView = (BottomNavigationView) findViewById(R.id.navigationView);
LinkedHashMap<Integer, Fragment> rootFragments = new LinkedHashMap<>();
rootFragments.put(R.id.tab1, new FirstTab());
rootFragments.put(R.id.tab2,new SecondTab());
rootFragments.put(R.id.tab3, new ThirdTab());
init(rootFragments, R.id.container);
navigationView.setOnNavigationItemSelectedListener(this);
navigationView.setOnNavigationItemReselectedListener(this);
}
#Override
public void tabChanged(int id) {
navigationView.getMenu().findItem(id).setChecked(true);
}
}
If you want to open a new fragment as inner screen in one of the tabs you can do it by using ZNavigation class in the tab fragment:
ZNavigation.openChildFragment(getFragmentManager(),new ChildFragment());
just remember the active fragment, and use userVisiableHint to get active status in each fragment.
private Fragment currentFragment; // need to be init
private void switch2Fragment(Fragment target){
getFragmentManager().executePendingTransactions();
if(target.isAdded){
getFragmentManager().beginTransaction().hide(currentFragment).show(target).commit();
} else {
getFragmentManager().beginTransaction().hide(currentFragment).add(R.id.xxx, target).commit();
}
currentFragment.setUserVisibleHint(false);
currentFragment = target;
target.setUserVisibleHint(true);
}
private boolean isFragmentActive(Fragment target){
return target.getUserVisibleHint();
}

Fragments get re-created upon bottomnavigationview change item click

I have an activity with a Framelayout and a BottomNavigationView...I have 4 fragments (A,B,C,D)...The thing is when I switch from A to B after clicking on the menu item to load fragment B, fragment A gets destroyed...I added a Log message on all the callback methods (OnAttach, OnCreate, OnCreateView.....etc) involved in Fragment lifecycle and onDestroyView is ALWAYS called when I change fragments...So when I come back to a previously opened fragment, onCreateView gets called again..
Here's my activity class:
public class Home extends AppCompatActivity
{
private BottomNavigationView.OnNavigationItemSelectedListener
mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item)
{
Fragment fragment = null;
Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container);
switch (item.getItemId())
{
case R.id.navigation_a:
if (!(currentFragment instanceof FragmentA))
fragment = FragmentA.newInstance();
break;
case R.id.navigation_b:
if (!(currentFragment instanceof FragmentB))
fragment = FragmentB.newInstance();
break;
case R.id.navigation_c:
if (!(currentFragment instanceof FragmentC))
fragment = FragmentC.newInstance();
break;
case R.id.navigation_d:
if (!(currentFragment instanceof FragmentD))
fragment = FragmentD.newInstance();
break;
}
if (fragment != null) {
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment).commit();
return true;
}
return false;
}
};
//TODO Handle life-cycle methods when switching between fragments
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction()
.add(R.id.fragment_container, FragementA.newInstance())
.commit();
fm.popBackStack();
BottomNavigationView navigation = findViewById(R.id.navigation); navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
}
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
moveTaskToBack(true);
return true;
}
return false;
}
}
I'd like to know what am I missing here actually....Thanks in advance
well your not adding the fragment to the backstack.
You are creating new instances every click.
Do retain the reference to those if you want to replace with the same one OR add then to backstack of the fragmentransaction, but you will need tags for navigating trough the previous ones.
Try to use setRetainInstance(true); for your fragments.
// this method is only called once for this fragment
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// retain this fragment
setRetainInstance(true);
}

Categories

Resources