I have two fragments.
There is some code in the onCreate() of fragment1.
When I'm in fragment2 and press back, it goes to fragment1 and start from onCreateView(). But I need the code that is in the onCreate() to run.
In Activity:
getSupportFragmentManager().beginTransaction().
replace(R.id.host_fragment, new Fragment1()).commit();
In fragment1 I have button that navigate to fragment2:
getParentFragmentManager().beginTransaction().addToBackStack("").
replace(R.id.host_fragment,Fragment2).commit();
And I don't have any code for onBackPressed() in activity.
The activity that has fragments, It's not MainActivity.java
Thank you.
I think, you need not do that, it is already okay. When you put fragment1 into backstack and then press back, onCreateView() of fragment1 is called only if that previously instantiated fragment1 instance is in memory. If not in memory, all the fragment lifecycle callbacks are called accordingly, including onCreate().
So, if you make your non graphical initializations in onCreate(), they are already initialized, when you press back; or at least be initialized if it is created as new. All these will be managed by fragment manager.
Is there any reason that you put your code inside OnCreate()?
if no then put your code inside OnCreateView() because OnCreateView() is called right after OnCreate(). so if you want to call that code on fragment creation it's guaranteed that your code is called.
also if you look at fragment lifecycle you can see that if a fragment is returned from backstack, its OnCreateView() method will be called. so when you come back from your second fragment, your code will run.
Simple workflow is move your code which need to execute every time from onCreate() method to onResume().
onResume() calls every time when user focus on the screen. Or from background to foreground.
Thank you all for the answers.
First I thought my problem was just because of onCreate(), but after I put my code inside the onCreateView(), my problem was still remains.
So, I decided to restart the fragment when Back Pressed. So I came up with this solution:
In the activity:
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
getSupportFragmentManager().popBackStack();
getSupportFragmentManager().beginTransaction().
replace(R.id.host_fragment, new Fragment1()).commit();
} else {
super.onBackPressed();
}
}
Is that efficient?
Related
I'm like an intermediate in android programming. I decided to take a deep dive into the Activity lifecycle methods and I realised something, like why do methods Toasts.show() and many other methods get called again when the activity is resumed. If the methods are in the onCreate so why then if you like go to another activity and return it will still give you a Toast message. Let me give an example.
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
{Your Initialization go here }
//Toas message
Toast.makeText(code).show();
}
}
So imagine you leaving this activity for another one and then coming back... why does it still show the Toast message. Because since the lifecycle is
OnCreate
onResume
onStart
onPause
onstop
onDestroy
And when you come back to your MainActivity it calls the
onResume
onStart.
So if onCreate is not called...So how does the Toast message show.
Please someone should help me answer this I've searched all day but couldn't find answers.
accoording to lifecycle of activity https://developer.android.com/guide/components/activities/activity-lifecycle, if there is no memory engouh the app process will kill, so when you back to your activity on created will call another time.
the image below for clarification:
When your activity goes in the background, and memory is required for other apps. It is possible that the system frees up space even though your activity is in the background with ONPAUSED state. and now if you navigate to your activity, since the saved instance is removed due to memory requirements. instead of ONRESUME, ONSTART is called. you can read more about it here: https://developer.android.com/guide/components/activities/activity-lifecycle
and see this image for better understanding: https://developer.android.com/guide/components/images/activity_lifecycle.png
This uncertainty is one of the reasons why we now mostly use view models for a sizeable app.
I just saw that onActivityCreated() is going to be deprecated in future. I try to implement LifecycleOwner and LifecycleObserver pattern but I'm not quite sure about what I'm doing here.
I'm using NavigationComponent, which meens :
I have a MainActivity
I have a MainFragment, instanciated as the home fragment
I have multiple fragments that can be accessed from this home fragment
For some reasons I need to know when activity is created from all of these fragments (MainFragment and sub fragments)
From what I've seen until now, I need to :
In the MainActivity, getLifecycle().addObserver(new MainFragment()). And do this for all sub fragments (which is verbose for nothing)
In fragments, implements LifecycleObserver and
#OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
private void onCreateEvent() {
Timber.i("%s MainActivity created", TAG);
}
This seems to work well, but I have some questions :
The syntax addObserver(new MainFragment() disturbs me. It looks like we are creating a new fragment instance, while the fragment is normally instantiated with the navigation defined in the navGraph.
As I said before, if I have my MainFragment with 10 sub fragments, I'll have to declare 11 observers ? Weird
Do I have to clear these observers at some point in the activity lifecycle ?
What is the proper way to implement it ?
EDIT 1:
To answer the question why I need to know when the activity is created :
I need this because I need to access my MainActivity viewmodel (new ViewModelProvider(requireActivity()).get(ViewModel.class). To call requireActivity() or getActivity() I need to know when the activity is created (was easy with onActivityCreated()).
Databinding is implemented with my MainActivity and this viewmodel. The layout of this activity is hosting a loader to show when network requests are performed.
I can perform requests from the MainFragment and from the sub fragments. When I perform a request from one of these fragments I need to enable this loader view, and when I got datas back I need to hide this loader.
And yes, all these fragments are in the graph
You have never needed to wait for onActivityCreated() to call requireActivity() or getActivity() - those are both available as soon as the Fragment is attached to the FragmentManager and hence can be used in onAttach(), onCreate(), onCreateView(), onViewCreated() all before onActivityCreated() is called.
This is one of the reasons why onActivityCreated() was deprecated - it actually has nothing to do with the activity becoming available to the Fragment, nor does it have anything to do with the activity finishing its onCreate() (it, in fact, can be called multiple times - every time the Fragment's view is created, not just once after the first time the Activity finishes onCreate()).
As per the deprecation notice:
use onViewCreated(View, Bundle) for code touching the Fragment's view and onCreate(Bundle) for other initialization.
Those are the recommended replacements, depending on whether the code you had in onActivityCreated() was accessing the Fragment's views or not.
Once you realize that requireActivity() can be called in onAttach(), etc., the rest of the deprecation notice makes more sense:
To get a callback specifically when a Fragment activity's Activity.onCreate(Bundle) is called, register a LifecycleObserver on the Activity's Lifecycle in onAttach(Context), removing it when it receives the Lifecycle.State.CREATED callback.
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
// Register a LifecycleObserver on the Activity's Lifecycle in onAttach()
requireActivity().getLifecycle().addObserver(this);
}
#OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
private void onCreateEvent() {
// Remove the LifecycleObserver once you get a callback to ON_CREATE
requireActivity().getLifecycle().removeObserver(this);
// Then do your logic that specifically needs to wait for the Activity
// to be created
Timber.i("%s MainActivity created", TAG);
}
But, as mentioned above, this is not what you should be doing if you are trying to access a ViewModel at the activity level.
Hi im currently building my First android app and i have a problem that i cant solve this past 3 days. so i have MainActivity and on it there is a Fragment with Recyclerview and ArrayList< Item > listOfItem, on this Fragment there is a Floating button that when i click it will take me to SecondActivity there is a edit text on this SecondaryActivity that i have to fill then i will pass the data back to listOfItem.My problem is what method can i call on SecondActivity to create/add an listOfItem when i go back to MainActivity Fragment? I dont want to make Adapter and listOfItem to be static. Is there a way? thanks
Simple, You can achieve this by using Shared Preference.
What you need to do is just save that Edit Text data to Model(POJO), save that Model to Preference and in your Main Activity - Fragment on Resume method show updated data from that Preference.
Yeah here you need to take care of
The fragments onResume() or onPause() will be called only when the Activities onResume() or onPause() is called. They are tightly coupled to the Activity.
For more convient and efficient handling of data from any activity or fragement to any activity or fragment, you can use Event Bus.. Here is link where you will get the details information: https://github.com/greenrobot/EventBus
The best solution would be to start the second Activity for result.
startActivityForResult(ActivityBIntent)
Then checking the result overriding
onActivityResult() on the first activity and updating your list/adapter from it
I have two activtiy. When a boolean variable in activity 1 is true then the UI in activity 2 should be update (activity 2 is with fragment). When I back to activity 2 with (setDisplayHomeAsUpEnabled) it works correctly but with back button it does not work. What is the difference between this ways and how I can solve this. I try update the activity 2 with this code but it does not work:
#Override
public void onBackPressed() {
super.onBackPressed();
//update();
}
The Home Button is not meant to behave like the Back Button. See this reference. The Home or "Up" Button should take the user up within the view hierarchy (i.e. if you have a number of multiple choice fragments, don't go back through each of them, but back to the activity that started the first fragment)
Each activity should specify what it's parent activity is in order to properly use this functionality. You can do this through the manifest, or by overriding onOptionsItemSelected() as outlined here
In terms of why your activity 2 may be updating when using the "Up" button but not the back button, this could be because both handle the back stack in a different way. Back will take you to the last thing on the stack and resume it, assuming you don't haven't tagged the activity with a launchmode that alters this behavior. Here's more info on the back stack. If you haven't designated your Activity 2 as "singletop" then when you use the "Up" Button, a new instance of that parent activity is created. See here. This may means that the information is updating after using the home button because it's creating a new instance of the activity, while for the back button - you are not creating a new instance but resuming a previous instance... make sure you implement an onResume() function to properly handle this and update the information.
I am nearly finished with my first Android App, but there is one thing that still bothers me: I have an activity with EditText fields and a "Start"-button that leads to a new Activity. When the user presses the back-button (the one thats on the phone), I get back to my first Activity. Can I change this and define a whole new Activity? A modified version of my first Activity?
Here is what I want to achieve:
First Activity - - > (start-button clicked)
- - > Second Activity - - > (back-button clicked)
- - > First Activity, modified.
Thanks for any help!
Use startActivityForResult and onActivityResult.
An example of this is here.
You will put your layout manipulation code as it were in the onActivityResult method in your first activity, and start the second activity using startActivityForResult.
override onBackPressed() in your second activity and start your modified activity from there. Something like:
#Override
public void onBackPressed()
{
//start your activity here
//make sure you remove the super call
}