Update ActionBar title after leaving fragment - java

When my MainActivity is launched my ActionBar shows the app title. Once you navigate to a fragment through the nav drawer, the title is changed to match the fragment... however, once you navigate back using the back button, the title is left untouched and still has the title of the fragment. I am looking to change it back to the application Title.
I have tried to use the onResume() method in the MainActivity.java but it appears that does not get called once you leave a fragment.
#Override
public void onResume() {
super.onResume();
// Set title
getActionBar().setTitle("FuelR");
invalidateOptionsMenu();
}
Does anyone know what the best way would be to change the title back to the app_name ?
Thanks

Indeed destroying a Fragment within an Activity doesn't mean the activity will call onResume, first you have to notice that the Fragment lives within the Activity life context, and the Fragment do not alter it's life cycle, is just part of it, what you could do is within the fragment get a reference to the activity and set the title back to previous state, as shown below:
//In Fragment
#Override
public void onDestroyView() {
super.onDestroyView();
((Cast If Necessary)getActivity()).getActionBar().setTitle("Previous Title");
}
Or a more OOP approach would be, creating an interface that declares a method setTitlePreviousText, you implement that interface in your Activity class and from the fragment you could do this:
//In Fragment
#Override
public void onDestroyView() {
super.onDestroyView();
Activity act = getActivity()
if(act instanceof SetPreviousTextInterface){
//setTitlePreviousText will be called giving you the chance to just change it back...
((SetPreviousTextInterface)act).setTitlePreviousText();
}
}
This would be the interface file:
public interface SetPreviousTextInterface{
public void setTitlePreviousText();
}
Regards!

Related

Retaining Fragment back stack after orientation change

I have a Fragment (lets call it Base Fragment) containing clickable components. When one of these clickable components is pressed, a new Fragment appears over Base Fragment (lets call this Fragment A). When the back button is pressed from Fragment A, the view navigates back to Base Fragment.
To implement this, I have a FragmentContainerView called myFragmentLayout. When one of the clickable components is pressed, the following method gets called from Base Fragment to add the Fragment to the back stack:
private void addFragment(#NonNull Class<? extends Fragment> fragmentClass) {
mOnBackPressedCallback.setEnabled(true);
getChildFragmentManager().beginTransaction().setReorderingAllowed(true)
.add(R.id.myFragmentLayout, fragmentClass, null)
.addToBackStack(null)
.commit();
}
which enables the onBackPressedCallback in Base Fragment defined here to allow a back press to return to Base Fragment:
private final OnBackPressedCallback mOnBackPressedCallback =
new OnBackPressedCallback(false) {
#Override
public void handleOnBackPressed() {
if (getChildFragmentManager().getBackStackEntryCount() > 0) {
getChildFragmentManager().popBackStack();
} else {
setEnabled(false);
requireActivity().onBackPressed();
}
}
};
This code is achieving what I want it to achieve. However, if an orientation change happens inside Fragment A, then Base Fragment and Fragment A get recreated, but the back stack is lost. This causes a back press in Fragment A after a rotation to exit the app instead of returning to Base Fragment. How can I retain the back stack on an orientation change?

On Activity App Bar back pressed go to the parent activity with the fragment it was called

I'm having an issue that maybe is happening to other community members and I wanted to ask if somebody knows the solution. I have an app with these Two activities (MainActivity, UserProfileActivity).
The MainActivity contains a NavigationDrawer that navigates through fragments. So here it's the problem. While navigating in the second fragment and pressing a button in that fragment. It opens the UserProfileActivity (child of MainActivity) with the app bar generated by being a child. When you press that back button of this new Activity it should get back to MainActivity (parent) in the fragment that we were when we called this new Activity. But not, it's getting back to the MainActivity but with the home fragment loaded. Not the one we called previously.
Does anybody know how to solve that problem? Here I leave the code of the intent I do from the fragment:
Intent intent = new Intent(context, UserProfileActivity.class);
Bundle bundle = new Bundle();
bundle.putString("userId", message.getUserId());
intent.putExtras(bundle);
context.startActivity(intent);
Reason behind this behavior:
If you set the value of android:parentActivityName in your manifest.xml, by default pressing navigation button will create a new instance of the parent activity every time rather than popping it out from the activity backstack, so you're seeing the home fragment.
Workaround
At first, remove android:parentActivityName from manifest.xml. In onCreate method of your ChildActivity, put getSupportActionBar().setDisplayHomeAsUpEnabled(true) if you haven't already. Then override onSupportNavigateUp() of your ChildActivity, and put finish().
ChildActivity.java:
public class ChildActivity extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
getSupportActionBar().setDisplayHomeAsUpEnabled(true)
...
}
#Override
public boolean onSupportNavigateUp() {
finish();
return super().onSupportNavigateUp();
}
}

How to call a method in a fragment through the onClick in another fragment?

I am building an app with 2 fragments. The 1st fragment has an ImageView and 2 TextViews and the 2nd fragment has a set of buttons and EditTexts. In the 2nd fragment, I have a button called "Save". When this button is clicked, I want to download the image inside my 1st fragment to my device folder (The ImageView, the URI, the bitmap and canvas objects are all in the 1st fragment).
Because fragments can't communicate with one another directly, I was thinking of doing this with an interface. What I did was:
I've declared my interface in the 2nd fragment
Applied the logic of the interface's method in the MainActivity (which is the shared activity between the 2 fragments)
Fed the necessary parameters for the method in the 1st fragment.
Didn't work
But I don't think that this was the correct order so it's no surprise that it didn't work. How do I apply the interface in a way that a button click in the 2nd fragment downloads the image in the 1st fragment?
You could try one of these three options:
1.) Using callbacks to communicate via the activity
As shown in this article, you can define an interface in fragment 2 which is then called when the button is clicked. Your activity (which holds fragment 2) provides an implementation for that interface in which the activity calls a method in fragment 1 for downloading the image. For example:
Fragment 1 providing the download method
public class Fragment1 extends Fragment {
OnButtonClickedListener mCallback;
public void startImageDownload() {
// Download the image
}
// ...
}
Fragment 2 defining and calling the interface
public class Fragment2 extends Fragment {
OnButtonClickedListener mCallback;
// Some kind of init method called by onCreate etc.
private void init() {
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Call the listener if present
if(mCallback != null) {
mCallback.onButtonClicked();
}
}
});
}
public void setOnButtonClickedListener(Activity activity) {
mCallback = activity;
}
// Container Activity must implement this interface
public interface OnButtonClickedListener {
public void onButtonClicked();
}
// ...
}
The Activity reacting on the Button click and calling the download method
public static class MainActivity extends Activity implements Fragment2.OnButtonClickedListener {
Fragment1 mFragment1;
#Override
public void onAttachFragment(Fragment fragment) {
if (fragment instanceof Fragment2) {
// Register the listener
Fragment2 fragment2 = (Fragment2) fragment;
fragment2.setOnButtonClickedListener(this);
} else if (fragment instanceof Fragment1) {
// Keep a reference to fragment 1 for calling the "download" method
mFragment1 = (Fragment1) fragment;
}
}
#Override
public void onButtonClicked() {
// Handle the button click
mFragment1.startImageDownload();
}
}
This way you avoid linking the fragments together, instead you have the activity beeing a loose "connection" between fragment 1 and fragment 2.
This is just an exmple, i did not had time to test it. But i hope it helps.
2.) Using a local broadcast
I would recommend using the LocalBroadcastManager for sending a broadcast in fragment 1 (that the button was clicked) and receiving it in fragment 2 (downloading the image). Here is a great article about local broadcasts.
3.) Another option is to use ViewModel
The ViewModel was recently introduced by the new Android Jetpack and "is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations." (from ViewModel Overview).
It can also be used to share data between two fragments: Your activity basically holds the ViewModel and the fragments (inside that activity) can get access to it by calling: ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
I think your scenario you could use Observers or some kind of LiveData to react to the button-click via a ViewModel.
Thanks to #Elletlar for helping me improve my answer.

Return to a activity's fragment

I have an activity (MainActivity) which has a navigation drawer and can show 2 fragments (Fragments A and B), one at a time. (This activity is the default activity with navigation drawer created by android studio)
When I choose fragment B on the drawer the action bar menu is updated to show a button specific for fragment B (Button P).
Button P open an independent activity (IndependentActivity) with an explicit intent, on this activity I perform a database operation and after it I finish this activity to go back to MainActivity.
The problem is: When IndependentActivity is finished, MainActivity is shown but it shows fragment A instead of fragment B which was the one that called the intent to go to IndependentActivity.
How do I fix this by showing the fragment that initiated the action to go to another activity? Is there any way to save the fragment that was appearing?
Basically what you have to do is:
Save the state of the MainActivity when you enter IndependentActivity
Reload the state of MainActivity when you exit IndependentActivity
A simple implementation of this could be:
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save which fragment that is in the view when entering another activity
savedInstanceState.putString("fragment", "fragmentB");
super.onSaveInstanceState(savedInstanceState);
}
Fragment B can be replaced with a string that tells the application which is the current fragment.
Once you come back to the activity you want to:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if( savedInstanceState != null ) {
// Get which fragment that was active when you left the activity
savedInstanceState.getString("fragment");
// Programatically select the fragment here
}
}
You can read more about saving instance state here:
http://developer.android.com/training/basics/activity-lifecycle/recreating.html
I will leave it to you to programmatically select the fragment. I hope it helps!
I found out that I was having the same problem as this: https://stackoverflow.com/a/29464116/2325672
The back arrow to return did not work and reset the activity's fragments and the emulator back triangle worked perfectly.
Adding this code to IndependentActivity worked for me:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId()== android.R.id.home) {
Intent intent = NavUtils.getParentActivityIntent(this);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
NavUtils.navigateUpTo(this, intent);
return true;
}
return super.onOptionsItemSelected(item);
}

Refresh the content of fragment

Here is an android programming question.
I follow the offical example and write an activity that consist of two fragments which show a list menu and content.
When user click a item in list, detail will be shown in content fragment.
Now, I want to add a refresh button in Actionbar. When user click it, content in content fragment will be reloaded.
But I don't know how to get the reference of the running content fragment and call it to refresh. (Suppose all content fragments have already implemented a method called refresh())
public class FragmentLayout extends Activity {
.....
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_reload: //refresh button is clicked
//how can I call the DetailFragment to reload here?
}
public static class TitlesFragment extends ListFragment {
....
}
public static class DetailFragment extends Fragment {
...
}
In short, how the fragment and the activity contains the fragment to communicate?
Override onOptionsItemSelected in the fragment rather than the activity and react internally to the refresh event there.

Categories