I'm trying to avoid having gigantic activity classes that are hard to follow, but the platform seems to be making it hard. Doing almost anything requires a activity or context - these can be stored away in a helper class, but unfortunately calls like startActivityForResult, for example, don't take a sperate listener but always call back on the same activity on an override with a supplied integer code - so this means that seperation of concerns is hard - the main activity needs to know about the helper class and dispactch to the helper class based on an request code - and of course, that request code needs to be unique, so that's a leaky abstraction as well. Why not specify a listener for every call thus avoiding the dispatching and need for unique request codes? Any other ways to slice this?
thanks
In API level 11 and higher, you can use Fragments.
Specifying a listener would be difficult since it would require passing an object to other processes in the Android environment- remember that activities can be called from one application to another.
How is using request codes making your activities "huge" in a way that listeners wouldn't? Activities should make use of classes defined elsewhere to do more most of the labor, let your activities pertain primarily to UI tasks.
Related
What is the use of Activity without UI? I have a MainActivity where I feel the code is too long and I was thinking about possibly creating a separate Activity without UI for each task and call it in my Main Activity (or use a Headless Fragment maybe?) in order to keep my code maintainable. Is that a bad approach? How do you manage relatively long code in one Activity?
That's a bad idea. It makes sense to break an activity up into multiple classes if its too large/too complicated. If those pieces have a UI, that's basically a fragment. If they don't, they should be some other class. But there's no reason to make them Activities- they're just classes.
THere's very few places where it makes sense to have a headless Activity. Almost all of those places are where Android requires you to start a context but you're not sure which one to start up yet (for example a headless activity that does url routing that's too complex to put into the manifest).
There a lot of things wrong with your questions.
First... An Activity without UI, then doestn need to be an Activity.
Second, you must know what is a class and why we use classs.
Third, When you have long code, maybe your logic is bad, you can separate en in other class the code, example: Adapters, Helpers, Task, etc.... the same activity and code must give you and idea how separte correctly if you know the concepts, please, maybe if you post the code we can help you more.
For example, let's say my Rest adapter created with Retrofit lives inside Application class.
I would love to get it inside the Activity, so I write the following code:
public class MainActivity extends Activity {
#Inject MyRestAdapter mRestAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((GlobalApplication) getApplication()).getComponent().inject(this);
}
}
Granted, it will make the job done. But...
How is this different from calling getApplication(), and then explicitly yank the MyRestAdapter to MainActivity? Yes, Dagger 2 will simplify the setup by automatically getting everything to the Activity, but you still need to explicitly tell from where you need these dependencies, and that, if I understand correctly, defeats the whole purpose of DI. Am I right to say that Dagger 2 is "semi-automated service locator", or it's just the tutorials that misled me, and there is correct way to inject dependencies with Dagger 2 into the View or Activity from Application?
I've been experimenting with Dagger and it definitely seems to blur the lines between service locator and dependency injection. This is at least true when used with Android activities. With the current version of Dagger, it is possible to write AndroidInjection.inject(this) in an activity's onCreate method. That's basically like saying "find all the services I need and inject them into me." So Dagger is a combination of a some central/global service locator that knows where to get the services and an injector that knows where (i.e. which instance variables) to put those services in the activity. It seems that Android activities force reliance on some kind of singleton/global object.
There is no 1 "purpose of DI" but definitely one of them is to separate the configuration from what actually requests the configured objects. The idea is that your higher-level objects, such as Activitys in Android, can request all of the objects it needs without worrying about where they come from, how they are constructed, and any semantics about their relationships. Similar to how an Activity doesn't deal with drawing text to the screen (and instead delegates that to a TextView[0]), DI helps keep your objects from knowing too much that is not relevant to the actual logic they need to perform.
Inherent in the "semi-automated service locator" you describe is static analysis and error handling. As applications become larger, it becomes even harder to get manual-DI correct. Dagger helps make your code less error-prone (and less tedious to maintain).
Consider the case where you have an internal version of your app for employees, where you log lots of information about how they use the app to make sure you can identify any issues. In your actual product, however, you don't want to track personally identifiable information like that when it's not necessary. Now, your MainActivity needs an AnalyticsLogger - which one should it get? The more cases you have, the easier it is for Dagger to help piece things together than for you to do it yourself.
[0] which delegates to a Paint object
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 have an app with multiple activities and multiple layouts. However, one piece of layout is included on several activities. I also have a thread which updates this layout. However, when i switch activity it doesn't work. Since the layout is included the elements have the same ID's, shouldn't it just work? Or do I really need to fetch an object for each element in the layout and feed it into my thread in order to make it update the elements in a new activity?
You should run the update code for each Activity/View, although the XML included is the same, each is a different instance.
My suggestion is on Restart verify is there is any modification to do in each activity, a simple way is to each Activity extend a BaseActivity that has this code.
I include a layout for adverts in my app, but on each activity that uses it, the adverts need to be reloaded.
If I call an activity from one that is using the same included layout when I go back to the previous activity it's still there.
I guess this is what you are seeing....
So you can also save that data inside sharedPreferences (if it is little data and primitive objets or parceable objects).
Also you can extend the Application class and store the data there and update every activity inside the onResume() method. that i believe is the best way to handle this. and this is quite simple to do.
Ask google about extending the application class and he will provide tons of results on how to do it. its an easy way to pass data between activities and/or keep a reference to a single object which you will use throughout the app. Just be carefull to clear it when you wont need it anymore because it will stay in existance untill the application is finished() (which comes with the application extension living thru the whole application lifetime).
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".