Add fragment and update actionbar title - android

I know that question about refreshing actionbar title has already been answered.
But my problem is quiet different.
I use fragments with add method and not with replace method for some reasons. So previous fragment are not destroy and when back, previous fragment aren't not recreating.
This is my configuration :
Fragment A with title "FragA" > Fragment B with title "FragB"
When I go back to Fragment A from Fragment B the actionbar title should be "FragA" but it stay "FragB".
The problem is with add method Fragment A is not recreating and I didn't find event to refresh it.
The only simple solution I found for now is :
1- fragB.OnResume : save previous action bar title
2- fragB.OnDestroyView : restore previous actionbar title
With this solution, the result is ok, but I found this solution is not very clean. Is there a better way to refresh actionbartitle using add method with fragments ?

You can override your onBackPressed of your activity and each time you pressed it you then get the name of the fragment from the backstack to know which fragment you current at.
sample:
#Override
public void onBackPressed() {
super.onBackPressed();
int framentCount = this.getFragmentManager().getBackStackEntryCount();
if(framentCount != 0)
{
FragmentManager.BackStackEntry backEntry=getFragmentManager().getBackStackEntryAt(framentCount-1);
String str=backEntry.getName(); //the tag of the fragment
if(str.equals("fragA"))
//set the actionbar title to FragA
else if(str.equals("fragB"))
//set the actionbar title to FragB
}
FragA myFragA = (FragA)getFragmentManager().findFragmentByTag("MY_FRAGMENTA_A_TAG");
if (myFragA.isVisible()) {
//action bar.title="title first fragment"
}
}
Now to know which fragment is which you need to put a tag to your fragment when you add / replace it to the backstack. Also make sure that you call addToBackStack to put the fragments to the backstack.
FragmentTransaction.add(int containerViewId, Fragment fragment, String tag)
FragmentTransaction.replace(int containerViewId, Fragment fragment, String tag)

Call the below line of code in all your fragments onResume() callback. you wouldnt need to save the title.
((YourFragmentActivity) getActivity()).setActionBarTitle(YOUR_TITLE);
it should help.

Put a public static string called tag on your fragments, then use this where the tag is. More maintainability.
Why - This means if you want to change the tag, you only have to change it in one place, less refactoring. (Its used also on add, replace functions - see Rod's answer if confused)
My implementation of the solution is similar to how Rod solved the issue in his edited answer except a lot less code.
#Override
public void onBackPressed() {
super.onBackPressed();
try {
if (getFragmentManager().findFragmentByTag(FragA.tag) != null) {
if (getFragmentManager().findFragmentByTag(FragA.tag).isVisible()) {
getActionBar().setTitle(R.string.FragA_title);
}
}
if (getFragmentManager().findFragmentByTag(FragB.tag) != null) {
if (getFragmentManager().findFragmentByTag(FragB.tag).isVisible()) {
getActionBar().setTitle(R.string.FragB_title);
}
}
}
catch (NullPointerException e) {
}
}
eg of static tag use
FragmentTransaction.add(int containerViewId, Fragment fragment, FragA.tag)

#Override
public void onStop() {
super.onStop();
((AppCompatActivity) getActivity()).getSupportActionBar().setTitle("Title");
}
Override the onStop() method in your current fragment, and gives the title name of your previous fragment.

Related

Android Navigation Drawer wrong toolbar title onResume

I have a Navigation Drawer in the main activity of my app. On the onCreate method of the activity I initialize one of the fragments like this :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
MenuItem menuItem = navigationView.getMenu().findItem(R.id.menu_history);
openFragment(menuItem);
}
public void openFragment(MenuItem menuItem){
Fragment newFragment = null;
switch (menuItem.getItemId()){
case R.id.menu_history :
newFragment = new HistoryFragment();
break;
//.....
}
if (newFragment != null){
//Replace content frame in activity_main.xml with newFragment
getSupportFragmentManager().beginTransaction()
.replace(R.id.content_frame, newFragment)
.commit();
menuItem.setChecked(true);
getSupportActionBar().setTitle(menuItem.getTitle());
}
drawerLayout.closeDrawers();
}
This all works well, the fragment appears on startup with the title on the toolbar being "History". But when the app goes into onPause and then onResume the toolbar title switches from "History" to the app name. I suspect this is an issue with onResume not opening the fragment / returning to its previous state correctly, because when I added the following lines to onResume the issue stopped:
#Override
protected void onResume() {
super.onResume();
MenuItem menuItem = navigationView.getMenu().findItem(R.id.menu_history);
openFragment(menuItem);
}
That solution seems to fix it but that means it has to reload the fragment with the animations every time the app is resumed, which isn't optimal. Any ideas on how to fix this?
If it helps, to recreate the issue I found useful to make the app split screen, because it always calls onResume. Thanks.
Inside your openFragment() method, you write:
getSupportActionBar().setTitle(menuItem.getTitle());
This is the only thing that changes your toolbar's title.
Note that this code has nothing to do with your Fragments, per se. When your activity is destroyed and recreated, the active Fragment will be successfully (automatically) destroyed and recreated by the FragmentManager... but your openFragment() method won't run again and so nothing will update your toolbar's title.
There are numerous ways you could solve this. Probably the right thing to do is update your toolbar's title from within one of your Fragment's lifecycle methods.
Edit: A reasonable place to update your toolbar's title would be in your fragment's onActivityCreated() method. This will run both when the fragment is first added and during recreation. Something like:
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
((AppCompatActivity) getActivity()).getSupportActionBar().setTitle("hello world");
}
If you do not want to re-create the fragment each time, you should use saveInstanceState like mentioned here: https://stackoverflow.com/a/17135346/1505074

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

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

Fragment Back button

I know how to add a Fragment to the backstack but how do I know, when the user presses the back Button, which fragment I left and which I went to? I need to do a certain action depending on this so I need to know from and to which fragment I am going. Specifically I need to know which fragment I left so if it is a certain fragment, I can remove a button.
Override onBackPressed in Activity:
#Override
public void onBackPressed(){
FragmentManager fm = getSupportFragmentManager();
Fragment f = fm.findFragmentById(R.id.content_frame); // get the fragment that is currently loaded in placeholder
Object tag = f.getTag();
// do handling with help of tag here
// call super method
super.onBackPressed();
}
You can add the Fragment like this :
ArticleMain articalemain = new ArticleMain();
getFragmentManager().beginTransaction().add(R.id.fragment_Top, articalemain, "MY_FRAGMENT").commit();
While Removing the Fragments do like this :
ArticleMain myFragment = (ArticleMain) getFragmentManager()
.findFragmentByTag("MY_FRAGMENT");
if (myFragment.isVisible()) {
// add your code here
myFragment.getFragmentManager().beginTransaction()
.remove(myFragment).commit();
}

Categories

Resources