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).
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
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.
I'm new to this and I'm sorry if this is a really dumb question. I'm just trying to clarify things. My book says I can retrieve application context for process by using the getApplicationContext() method. I just really don't know where to type this or what to do with any of it. I can go to the hierarchy but what do I do with all the script there. Also where would I write Activity Callbacks, in the main.xml? An exercise wants me to add a logging tag to my project but I'm not sure how to do this. The exact text says:
"Within the onCreate() callback method, add an informational logging message, using the Log.i() method."
and another exercise says to:
"Implement some of the Activity callback methods in addition to onCreate(), such as onStart(). Add a log message to each callback method and then run the application normally".
As these seem like basic questions, can someone please help me.
I am using the Android SDK, and Eclipse. I have made the Hello World application, but I have no idea what to do with Context or Retrieving resources. Please help!
The first rule I would give you: if you don't know why you need it, you probably don't need it. Use your activity object as the Context when you need a context.
The callbacks you talk about are on the Activity class. The Application Fundamentals describes what an Activity is: http://developer.android.com/guide/topics/fundamentals.html#Components
The only time you want to use getApplicationContext() is when you need a Context that exists outside of the lifecycle of an Activity class (or other component). You'll want to find documentation on specific cases where this is desired, there is a lot floating around. For example this one is part of the Android documentation: http://android-developers.blogspot.de/2009/01/avoiding-memory-leaks.html
For the tasks you're working with here, you'll be using the Java code that defines the behavior of the application, not the XML files that define resources and layouts or the AndroidManifest.xml file that declares basic application properties.
If you're working with Hour 3 of the Sam's Teach Yourself... book, then you need to open the src\com.androidbook.droid1\DroidActivity.java file. In general, you would need src\<package-name>\<class-name>.java. When you open that file, you'll see a class (in this case, DroidActivity) that extends Activity and already has the onCreate() callback method. Anything that you want to happen during onCreate() goes inside that method. Other callback methods can be added inside the activity class. To see an example that has all the lifecycle callbacks (but doesn't do anything in them), look here.
A logging tag is just a string. You can declare it, for example, as a private static final String inside the activity class.
If there's confusion about where methods belong, where and how to define variables or constants, how to call methods, how to use classes, and so forth, then it might be best to go through an introductory Java text before starting with Android. There are plenty of free resources available for that.
I read up on how Android handles "configuration changes" - by destroying the active Activity.
I really want to know from Android Team why this is. I would appreciate an explanation on how the reasoning went, because I don't understand it. The fact that it acts in that way puts us all, as I see it, in a world of pain.
Lets assume you have a Activity which presents a number of EditText:s, checkboxes etc. If a User starts to fill that form with text/data and then changes orientation (or get a Phonecall), then all input the User made is gone. I haven't found any way to preserve state. That forces us to make extremely painful coding to not lose all data.
As I see it, you need another "non-Activity" class (or "value-holding" class perhaps) that has one field for each "form element" (EditText, checkbox etc).
For every single "form element" that exists, you then need to attach an Event like "onChanged" (or onTextChanged or something like that) that updates the corresponding field in the "value-holding" class to make sure that for every single character you type (in a EditText for example) is saved at once.
Perhaps you can use some listener (like "onDestroy" or something) and then fill the value-holding class with data.
I have also found this piece of info where they talk about using Bundle, onSaveInstanceState and onRestoreInstanceState, but that also mean that the programmer has to manually save and then later put back the values in the correct place? This approach is a bit less messier than my suggestions above, but still not very nice.
Can someone tell me that I am totally wrong and that this is not how it works and that I totally missed some vital information?
You should read the Application Fundamentals (specifically, Activity lifecycle). Since Activitys must be able to handle being killed at any time due to memory contraints, etc. it's just a cleaner way to handle rotations without adding too much complexity - instead of checking every resource for an alternate resource, re-structuring the layout, etc. you just save your essential data, kill the activity, re-create it, and load the data back in (if you're willing to deal with the extra complexity of managing this yourself, you can use onConfigurationChanged to handle the configuration change yourself.) This also encourages better practices - developers have to be prepared for their Activity to be killed for orientation change, which has the (good) consequence of being prepared for being killed off by memory contraints also.
The contents of an EditText will be saved for you automatically when rotating the screen if you put an android:id attribute on it. Similarly, if you display dialogs using Activity#showDialog, then the dialogs are reshown for you after rotating.
on why part - short answer - because you might have resources that needed to be changed as you've rotated the phone. ( Images, layout might be different, etc )
On save - you can save you stuff to bundle and read it back.
#Override
protected void onSaveInstanceState(Bundle outState) {
String story_id = "123"
outState.putString(ContentUtils.STORYID, story_id);
}
or you can use onRetainNonConfigurationInstance () as described here
http://developer.android.com/reference/android/app/Activity.html#onRetainNonConfigurationInstance()
Finally if you don't have anything you want to handle during rotation - you can ignore it
by putting this into your activity in manifest
android:configChanges="keyboardHidden|orientation"
In general, i would read trough article from url above couple of times, until lifecycle is crystal clear.
#Alex's approach above pointed me to a really, really useful solution when using fragments:
Fragments usually get recreated on configuration change. If you don't wish this to happen, use
setRetainInstance(true); in the Fragment's constructor(s)
This will cause fragments to be retained during configuration change.
http://developer.android.com/reference/android/app/Fragment.html#setRetainInstance(boolean)