Why Is OnCreate Preferred To Do All The Main App Tasks? - android

Why Is onCreate() Preferred To Do All The Main App Tasks? Why not onResume() or onStart()? Why only onCreate()? I tried to do the main tasks like binding findViewById() setting text to text views and a lot more. They all work fine. When why do we always are preferred to do that task in onCreate()?

OnCreate serves as the first entry point into your activity, so logically it makes sense to do as much of the initialization here as possible. Often times there are cases when things need to get configured with higher priority - crash reporting services, dependency injection etc. where this would get escalated to a custom application class.
according to the docs
protected void onCreate (Bundle savedInstanceState)
Called when the activity is starting. This is where most initialization should go: calling setContentView(int) to inflate the activity's UI, using findViewById(int) to programmatically interact with widgets in the UI...
so, I suppose it is fair to say that most initialization will get done inside of onCreate, which usually means that if you were to place this into a lifecycle method which could get executed repeatedly, that could be considered redundant as you'd be assigning the same values to variables repeatedly, unless that's something you actually want to do.
However, lazy initialization is also a concept to keep in mind, being able to initialize something inside of onCreate doesn't always mean that you should, it is often times better to delay initialization until you actually need the instance.
regarding
I tried to do the main tasks like binding findViewById() setting text to text views and a lot more. They all work fine.
they definitely would, findViewById can always be used and isn't limited to being inside of onCreate, in fact the result of findViewById doesn't even have to be assigned to a variable for you to be able to use it

Related

Invalidate is failing to call onDraw when returning to an activity that has a custom view

I have inherited some code hence I don't have true freedom to change it. :(
I have a main activity, from which other activities (I will refer to these as sub activities from now on) are called. Whenever one of these completes, it calls finish and returns data to the main activity.
Each activity (including the main one) has a bar on the top that displays a custom view. The custom view contains a canvas which has a drawing that is dependant upon the state of the network.. i.e. wifi/mobile etc...
Since that 'state' data never changes, it's held within a singleton and the view gets data from the singleton to define what it draws. That is working with no issues, i.e. the data is always as I expect it.
When I first launch the MainActivity, as the network changes, the data changes and each call to 'invalidate' the view receives a system call to 'onDraw' as I would expect.
In each of the sub activities the same is again true.
Upon finishing a sub activity and returning to the mainActivity, calls to invalidate no longer cause a call to onDraw to occur.
I have looked at this for quite a while now and just cannot figure out what is going wrong.
In my constructor I have:
setWillNotDraw(false);
Whenever the data changes the following methods are called:
invalidate();
requestLayout();
Now, there's one more thing... upon returning to the activity at that immediate point, I refresh and this DOES draw correctly, i.e. invalidate does trigger an onDraw call... any subsequent network changes (which are propogated) fail to result in the onDraw call.
I'm wondering if this is to do with the view somehow being detached. I can see that 'onDetachedFromWindow' is called, however the trigger for this is the destruction of the subactivity, hence I don't see why that should affect the MainActivity but it's the only thing I can think of.
I'm hoping I've provided enough information for someone to help me...
Well, in the end my answer has very little to do with the question and I guess this is an example of how an issue can be solved by going back to absolute basics and checking for the obvious.
My activities all inherit from an abstract activity. Within that activity there is an instance of the view. The views in which I was having trouble were using that declaration as opposed to having their own instance, hence behaviour from one activity was then affecting another inadvertently.
So, if I'd been able to post up all the code, I'm sure someone else would have spotted this but, unfortunately I couldn't in this instance.
Still, whilst this posting doesn't provide a resolution that will help others, maybe it does say... step back and check the obvious first!

Why is there no Android API for getting the current Activity?

The question, How can I get the current Activity? has been asked dozens of times on Stackoverflow and other sites and there are many proposed approaches. However, all of them have drawbacks in one form or another.
In this posting, I am assuming that there is no solution provided for this in Android's APIs, e.g., something like: Application.getTask().getRootActivity().
Wouldn't it be nice if there was :-)?
So, to be clear, I'm not asking for an answer to How can I get the current Activity?
Instead, I am asking for the reason that such a capability has not been provided. Given that each running app has a task (assuming that the task hasn't been emptied) and each such task has a root Activity, it would seem to be easy to provide access to that root Activity.
The fact that that such access is not provided, when it is so clearly desired, implies to me that there is something fundamental about the Android architecture that I don't understand.
What is it that I'm missing? Why is this information not provided by the Android APIs?
For background, here is a section summarizing some of the approaches that have been proposed. I found the following two links particularly informative (each of the approaches below is presented at one or both of the links).
Links
How to get current foreground activity context in android?
Android: How can I get the current foreground activity (from a service)?
Approaches
Static Hook
Reflection
ActivityManager
Other (Instrumentation, AccessibilityService, UsageStatsManager)`
ActivityManager
The ActivityManager approach only provides the name of the Activity class, not the current Activity instance. E.g., for a Context instance c:
c.getSystemService().getActivityManager()
.getAppTasks().get(0).getTaskInfo()
.topActivity().getClassName()
Reflection
My favorite is reflection, as proposed by _AZ, but that approach is fragile, given that it relies on internals. What I would like to see from Android is this approach provided via a standard API that developers could then safely rely on.
Static Hook
The most common approach is using a static hook to save a reference to the currently running Activity. The hook can be either per-Activity or per-Application. Memory leaks can be avoided by saving/destroying the hook's value (e.g., in onCreate()/onDestroy(), onStart()/onStop(), onPause()/onResume()). However, issues can arise when multiple Activities are involved (e.g., due to overlapping lifecycles -- see below).
I implemented a static hook approach which does the following (to be perfectly transparent, I haven't implemented #1 yet -- I am currently using a per-Activity static hook, which is a bug).
Provides a class that extends Application to provide the hook. The hook contains a Stack; each node in the stack is a simple ActivityInfo class which contains a reference to an Activity instance as well as the state of that instance (CREATED, STARTED, RESUMED).
Provides a class called ActivityTracker that extends Activity. I then extend each of my Activities with ActivityTracker. ActivityTracker uses its lifecycle callbacks to push/pop itself to/from the stack and to update its state -- my other Activities don't have to do anything.
In theory, this would allow me to always know the full state of the task's back stack -- the full set of Activities, including the root Activity, as well as their current state. In practice, however, there is a twist -- when one Activity starts another Activity, their lifecycles overlap. During that period, peeking at the stop of the stack can yield an unexpected Activity instance.
From: https://developer.android.com/guide/components/activities/activity-lifecycle.html#soafa, "Coordinating activities":
Here's the order of operations that occur when Activity A starts
Acivity B:
Activity A's onPause() method executes.
Activity B's onCreate(), onStart(), and onResume() methods execute in sequence. (Activity B now has user focus.)
Then, if Activity A is no longer visible on screen, its onStop() method executes
Of course, this could be managed also. The bottom line is that we do have a global context available for storing information (the Application) and we do have full information about Activity lifecycle transitions, so with enough effort I believe that this static stack-based approach could probably be made pretty bullet-proof.
But in the End
But in the end it feels like I am simply rewriting code which probably already exists internally for managing an Activity back stack, which is why I ask (in case you've forgotten):
Why is there no Android API for getting the current Activity?
UPDATE
In this update, I'll summarize what I've learned from this thread and my own experiments and research. Hopefully, this summary will be useful to others.
Definitions
I'm going to use the following definitions for "Activity Visibility States", based on the Activity State definitions at https://developer.android.com/guide/components/activities/activity-lifecycle.html.
-----------------------------------
Visibility State Definition
-----------------------------------
Not Visible Created+Stopped
Partially Visible Started+Paused
Fully Visible Resumed
-----------------------------------
Issues
The very definition of "Current Activity" is murky. When I use it, I mean the single Activity in the Fully Visible state. At any given instant, there may or may not be such an Activity. In particular, when Activity A starts Activity B, A's onPause() gets called and then B's onCreate(), onStart() and onResume(), followed by A's onStop(). There is a stretch between A's onPause() and B's onResume() where neither is in the Fully Visible state, so there is no Current Activity (as I define it). Of course, there are also situations where a background thread may want to access a Current Activity and there may or may not be an Activity at all, much less a Current Activity.
I've also realized that I may not always need a Current ("Fully Visible") Activity. In many cases, I may simply need a reference to an existing Activity, whether or not it is currently visible. In addition, that reference might be to just any Activity (for situations where I need to pass a generic Activity reference to some API method) or it might be to a specific Activity subclass instance (so that I can trigger some code specific to that Activity subclass).
Finally, there is the need to understand when Activity lifecycle callbacks are called by the main UI looper and how events like configuration changes are handled. For example, if I create a DialogFragment using an Activity intance which is currently in the "Not Visible" state, will it ever get displayed and, if so, when? Along similar lines, it turns out that the onDestroy() and onCreate() methods caused by a configuration change are contained in the same message in the UI's message queue (see Android UI Thread Message Queue dispatch order), so no other messages will be processed between those two callbacks (during a configuration change). Understanding this level of processing seems to be critical, but documentation on it is sorely lacking, if not missing completely.
Approaches
Here is a collection of approaches that can be used to address most of the above situations.
Background
For discussion, assume Activity A and Activity B, where A creates B.
Generally speaking, a "global" variable can be created by making it
"public static" on pretty much any class. Conceptually, extending
the Application class and adding it to the extended class would be
good, but if that's too much work it could be included (for
instance) in one of the Activity classes.
Generic Activity Reference
Useful whenever a generic Activity is needed.
Create a global variable. In both A and B, have onCreate() set it to "this" and onDestroy() set it to null.
Topmost Activity Reference
Useful whenever you want to access the currently visible Activity.
Create a global variable. In both A and B, have onResume() set it to "this". This approach works fine unless all Activities exit, in which case you may need to create a separate flag to indicate that situation. (That flag could be the Generic Activity Reference implementation mentioned above.)
Specific Activity Reference
Useful whenever a handle to a specific Activity subclass instance is needed.
In both A and B: create a global variable in the Activity subclass itself. Have onCreate() set it to "this and onDestroy() set it to null.
Application Context
Useful whenever a Context spanning the lifecycle of the entire app is needed or when you don't care about using a specific Activity Context (e.g., to create a Toast from a background thread).
You can get this from Activity's getApplication() and store it on a static hook.
Handling Configuration Changes
There may be times when you want to stop/start a background thread only across an Activity "session", where I define "session" to include the series of Activity instances which may be created and destroyed due to configuration changes. In my particular case, I have a Bluetooth Chat Activity and an associated background thread to handle the network connection. I don't want to have the connection destroyed and created each time the user rotates the device, so I need to create it only when one doesn't exist and destroy it only if a configuration change isn't underway. The key here is understand when onDestroy() is called due to a configuration change. This can be done with or without fragments. As is often the case, I prefer the non-fragment approach since the fragment approach doesn't seem worth the extra complexity to me.
Approach 1: Without Fragments
In onCreate(), create the background thread if it doesn't exist yet. In onDestroy(), destroy the background thread only if isFinally() returns false.
Approach 2: With Fragments
This works well because the FragmentManager will store fragment instances across configuration changes if setRetainInstance(true) is used. For an excellent example of this, see http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html. The example is for AsyncTasks, but can also be applied to managing a background thread (just create the thread instead of an AsyncTask in the fragment's onCreate() and then destroy the thread in the fragment's onDestroy()).
Closing
Fully understanding these issues requires a deep understanding of how the UI looper processes its message queue -- when Activity callbacks are called, how other messages are interleaved with them, when display updates occur, etc. For instance, if a DialogFragment is created using an instance of a non-visible Activity, will it get displayed at all and, if so, when?
Perhaps some day Android will provide a deeper API to Tasks and their associated backstacks, along with documentation describing the UI's message processing and associated mechanisms in more detail. Until then, more "source code and/or ... empirical analysis" :-).
Thanks,
Barry
If all you want you want to know is which Activity is foremost and accepting user interactions, just create a BaseActivity that extends Activity and override onResume() and save a reference to "this" in a static variable. All of your other activities should extend BaseActivity. You're done.
The short answer I would guess is that only one activity can ever be active at a time in a given app, and that activity obviously knows who it is (it is itself) -- so the only answer any activity can get to "what activity is currently active" can only ever be "you are, silly".
For simple apps with a clear division between the different activity classes, this works fine, and so that's a great percentage of most of the apps in the play store. It doesn't work so hot when you're getting real clever with encapsulation and polymorphism, as I'm sure you've discovered, but I don't think Google is really targeting those types of developers.
Just my $0.02, I don't think you'll get an "official" answer here.

Is it ok to use setContentView() once in OnResume()

I have heard things about how it is bad to use setContentView()
Pattern "One activity, multiple views": Advantages and disadvantages
However I was wondering, would it be unlikely that my application will cause memory leaks, if I use setContentView() once in the onResume() method of my activity?
Whenever the user opens my app, it checks to see if something has been enabled in settings. If it has been enabled then the app uses a different screen compared to the original screen.
Therefor my code looks like this:
#Override
protected void onResume() {
super.onResume();
InputMethodManager im = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
String list = im.getEnabledInputMethodList().toString();
if(Stuff is true){
setContentView(R.layout.activityscreen_enabled);
}
}
}
Would using setContentView() be unlikely to cause memory leaks and other such problems? Or is there a better solution?
I'm doing Android since few years now and I have never done that because I like to stick to the pattern which is almost always having the setContentView in the onCreate.
However, I do not believe that you would have big troubles doing that (for the memory leaks I mean).
Nevertheless, I do not see the point of doing such a thing, the pattern of the Activity (or how I understood it) is more:
I create a view in the onCreate and I update its data in the onResume and if the data are A then add/remove this view and if the data are B add/remove this other view.
To be complete, I read your (really good) link and I think you maybe misunderstood how you can apply what Commonsware is saying: you can have multiply views without having different setContentView: your view structure needs, in this case, to be really modular and you will be able to load all the subviews dynamically (or, at least, it's how my colleague and I are doing ;) ).
For your example, I would have an empty layout for the base of the activity (let's say a blue background) and then for every view I want to have (every case), I would have a dynamic layout that I load at some point in the life cycle (probably at onResume). I do not believe that what you're doing is particularly bad but I doubt that it was thought like this ^^
This link agrees with me
If you need multiple screens use a Fragment or even create a new Activity inside of messing around with the view for some reasons
It's not good to have single Activity for the whole app or it will be so long and complicated.
Your onResume() would need to handle the new views and their ids, onClickListeners... etc.
onResume() is called many times unlike onCreate() so it would be a waste of time and memory to load the views over and over.
According to android doc in activity life cycle about onPause() and onResume()
Because this state can transition often, the code in these two methods should be fairly lightweight in order to avoid slow transitions that make the user wait.

Where should you call PreferenceManager.setDefaultValues?

In order to initialize preferences with default values from XML file describing the preferences, I can call PreferenceManager.setDefaultValues(this, R.xml.preference, false). Sounds simple, but I'm not quite sure when exactly should I call this?
As I understand from the docs, the above call is only needed once, in situation when no preferences are set yet. As a result of this call, preferences residing in /data/data/<myapp>/shared_prefs are going to be set, so all subsequent attempts to read preferences will get me the default values. Logically, setDefaultValues should be called in every single code path that might be executed without preferences being already initialized. Over time, this turned out to be multiple places - main activity, another activity, background service, small BroadcastReceiver handling system messages... Right now I've put call to setDefaultValues in onCreate() for my Application object, as I'm already using it as convenient singleton for other things.
Questions:
Do I have a guarantee that every time my code executes, Application object will be created and onCreate will run?
How are you dealing with this problem? One other way would be to hardcode default values into getFoo(key, defValue) calls, but that effectively scatters your default settings across whole code.
EDIT: Essentially, I don't know which solution is worse: calling setDefaultValues every time I access prefs in given code path, or calling it in some common place (like app's onCreate) every time, no matter whether I need it or not.
I'm going to delete my original answer and answer the questions that you actually asked.
Yes, the Application object's onCreate will be executed at the start of every process. Keep in mind that doesn't guarantee it will be run each time you start your main activity. If Android still has your process running it will use that again (e.g. you still have a service running). So yes what you're doing will work and you're correct in observing it won't blow up.
I'm dealing with this problem by subclassing SharedPreferences (let's call it MyPrefs -- that's not what I call it but that's not important). The key features of MyPrefs are:
encapsulation of get/set methods instead of directly accessing the key names
Handling code for loading defaults. I'm being a little lazy by using a static boolean instead of an AtomicBoolean to tell me if the defaults have been loaded.
Having said that... it works for me, but if you're almost certain you'll be calling the SharedPreferences every time your code runs where you're at works as good as any.
Hope this helps more than my previous answer.

How to run callback on application launch?

I know Android's Activity model is a bit different from what I usually consider to be an "app".
I want to do something (in this case, check some notifications on a server and show them if available) when my app is "launched". What is a good way to accomplish this?
I likely don't want to do it in an activity's OnCreate, since each activity can be created any number of times - the code would get called more often than necessary.
The app also has multiple entry points - would I have to duplicate the check in each activity?
What I'm thinking of doing is setting up this code inside the Application object, along with a flag that tracks whether it's already been called - and just call it from each Activity's onCreate().
Is there a better or more "proper" way to do this?
The right, Android-approved way to do this is:
Create your own android.app.Application class
Override the onCreate method
In the AndroidManifest.xml, change the android:name attribute of the application element to the name of your class
Now, whenever your app is "started" (any one of your activites is started for the first time and no other instances are alive) onCreate will be called.
You may also find the onTerminate method useful.
Can you just check if the bundle passed to onCreate() is null?
It's not null "If the activity is being re-initialized after previously being shut down..."
There's probably no harm in putting it in onCreate; the Activity is really only destroyed when the OS needs the RAM for something else, not when the user goes to another app.
EDIT: You can also have a Service that runs when the device gets booted up, too. This might be a better option if you also want to check when the app starts, since you'll only have to call context.startService from the Activity to run the check. Just be sure to stop it when it's done if you don't need it to be persistent.

Categories

Resources