How do you think?
I think to create small app and put everything on only one Activity.
Just change the content Views. Get rid off problems with share data,
start from recent apps and couple more.
I know that in that way I can get much more problems, like stackoverflow.
But did someone try it?
My friend and I were making 1st application together and he insisted to make it like that..It was laggy, unstable and it can be characterized as "the worst practice" example..
I don't agree that it runs much faster, I agree that you need to do additional programming, which Android by default would handle automatically if u follow good practice (like BACK pressed) and I am sure that it will lead to a lot of memory leaks, unnecessary memory use, and decrease of performance. All in all it doesn't leave good impression to someone who is using it..
If you are doing it just to avoid sharing data and other "problems" it is much better to invest some time in this topics and try to learn more about them, to start using them in a proper way. When you know framework a bit better you will understand why such ideas of putting everything in one activity is bad.
moral I learned:
It is terrible idea to put everything in one activity, if your application in reality needs more components !!!
Blockquote
Choose your programming companion wisely!
Learn Learn Learn..
good luck ;)
Yes... it's definitely doable. However, it's a really terrible idea for anything other than the most basic apps. I had the same impulse when I was first starting out and built an app that had 5 screens. It quickly became much more trouble than it was worth, and that one activity had SO much code, it was a nightmare.
If you're targeting Honeycomb and > you should just use fragments. It's much nicer.
If your primary motivation for doing this is the complexity of passing data around from Activity to Activity you should consider extending Application and just storing all your persistant data (by that I mean the stuff you need while the app is actually running, not when it's backgrounded) up there.
If you're not doing any substantial interacting with the user and just want to swap out XML views with minimal functionality, you could be ok with the one Activity approach, but for most applications it's just too messy.
Yes, a couple of my first apps were made using exactly this approach. There are some advantages like:
It usually works a bit faster than changing from one activity to another.
You have just one Activity class.
and some disadvantages:
You may confuse yourself if you have too many screens.
You must code the screen changing logic yourself.
This is not considered as usual practice for Android development.
Anyway, this approach works, so it's your decision to use it or not. Hope this helps.
I would suggest you to use fragments. These fragments can be called through one activity. Although I am sure of that simple one activity will do, because I used one activity class for handling fragments, but i was using few more activity class also.
For ex. You can create different fragments and call them in activity like;---
public void onStatusClick(View view)
{
setFragment(new HomeFragment());
}
public void onNotificationsClick(View view)
{
setFragment(new NotificationsFragment());
}
public void onContactClick(View view)
{
setFragment(new ContactFragment());
}
public void setFragment(Fragment fragment)
{
FrameLayout framelayout = (FrameLayout) findViewById(R.id.frme_container);
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(framelayout.getId(), fragment).commit();
}
If its the kind of project you can abandon after handover then you can get away with using one class
If however, your client is long term and will be requesting future changes and or extensions then it best not to dump everything in one class. Changes are hard to anticipate and you may find yourself refactoring everything if its all in one activity.
I agree with all of positives of using Activities and Fragments. My card-game app was initially written with 1 activity and 7 views. Eventually I refactored the application to use 7 Activities. The start up time of the application dropped significantly. However, when using 7 views, the app never had memory problems, and once loaded, was lightening fast between screens.
So my conclusion is that using views vs. activities (or fragments) is more of a trade-off than the slam-dunk presented by other answers. Views take longer to initially load, but are super-quick to swap. Activities are modular and are only loaded when needed. Memory is less and load time is quicker when using Activities, but the trade off is more complicated code and slower transitions between screens.
Finally, you don't have to use an all or nothing approach. You can always mix both solutions into your application, which is what I finally settled. I use Activities for screens that are infrequently used and Views/ViewSwitcher for the main 2-screens that are frequently used. Its the best of both worlds.
Related
In Big Nerd Ranch's Android Programming, it advocates AUF (always use fragment). Specifically, it has this to say:
"...adding fragments later can be a minefield. Changing an activity to
an activity hosting a UI fragment is not difficult, but there are
swarms of annoying gotchas. Keeping some interfaces managed by
activities and having others managed by fragments only makes things
worse because you have to keep track of this meaningless distinction.
It is far easier to write your code using fragments from the beginning
and not worry about the pain and annoyance of reworking it later, or
having to remember which style of controller you are using in each
part of your application."
The book doesn't expound on what the annoying gotchas are. What are the gotchas?
Biggest of all is Context. as Activity is driven by Context (not directly). when you need context in an activity you have it there all the time. same is not with the case with fragment, in fragments you can call getActivity method to get parent activity but when porting code from Activity to fragment you have to deal with supplying it everywhere.
Another problem could be life cycle of Activity. where activity lifecycle is simple and functions like onResume, onPause are pleasure to use same can not be said for fragments. Adapting things which were designed for Activity life cycle into fragment life cycle can be nightmare.
Having said that, if things are not complex and you need to handle only one task it is safe to go with activity to begin with.
Because you are at the very start of decision making, I want to leave this here:
https://corner.squareup.com/2014/10/advocating-against-android-fragments.html
On the bottom line, this blog says that the lifecycle of a fragment is too complicated and therefore it advocates against using fragments, in favor of an Model-View-Presenter-Pattern
A personal note: the wordy comment from CommonsWare hits the spot. I blindly used fragments because they were there and I never questioned them. But after reading the above article, I've changed my mind.
PROBLEM:
I have an Android application that allows a user to browse to a user's profile ViewProfileFragment. Inside ViewProfileFragment a user can click on an image that will take him to StoryViewFragment where various users' photos show up. It is possible to click on a user profile photo that will take them to another instance of ViewProfileFragment with the new user's profile. If a user repeatedly clicks on user's profiles, clicks an image that takes them to the gallery then clicks on another profile the Fragments stack up in memory quickly causing the dreaded OutOfMemoryError. Here is a diagram flow of what I am describing:
UserA clicks on Bob's profile. Inside Bob's profile UserA clicks on ImageA taking him to a gallery of photos of various users (including Bob's). UserA clicks on profile of Sue then on one of her images - process repeats, etc, etc.
UserA -> ViewProfileFragment
StoryViewFragment -> ViewProfileFragment
StoryViewFragment -> ViewProfileFragment
So as you can see from a typical flow there are lots of instances of ViewProfileFragment and StoryViewFragment piling up in the backstack.
RELEVANT CODE
I am loading these in as fragments with the following logic:
//from MainActivity
fm = getSupportFragmentManager();
ft = fm.beginTransaction();
ft.replace(R.id.activity_main_content_fragment, fragment, title);
ft.addToBackStack(title);
WHAT I'VE TRIED
1) I am specifically using FragmentTransaction replace so that the onPause method will be triggered when the replace takes place. Inside onPause I am trying to free up as many resources as I can (such as clearing out data in ListView adapters, "nulling" out variables, etc) so that when the fragment is not the active fragment and pushed onto the backstack there will be more memory freed up. But my efforts to free up resources is only a partial success. According to MAT I still have a lot of memory that is consumed by GalleryFragment and ViewProfileFragment.
2) I've also removed the call to addToBackStack() but obviously that offers a poor user experience because they can't traverse back (the app just closes when the user hits the back button).
3) I have used MAT to find all of the objects that I take up a lot of space and I have dealt with those in various ways inside the onPause (and onResume) methods to free up resources but they are still considerable in size.
4) I also wrote a for loop in both fragments' onPause that sets all of my ImageViews to null using the following logic:
for (int i=shell.getHeaderViewCount(); i<shell.getCount(); i++) {
View h = shell.getChildAt(i);
ImageView v = (ImageView) h.findViewById(R.id.galleryImage);
if (v != null) {
v.setImageBitmap(null);
}
}
myListViewAdapter.clear()
QUESTIONS
1) Am I overlooking a way to allow a Fragment to remain on the backstack but also free up its resources so that the cycle of .replace(fragment) doesn't eat up all of my memory?
2) What are the "best practices" when it is expected that a lot of Fragments could be loaded onto the backstack? How does a developer correctly deal with this scenario? (Or is the logic in my application inherently flawed and I'm just doing it wrong?)
Any help in brainstorming a solution to this would be greatly appreciated.
It's hard to see the whole picture (even tho you have shown us a lot of information), without concrete access to your source code, which I'm sure it would be impractical if not impossible.
That being said, there are a few things to keep in mind when working with Fragments. First a piece of disclaimer.
When Fragments were introduced, they sounded like the best idea of all times. Being able to display more than one activity at the same time, kinda. That was the selling point.
So the whole world slowly started using Fragments. It was the new kid on the block. Everybody was using Fragments. If you were not using Fragments, chances were that "you were doing it wrong".
A few years and apps later, the trend is (thankfully) reverting back to more activity, less fragment. This is enforced by the new APIs (The ability to transition between activities without the user really noticing, as seen in the Transition APIs and such).
So, in summary: I hate fragments. I believe it's one of the worst Android implementations of all time, that only gained popularity because of the lack of Transition Framework (as it exists today) between activities. The lifecycle of a Fragment is, if anything, a ball of random callbacks that are never guaranteed to be called when you expect them.
(Ok, I am exaggerating a little bit, but ask any Android seasoned developer if he had trouble with Fragments at some point and the answer will be a resounding yes).
With all that being said, Fragments work. And so your solution should work.
So let's start looking at who/where can be keeping these hard references.
note: I'm just gonna toss ideas out here of how I would debug this, but I will not likely provide a direct solution. Use it as a reference.
WHAT IS GOING ON?:
You're adding fragments to the Backstack.
The backstack stores a hard reference to the Fragment, not weak or soft. (source)
Now who stores a backstack? FragmentManager and… as you guessed, it uses a hard live reference as well (source).
And finally, each activity contains a hard reference to the FragmentManager.
In short: until your activity dies, all the references to its fragments will exist in memory. Regardless of add/remove operations that happened at Fragment Manager level / backstack.
WHAT CAN YOU DO?
A couple of things come to my mind.
Try using a simple image loader/cache lib like Picasso, if anything to make sure that images are not being leaked. You can later remove it if you want to use your own implementation. For all its flaws, Picasso is really simple to use and has come to a state where it deals with memory "the right way".
After you have removed the "I may be leaking bitmaps" problem out of the picture (no pun intended!), then it's time to revisit your Fragment lifecycle. When you put a fragment in the backstack, it's not destroyed, but… you have a chance to clear resources: Fragment#onDestroyView() is called. And here is where you want to make sure that the fragment nullifies any resources.
You do not mention if your fragments are using setRetainInstance(true), be careful with that, because these do not get destroyed/recreated when the Activity is destroyed/recreated (e.g.: rotation) and all the views may be leaked if not properly handled.
Finally, but this is harder to diagnose, maybe you'd like to revisit your architecture. You're launching the same fragment (viewprofile) multiple times, you may want to consider instead, reusing the same instance and load the "new user" in it. Backstack could be handled by keeping track of a list of users in the order they are loaded, so you could intercept onBackPressed and move "down" the stack, but always loading the new/old data as the user navigates. The same goes for your StoryViewFragment.
All in all, these are all suggestions that came from my experience, but it's really hard to help you unless we can see more in detail.
Hopefully it proves to be a starting point.
Best of luck.
It turns out that fragments share the same lifecycle as their parent activity. According to the Fragment documentation:
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.
So the step that you took to clean up some resources in onPause() of the fragment wouldn't trigger unless the parent activity pauses. If you have multiple fragments that are being loaded by a parent activity then most likely you are using some kind of mechanism for switching which one is active.
You might be able to solve your issue by not relying on the onPause but by overriding setUserVisibleHint on the fragment. This gives you a good place to determine where to do your setup of resources or clean up of resources when the fragment comes in and out of view (for example when you have a PagerAdapter that switches from FragmentA to FragmentB).
public class MyFragment extends Fragment {
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
//you are visible to user now - so set whatever you need
initResources();
}
else {
//you are no longer visible to the user so cleanup whatever you need
cleanupResources();
}
}
}
As was already mentioned you are stacking items up on a backstack so it's expected that there will be at least a little bit of a memory footprint but you can minimize the footprint by cleaning up resources when the fragment is out of view with the above technique.
The other suggestion is to get really good at understanding the output of the memory analyzer tool (MAT) and memory analysis in general. Here is a good starting point. It is really easy to leak memory in Android so it's a necessity in my opinion to get familiar with the concept and how memory can get away from you. It's possible that your issues are due to you not releasing resources when the fragment goes out of view as well as a memory leak of some kind so if you go the route of using setUserVisibleHint to trigger cleanup of your resources and you still see a high-volume of memory being used then a memory leak could be the culprit so make sure to rule them both out.
I have been researching this for about an hour and cannot figure out whether to use fragments within an activity or start a new fragment activity.
Some sites make it sound as if you should have 1 activity and EVERYTHING else is a fragment. Is that the more proper way now? I can't figure out when you use an Activity (or fragment activity) and when you use a fragment.
I have an app for a conference with:
-Speakers (and sub views/activities/fragments) for each speaker.
-Schedule (different sections for each day)
-General info
-Sessions (different sections for each session).
So do I have 4 activities each with their own fragments or do I just use 1 activity with fragments and nested fragments?
You could do it either way, but generally it is best to use an Activity (or FragmentActivity) for each "screen".
If the user sees your app as logically a single screen that has little panels appearing/disappearing for different kinds of data, then use one activity with a lot of fragments. If the user sees it as "going to different screens", then you probably want multiple activities.
If you go with the one-activity-many-fragments model, you may find that your activity's code gets really complicated dealing with all the possible configurations of fragments. That is a good sign that you may want to split it into multiple Activities. Similarly, if you go with the many-activities model, but find that things get complicated as you pass shared data between activities, consider merging the activities.
Converting from Activity to FragmentActivity is as simple as changing the extends and nothing else needs changing.
My conclusions:
I stopped using Activity and only use FragmentActivity as it is more flexible and more up to date and backwards compatible (Using the support library).
If the FragmentActivity has a component that is large enough to be a standalone component, or needs to be one, then I make it as Fragment.
I haven't come across something that would require a complete separate activity to be within another activity, but that should only be used if that component is large enough and completely standalone enough to need an activity for itself.
I don't fully understand your app to be able to make a specific call on which you should use, if you want my opinion, can you provide more details on what you are working on and how are those components connected.
Regards
Another consideration in choosing a more decomposed architecture (many Activities) might be the cost of destruction / creation in the Activity Lifecycle. Do you plan to use Explicit/Implicit intents to leverage existing apps? More death. So, you might have only one activity in a dispatch oriented model and clearly see your apps logic in one place, but how much state will you have to save/restore? Are there performance penalties for re-inflating or populating data resources?
Android newbee here, I have some code that I want to run when my android app first starts up. It checks the version of the local database and downloads a new version if the current version is out of date. I have been sticking it in the oncreate of my first activity, pretty sure there has to be a better place to put this. Any recommendations of somewhere I can put it where it will get called once on startup?
You can write a custom Application class (extend from android.app.Application). Override onCreate to specify what happens when the application is started:
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
// Do something here.
}
}
You'll then need to register your custom class in the manifest file:
<application ... android:name="fully.qualified.MyApplication">
Edit:
In response to David Cesarino, I disagree with the purpose of the Application class. If you rely on the Activity's onCreate, then what's to stop it from becoming the same huge class of miscellaneous purposes... if you need something to happen when the application starts, you have to write that code somewhere; and the Activity would probably become more cluttered because you have to perform Activity specific logic in it as well. If you're worried about clutter, then separate the logic into other classes and call them from the Application. Using the SharedPreferences to determine whether or not the logic should execute seems like more of a work-around to a problem that's already been solved.
Dianne Hackborn seems to be referring to data, not logic, in which I totally agree. Static variables are much better than Application level variables... better scoping and type safety make maintainability/readability much easier.
First, look at the Activity lifecycle.
Answering your question, you could put code in any of those "start-up" methods, depending on what you want to do and, mostly important, when you want to trigger that. For what you asked, onCreate is the reasonable place.
I have been sticking it in the oncreate of my first activity, pretty sure there has to be a better place to put this.
And why is that? Any code has an entry point, right? In Android Activities it just happens to be onCreate (again, see above link for the full details). Besides event handling, which are responses to events happening outside the main sequence of calls, you put stuff in onCreate.
If you're concerned about the method becoming huge, then that's another problem. Abstract your code better, I say. For checking preliminary stuff, people generally provide a "Loading" activity, before starting the main activity of the app.
edited:
This is a follow up to what drumboog proposed, since my comment started to grow in complexity to be "just a comment".
Personally, I'd avoid extending the Application class for the sole reason of executing code early on, more so a code that is not that sensible in priority (versioning databases). The Application class is mostly used as an easy way to persist state between Activity'ies, not as a way to "do everything". In short, I feel the Application class is commonly abused.
For what you want, you could perfectly achieve that calling code in Activity onCreate. That reduces complexity, because I've seen people stuffing Application until it becomes a huge class of miscellaneous code purposes. And that's a no-no for maintenance, with logic problems of its own.
Besides, if you truly want another solution, completely disassociated with the UI, you should think about implementing a Service instead (but I don't think it's necessary for just that).
Both of those concerns were previously addressed by Dianne Hackborn (or what I got from her message).
I want to reuse the same view object (not the view class, or the xml file, I mean the object in the memory) in different Activities.
I almost had this done. The thing is, of course, the context.
I tried with the application context. It almost worked, but then when I click on the view I am transmitting between different activities, and try to start another application from it (or link) it crashed. (I don't remember the exact crash, but I'll dig it, if you need it).
I tried with some activity, that I didn't mind leaking once, and giving it as a Context. It worked, actually everything worked, until I began to get weird exceptions in ViewFlipper.
My question is, is this reusing really possible, and how to do it stable? Have you got any experience with that?
Thanks A LOT in advance,
Dan
I'm keeping in mind that you can afford to leak 1 activity, as this is the only solution I know:
Declare a static view, say myAdView in your 1st activity (in which you are requesting ad). Now you can ad and remove this myAdView in every activity transation. Ofcource you will have to maintain seperate LinearLayouts for ur ads in seperate activities, where we will add/remove the myAdView
eg. Suppose you are going from activity A to B, then in A's onPause remove myAdView:
private LinearLayout layoutAd;
layoutAd = (LinearLayout) findViewById(R.id.layout_ad); // from A's xml
protected void onPause() {
super.onPause();
layoutAd.removeView(FirstActivity.adBannerView);
}
and in B's onResume add the same (FirstActivity's) myAdView:
private LinearLayout layoutAd;
layoutAd = (LinearLayout) findViewById(R.id.layout_ad); // from B's xml
protected void onResume() {
super.onResume();
layoutAd.addView(FirstActivity.adBannerView);
}
Hope this solves your problem to some extent.
Why don't you use Fragments?
http://developer.android.com/guide/topics/fundamentals/fragments.html
I think your use case is perfect for this.
This isn't really possible in the form you are asking. The views in an activity must be inflated at load time, copying/referencing them in-memory is unlikely to work how you want it to.
Instead, you should look to building the view in each activity you need it, and transferring just the data you need to populate it instead.
If you are trying to improve the performance of your app, I would recommend looking for ways to simplify your view, rather than violating the activity lifecycle.
Update:
Since you've revealed the purpose behind this question (intercepting served ads from a third-party library), I suggest you first contact the company and check the terms of use. If they permit the use of their service while bypassing the View code, then they might be able to provide you with a lower-level API for displaying the ads as you see fit.
If such use is not permitted, consider the fact that they might block your account (and withhold payment) for mis-use.
If you still want to go ahead: DON'T hack away at the Android UI patterns to make this work. Extract the ad images from the third-party library server-side (i.e. building a simple hosted Java webapp with cache store and a REST API) and serve the ads to your Android app from this "man-in-the middle" service. I certainly do not endorse this method, however.
I accept you are seeking some penultimate technical solution for your approach, but I genuinely think it is the approach itself that is the problem here. If I was in your position, I would start to look for other Ad serving solutions that better fit my requirements, as well as contacting the third-party to see if I can pay for more customised integration. Anything involving transferring inflated Views between activities is doomed to constant maintenance problems, if it works at all.
I'm in the same case as Danail. The thing is not about to hack de Ad provider, but that if you want to show a banner through different activities it's a best practice in advertising not to reload it every time you change the activity, because you do more impressions so you CTR (Click Through Ratio) will decrease. You'd rather reload the banner at the time rate you fix, independently of activity changes.
I think the right way to do that would be, as NeTeInStEiN says, using fragments. You could have a unique activity composed by different fragments. In one of the fragments, for example at the bottom, you'd have the banner and you'd load it actually once. Then on the bigger area on the top (let's say we are on a handset) you'd place different fragments, one at a time, that would correspond to your existing activities. When you'd normally "change" the activity, now you'd just change the "main" fragment, but the banner fragment will stay there unchanged.
The main and BIG problem about this approach is that you need to design you app this way from the beginning, because changing the app model from several activities to one activity with several fragments is quite a big code change... :.(
So I understand that, for implementation costs, one could try to "carry" the view from one activity to another. But as I saw in other responses, it's really not recommended and a troublesome way...
If you want a variable to be used within multiple activities then best practice for it is to put them in a separate class (can be named as Constants or MyVars) as static variable and use them in any activity you want as like Constants.SavedVar or MyVars.SavedVar as below is code example.
public class MyStaticVars {
public static Context myContext;
}
// First Activity where you want to save a specific context
MyStaticVars.myContext = ContextToBeSaved;
// Any Other Activity where you want to reuse that context
priviousContext = MyStaticVars.myContext;