I'm pretty new to android development and was reading about fragments and their profits, but reading about fragment's lifecycle, I understood that "All fragments will be created when the host activity is created, All goes to start state when the host activity goes to start state and ..." , in return when working with multiple activities, each start independently.
now the question I came with is that :
Due to fragment's lifecycle behavioral, would it cause a big delay at the starting of an app when too many fragments (let's say more that 20) exist in the activity?
Is it suggested to use single activity app when the app has a complex structure which leads to creation of multiple fragments?
After some test and logging I realized that in special case of using Navigation, not all the fragments are loaded at the same time but only those are required, for example in my case I do only have one fragment which is handled by a navigation, then when the activity runs only the Home Fragment is created, started and resumed not any other fragments, so not only this doesn't cause delay but it increase overall app performance as fragments are much less heavier than activities . So I suggest using Single Activity App along with navigation
Related
I'm developing an android app that is going to be used on a information screen. This app contains 5 (weather, next run, opening hours, etc...) activities, the plan is to loop through these activities with a timeinterval. So it starts with first activity, sleeps for like 5 seconds and then jump to next activity, and when it comes to the last activity, it should start in the front again.
What is the best solution to create a navigation system like this? Have Android some special features for things like this, or is the default startActivity() the only way?
And there is a little twist with this, some of the activities needs to retrive data from external sources by HTTP. So the activities must be done with data-query before it starts the activity.
You use startActivity to swap between activities. After you are finished with an activity, remember to call finish() - otherwise there will be a lot of instances of the same activity.
But if you want something like an information screen, you could use a single activity but use Fragments. That way you simply inflate a single fragment, and keep a timer to swap between them. You can still show the same content, but there are some differences between activity and fragment in inflating and finding the views by id.
I'm using an Activity A which starts another Activity B to get a result (the id of a customer), all seems to work perfectly but I have few error reports which tend to indicate that I have a concurrency bug between the UI building process and the onActivityResult method.
The whole hypothesis is based on the fact that the Activity A could have been destroyed during the appearance of the Activity B and created again which can create problems because Activity A creates its UI by doing some asynchronous network requests.
Of course, I'm not able to reproduce the bug (stopping the activity manually would be the nearest reproduction but only if the problem is the concurrence bug I mentioned).
So, in short,
Is it possible that an activity starting another one for result is cut by the OS while the user is in the newly created activity? (and then recreated when the user is finished and when setResult and finish are called on the newly created activity).
-- Update --
Sorry for the imprecision, Activity A is containing a Fragment which is starting the Activity and doing the network stuff, so it's maybe a matter of fragment (so the question is also "could the OS cut a Fragment which started an activity for result?").
I am having an issue in ViewPagerwith Tabshaving Fragments. I have my Home Activity that has a ViewPager with Tabs. For each Tab there is a Fragment. There are 3 sets of data coming from service when we start the application. The requirement is when I do changes for these sets of data in some other activities, I should be able to see the changes in the Home Activity, that means the service calls are to be done again in each of these Fragments, which is why I am doing all this part in onResume().
Required Output is :
When coming back to HomeActivity(that has the tabs) from another child activity, the service calls should be done.
When hitting on Load More button in any of the tab, the service call associated with that fragment or Tab should be done.
When moving between the Tabs, service calls should not be done, instead the data has to be loaded from Database.
Current Output is :
Since I kept all the service calls for those Tabs in onResume() of the associated Fragment, the first and second requirement is met.
When it comes to third requirement, the output is same as the first one i.e., its making service calls which should not happen.
Problem : How to identify if user is moving between the Tabs or if he is coming from child activity. This service calls happening while moving between Tabs is causing performance issues. Please help me with this, I have no idea about how to proceed to overcome this performance issue. Thanks.
Is the behavior similar to the way Activities work? For example with Activities it works like this:
Activity A starts Activity B, while B is on screen, the system is able to remove A from memory if it is needed by the system. Upon pressing BACK, A will be recreated into memory as if it never left in the first place.
I have looked for a clear explanation of what happens memory wise with Fragments and haven't found anything. Does it work the same way? For example:
Activity C has Fragment F in its layout. Then, at some point F is replaced by Fragment G, but F is kept in its back stack.
Will F stay in memory until the C is killed or can it be removed by the system as needed?
Really what I am asking is whether or not I run the risk of running out of memory if I have a back stack of complicated Fragments in a single Activity?
Take a look at this: BackStackRecord.Op.fragment
That is how fragments are stored in the back stack. Note the live reference, neither WeakReference nor SoftReference are used there.
Now this: FragmentManagerImpl.mBackStack
That is where manager stores the back stack. Simple ArrayList, also, no WRs or SRs.
And finally this: Activity.mFragments
That is the reference to the fragment manager.
GC can only collect objects that have no live references (are not reachable from any thread). That means, until your Activity is destroyed (and so, FragmentManager reference is gone), GC will not be able to collect any of the Fragments in the back stack.
Note that when Activity is destroyed and retains state (like when you turn the device to landscape mode), it doesn't retain actual Fragment objects in the stack, only their states - Fragment.FragmentState objects, i.e. actual fragments in the back stack are re-created every time activity gets re-created with retained state.
PS So, in short: Yes, you can run out of memory by adding Fragments to back stack as well as by adding too many views to view hierarchy.
UPD Considering your example, F will stay in memory until C is killed. If C is killed and then resurrected with different configuration - F will be destroyed and reincarnated in a different object as well. So, F's memory footprint is around until C loses state or back stack is cleared.
I'm sorry for not being able to provide you with some official source of information, but I was curious too to see what would happen and decided to test it. And according to my tests, yes, you run the risk of running out of memory.
I had to add an incredible amount of Fragments (more than one hundred) in a for loop for the OutOfMemoryError to happen, but it did happen. And checking my logs, I could see that the onCreate() and onCreateView() methods were called a lot of times but onSaveInstance(), onPause() and onDestroy weren't called at all.
For reference, this is how I added the fragments to the backstack:
getSupportFragmentManager().beginTransaction().add(R.id.scene_fragment_container, mSceneFragment).addToBackStack("FOOBAR").commit();
And the Fragments I added were somewhat simple: an ImageView, an EditText, a couple TextViews, a SeekBar and a ListView.
But unless you are holding a huge amount of data in memory it shouldn't be an issue.
Later I tried adding only 50 to the backstack, killing the app and restarting it. And as I hoped/guessed, all the fragments were restored (and the onSaveInstance() and onPause() methods called) so my lifecycle implementation wasn't the issue that caused the OutOfMemoryError to fire.
From developer.android.com/guide/topics/fundamentals/fragments.html
A fragment must always be embedded in an activity and the fragment's lifecycle is directly affected by the host activity's lifecycle. For example, when the activity is paused, so are all fragments in it, and when the activity is destroyed, so are all fragments. However, while an activity is running (it is in the resumed lifecycle state), you can manipulate each fragment independently, such as add or remove them. When you perform such a fragment transaction, you can also add it to a back stack that's managed by the activity—each back stack entry in the activity is a record of the fragment transaction that occurred. The back stack allows the user to reverse a fragment transaction (navigate backwards), by pressing the BACK button.
Yes you can run out of memory creating too many fragments in a single activity. The fragments will only be destroyed when the containing Activity is.
I'm writing a simple Android app, and I'd like better control over the navigation/relationship between the activities. I don't want my activities to act like android activities...I don't want them to stack up within the Task. I want one Activity (let's call it MainActivity) to be the landing point and always be at the bottom of the stack, and I want only one instance of my second activity (call it SecondActivity) to be above it in the stack...would be nice to reuse it as well. I thought I could get this behavior by making MainActivity be the "main" Activity, and declare them both as launchMode=singleTop. This isn't working at all. I provide navigation between them using menus, so when I go back and forth a bunch of times and back out of the app, I go through the whole stack.
How's the best way to have fine control over the Task's Activity stack? I want MainActivity to always back out of the app, and SecondActivity to always back into a single instance of MainActivity. As well, I'd love to get singleTop working so I would use onNewIntent instead of creating and destroying every time. Using the manifest as well as the intent flag is just not working. Any ideas?
Well, you could always just call "finish()" within whatever Activity is calling another activity after the "startActivity()" call. I would definitely advise against trying to stuff an entire app into two activity classes and try to swap views based on what they're doing. If it's that important to you, just close your activities as you launch new ones (obviously not the MainActivity, though).