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?
Related
For my current project, I will be using this SlidingUpPanel library.
The sliding up panel will host a fragment that will contain application/global level information. This panel will be in every activity in my application. This will be very similar to the way Google Play music works.
My question is, what is the best way to persist the sliding up panel fragment throughout my application? I see myself going about this in two ways...
Storing the fragment inside the Application class and loading it at the start of every activity (somehow, not even sure if this is a possibility).
Storing the data that it will display in the Application class & loading a new instance of the fragment, passing in the persisted data.
Which one of these two ways would be the best? Is 1. even possible? Are there any coding landmines with these approaches?
Storing a fragment to persist throughout the application lifecycle would be pretty unorthodox, mainly because the fragment class should be able to follow it's normal lifecycle events (in this case, mainly onPause and onResume) instead of being stuck somewhere in the application class.
It is definitely common practice to store the data and load it each time you display the fragment. If you want to enable some sort of cacheing or singleton pattern to access the data, it should most likely be with another object that the fragment can access but is not a member within the fragment.
There is a good video from google about leaking views and it touches briefly on the pitfalls of doing some similar to what you're proposing in bullet #1.
I think the structure of your app looks like it should be a single activity where that bar is in it, then the main content is a Fragment that you replace and use addToBackStack on in order to maintain the use of the back button. Otherwise, you are going to have a lot of repeated code with solution 2 (which means a lot of repeated work in the case of bugs etc., not very maintainable), or leak views using solution 1.
More info on providing a proper back implementation
I am creating my app with using fragments. I have something like main activity, it has FrameLayout as root layout to hold fragments.
After much thought I have decided to separate my application logic in several parts, for example : MainActivity is responsible for app basic navigation (MainPageFragment, CategoryListFragment, ProductListFragment, ProductDescriptionFragment), AuthActivity is responsible for autherization, registration (SignInFragment, RegistrationFragment, RecoverPasswordFragment).
A little about my app. If you have recommendation or don't agree with app structure, I would be grateful for any critics.
What is the problem, as you can see my MainActivity has many responsibilities. There are four Fragments now but it can be more in the future.
Lets consider next situation. In my MainActivity I have MainPageFragment and this fragment in turn of course has some views. And on click event I need to change fragment, for instance from MainPageFragment to the CategoryListFragment. In this case I have several ways to handle clicks or other events from framgents.
The most common way is to have activity implements callback interface defined in fragment class as nested class inteface. This approach is quite good and easy to use. But what if my host activity has to handle multiple callbacks from fragments, to say more, there can be more than one callback from single fragment, class(activity) declaration starts growing, class body too. What are another possible approaches to solve this problem.
You can handle all clicks, events directly inside fragment (start activity, replace framgent......) you can do this painless, but for me personally callback approach looks better, but maybe there is nothing bad, and I can use this approach.
Use one or several interfaces for getting information from fragments. For example create class CallbackEvent for holding such info as framgentId, eventType .... Using this approach we can reduce interfaces and methods, but Activity class body can become larger in first approach.
Use something like EventBus pattern to communicate between app components via third party service.
Of course there are some other ways to do this, but I have described most popular.
Please suggest, or just explain how to do you solve this problem in your apps, what approach is better, how to built this communication easy to maintain.
I am grateful for any advice,critics in advance.
If your app becomes more complex using the callback pattern will get messy, especially if fragments need to communicate with fragments. I'd only use that pattern for apps with low complexity (activity, one or two fragments).
Clicks, events etc. should be handled inside a fragment if whatever happens stays within the fragment. Don't replace a fragment from within the fragment, that's the Activity's responsibility. It might look easier to just do a getActivity().someMethod in the fragment but this leads to hard to maintain code. You might understand now what it's doing but will struggle in half a year.
This approach looks messy to me too (similar to 1.)
That's the one I'd recommend. I'm using EventBus (https://github.com/greenrobot/EventBus) but there are alternative implementations like Otto (https://github.com/square/otto) and I've never looked back to the times when I used the callback pattern. Using an EventBus decouples the communication between the different components and your code becomes much simpler and leaner. However you need to be careful with that approach since there are some pitfalls. One is that it gets much easier to communicate from any component to any other component which could lead to even messier code than the listener/observer pattern. Another one is that events are asynchronous compared to synchronous listener calls so you need to make sure you're only receiving the "right" events at the right moment in the component's lifecycle. The main advantages of an EventBus approach are IMO:
A message is always an object forcing the developer to code object oriented compared to the more functional listener method calls
It decouples the different components. Publisher and subscribers don't have to know about each other. Decoupling the components will make your code much leaner and easier to read (and maintain).
It can be used by arbitrary components. E.g. I replaced all LocalBroadcastManager calls by EventBus messages (EventBus is MUCH faster that using a LocalBroadcastManager). Being able to communicate between arbitrary components is especially convenient if the components can't access each other directly (like a Dialog and a Preference object)
I have two rules of Fragment - Activity separation.
One is logic. Anything that deals with View (layout expansion, display, listeners, etc) should go inside a Fragment. Important background processes (http requests, file reading, image processing, etc) should go inside Activity. Part of the reason is explained in my second point:
Lifecycle. Activity's lifecycle outlasts Fragment's. Fragment is also fragile it doesn't even retain its views. And this is the reason Fragment should be decoupled from Activity. Listeners and callbacks are tight coupling and they are the cause of countless null pointer exceptions when some process tries to update a View of a Fragment that has called its onDestroyView. Having said this I'd suggest Publisher - Subscriber pattern like Event Bus where you can plan a message delivery in which it gets digested only when a publisher (which in this case corresponds to Fragment's view) is available.
The numerous click listeners you have are related to how you design your UI. Moving code around doesn't really help much, unless you trim down your layouts.
The Android Developer Guide states that activities are launched via Intents:
Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);
For Fragments, the usual way to display it on the screen is as follows:
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
Why is it that in one case I have to specify a class, and in the other an object? I.e., I would like to use something like
Activity nextActivity = new SignInActivity();
Intent intent = new Intent(this, nextActivity);
startActivity(intent);
Because Activity lifecycle is managed by Android whereas Fragment lifecycle is tied to the Activity in which it is contained.
As mentioned, Activity lifecycle is managed by Android. This is required, among other things, for Android to manage the system resources and also to take care of the back stack.
Fragment, on the other hand, was introduced to modularize and better organize the UI for devices with different sizes. According the the documentation:
Starting with HONEYCOMB, Activity implementations can make use of the
Fragment class to better modularize their code, build more
sophisticated user interfaces for larger screens, and help scale their
application between small and large screens.
To answer the latter part of your question, you can indeed pass the results of an activity to a second activity. But you should never create an instance of an Activity class for that. The right way is to use the startActivityForResult() and send the resulting value to the destination activity through the Intent.
While adding fragment, you are already specifying where exactly to insert that fragment into. So, the ideal way is to,
Create your fragment.
Insert into a layout of your current activity.
Use transactions to remove/manage your fragments, added to the current activity.
In no way, you could launch or use just a fragment, without attaching it to an existing activity.
Android handles Activity life cycle by itself. Just look at the methods of Activity class, they're just like a fill in the blanks. Android calls the shots here. Through these methods it just ask if you want to do something when this activity is created, resumed, paused etc.
The reasons for Android handling activity life cycle internally, are many:
Properly setting up an Activity involves lots of boiler plate code, better let system do it for you. The whole Context and window management is set up for you behind the scenes. Imagine the amount of extra work, if you had to do it for every Activity you created.
Activities are shared, home screen and other applications might want to launch/use them. How would be this possible if they have to call new MyActivity() of some obscure package ? . This is why Activities and other externally invokable components must be declared in application manifest.
Activities from many applications can be parts of an android task ( a piece of work from user's perspective). And are automatically placed/removed/re-arranged on a back-stack. Again, its better Android manage their creation and destruction rather than developers messing with this whole setup.
All user cares is that an Activity must show up when asked for, and just get out of the way if user navigates somewhere else. Android enforces this. Making an Activity appear on its own, or refuse to go away, just because its allowed to be programmed that way, is unacceptable.
Now Fragments , on the other hand are internal. They live inside an Activity and are not accessed from or shared with outside applications or tasks in any way. Fragments are even not a part of application manifest and hence are not exposed outside. Android need not worry about each fragment separately, because fragment life-cycle is bound to that of its parent Activity. Android doesn't care what you do with fragments internally, it can just end the activity and everything inside it is destroyed as well.
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;
I have a similar issue with this one:
Android: Multiple activity instances launched by same intent. Bring one uniquely to foreground?
I need to create a stack of activities, all created by using the same class: it is a class defining a news list, only there needs to be multiple children activities that are also news lists, but from different categories. (I do need to have these activities in a stack)
The trouble is I need to change data on each of these activities after they are shown, but I can't find a way to access each one of these activities separately, since they are all using the same class, so if I used static methods, I would change the data on all these activities at the same time. Ideally, there could be a way to use references of each activity, so that I can access methods on each one separately, but I don't think there is a way of doing this.
I might as well pass parameter IDs when starting each activity, and instantiate objects at the same time, for each activity, and using these IDs later access the respective objects' methods...
Edit to clarify: Let me use an example to what I am trying to achieve. I have an A class and I am using this same class to instantiate multiple activities, in a stack. After the creation of these activities, I need to alter data, say, on one of these activities statically, so by calling A.alterData(); , but not when the activities are created, so there is no way of doing this by starting the activities with different data.. Since there are multiple instances of this class, if I do so, this will result on altering the data on all these activities, that are using the A class. Would I be able to somehow use objects and methods to these objects to alter data on different activities that are using the same class?
any other ideas?
You could use an ActivityGroup. It basically holds a list of activities and you need to control the navigation around them. It sounds like it suits your situation. There are many examples of them that can be found through google.
How I would approach changing the data on the other screens is by using shared preferences. You can store whatever data you need in there, and then (through your activity group) when you change screen, the data is refreshed. This is faster and a little more efficient than restarting the intent every time.
Another way is to change the data in the background without the user noticing. This can be done because an Activity group loads all of the Activity it holds and they are always there in the background, running, unless the developer states otherwise.
You could grab a a hold of the appropriate instance of the class you want to change the data on and then just change it.
Does any of this make sense?
I can elaborate more if needed.
I would supply the parameters to each activity, such as:
intent.putExtra("category", categoryId);
That way you aren't managing too much global state.
About changing the data - if you are talking about refreshing the data from its original source, then you should probably be doing this in the onResume() method of the Activity. Check out the Activity Lifecycle.
This has a few benefits:
you will have access to all of the context of that Activity
you won't have to do something nasty like access another Activity's data
you won't waste time refreshing data the user isn't looking at
Even if you have to make updates to the data, there are ways to make sure each Activity "minds its own business".