In the wonderful article by Chet Haase I read this advice which I find quite important:
never make a network request in your Application object. That object
may be created when one of the app’s Services or BroadcastReceivers is
started; hitting the network will turn code that does a local update
at a specific frequency into a regular DDoS.
The application I work on currently follows this (bad) practise: it performs a user login in Application.onCreate() - on a background thread of course, but still. This is a requirement: user needs to be logged in before any activity would do any other tasks, which usually depend on logged in user. I currently do this using RxJava in a way that any activity task observables are flatMapped onto an userlogin event and it works quite nice.
So if I should take that login task out of Application, where should it go? At first I thought it would be nice to use ActivityLifecycleCallbacks and watch for the first activity to be created. But this callback (onActivityCreated) will be called after creation, which is too late for me.
So I think that this should be done by creating some BaseActivity class and putting login and other initialization calls in it's first onCreate(). But I don't feel this is too good, because I'm mixing some app-wide logic in an activity class, it's smelly...
Anything I could have missed?
SplashActivity
An activity that starts the application. It checks for resources availability and if needed, obtains them. It also checks whether there is an active user session, and if there isn't performs a log in, if there are remembered credentials, or redirects the user to the Login/Register screen
BaseActivity
An activity that is specific for your app and that holds initialization and lifecycle callback code that is applicable for all your activities in the application.
Related
This topic has so many different SO questions linked to it, I know, but I think most people ask their questions while still confused about why things happen when.
I've read Alex Lockwood's article on Fragment Transactions & Activity State Loss, and although he provides clear arguments for all things (read the article - it's really informative and easy to understand), he doesn't provide a full proof work around for my situation - using AsyncTasks.
Here's what we do in our app:
User presses a button which initiates an AsycTask doing a call to our server.
A phone call is initiated from within the app using Intent.ACTION_CALL.
Phone call is ended and user returns to the app.
AsyncTask responds with server call response.
App code processes the response and displays output to user.
So obviously, when the user goes to the phone call, our app is stopped. So when the AsyncTask gets to onPostExecute() and provides the server call response, we might not be in a live activity, and it's probably after onSaveInstanceState() has been called.
So how do I solve this?
I have to communicate the results of the server call response to the user through an AlertDialogFragment, but when I want to show that alert, I get IllegalStateException.
Alex Lockwood suggests that I make sure that no fragment transactions occur after onSaveInstanceSate() has been called - i.e. (I figure) don't trigger anything in the app (like displaying an alert), from the onPostExecute() of an AsycTask.
So when then?
Should I do something in onResume() like check there whether I've received a response from that AsyncTask server call, which I should probably save to shared prefs rather than process and present results to the user, and if so, display that alert to the user?
Please advise?
An AsyncTask will still run after an Activity is navigated away from. This means that onPostExecute() may be called when an Activity is no longer visible and any UI changes that should be done in onPostExecute() will result in an Exception, most likely a NullPointerException or an IllegalStateException.
To remedy this, you will have to either manage the AsyncTask yourself by stopping it in your activity's onPause() and restarting it in your activity's onResume() or place the task in a retained non-UI Fragment. In my opinion, these solutions are a little hacky. I would highly recommend using an AsyncTaskLoader in place of an AsyncTask when the UI will be modified after the task executes. AsyncTaskLoaders use a LoaderManager which handles the Activity/Fragment lifecycle for you.
There are many resources that demonstrate the correct implementation of AsyncTaskLoaders, I have listed some of them below:
Android developer documentation
Alex Lockwood's blog post
Wolfram Rittmeyer's blog post
I used the AsyncTaskLoader class in one of my open source applications, CrimeTalk Reader, to load web data using Jsoup and put the resuts in a ListView. The class that uses it can be found on Github.
In instances where you want to run a long-running task without UI interaction, you may want to check out the IntentService class.
My app needs to initially download data from two different web services (JSON) and import them into it's local database (Realm). I have two activities that need to display data from these web services. The first one (HomeActivity) is the initial activity that the app loads. The second one (LineupActivity) is created when navigating to it from the HomeActivity.
Currently, I've created an Application class (extending Application) in order to handle the web service downloading and importing. In it's onCreate(), it calls two methods, which are AsyncTasks that download and import each web service.
The reason I've added this download/import process into the Application class is for 2 reasons:
I want all the app data to be downloaded as soon as possible, so
when navigating to the second activity it doesn't need to initiate
another download.
Both these activities have swipe to refresh. They call each respective method in the Application class to re-download/import the
web service data.
Have I approached this incorrectly? Should I move the web service download/import logic out of the Application class? Also, does the onCreate() of the Application class get called more than once? Meaning, I know that it only gets called only once in the application's lifecycle, but does the Android OS eventually kill an app and have it call the onCreate() in the Application class when starting it again? I want the app to download fresh data upon startup, but not every time the user brings the app into focus.
Have I approached this incorrectly?
"Incorrectly" is a very relative term in this context.
Metaphorically, its like the context is never null but that doesn't determine boolean incorrect is true or false.
Should I move the web service download/import logic out of the Application class?
I would say Yes, as the download logic would not be related to the O.S. and the app being alive in its memory. Your requirement does not seem complex. Service would be necessary if the downloads are huge chunks of data, and if its not necessary, don't do it.
Also, does the onCreate() of the Application class get called more than once? Meaning, I know that it only gets called only once in the application's lifecycle...Application class when starting it again?
No, it won't be called more than once without app being killed and restarted. And what your are saying is correct, but for your requirement, there are probably more efficient and lighter ways to do it rather than combining it with an Application class.
For the rest of the logic, you could implement Asynctasks as a separate class and implement interfaces which are the callbacks of the result of your task. This would help in Swipe-to-refresh functionality.
In terms of documentation reference, Application class
There is normally no need to subclass Application. In most situation,
static singletons can provide the same functionality in a more modular
way.
Your case seems exactly that.
One thing you need to decide is When, how often do you need to refresh/download the data. For only start-up of the app or once daily, you can store date/day in SharedPreferences and check the value in onResume() of your Activity.
You can also implement inheritance with a Base Activity with the necessary download check logic in it and extend your classes. A Splash Screen would always help to initiate the downloads.
I suppose you could approach this anyway you want, though I like to implement one of the three options mentioned here: https://dl.google.com/googleio/2010/android-developing-RESTful-android-apps.pdf.
The presentation itself can be found here: https://www.youtube.com/watch?v=xHXn3Kg2IQE.
This does however not mention how you should sync on startup. But you could just set a SharedPreference in the application class and then use one of the patterns to sync in the background.
I'd recommend you instead of using Application to download your stuff to use a Service. If by any reason your app gets killed by the OS your dl's will never complete. Using a Service it will.
Also, you can use a Broadcast to your activity to signalize that the service has completed downloading and taking the necessary following steps.
first: I think it's bad to place the download at appliaction onCreate
as stated in documentation
Called when the application is starting, before any activity, service,
or receiver objects (excluding content providers) have been created.
Implementations should be as quick as possible (for example using lazy
initialization of state) since the time spent in this function
directly impacts the performance of starting the first activity,
service, or receiver in a process. If you override this method, be
sure to call super.onCreate().
pay attention to this part
Implementations should be as quick as possible (for example using lazy initialization of state) since the time spent in this function directly impacts the performance of starting the first activity
so any delay in download or import may cause the first activity to be delayed.
and the behavior is not clear, a black screen maybe?
Second suggestions for download/import:
1- use an AsyncTask in the first activity, where you display a small progress bar indicating the download/import process or even block the whole UI until completed (based on your business)
2- add a splash screen while downloading the data
regarding fresh data, you can store a timestamp, last_updated
and before starting the download/import process, check that value, if less than your accepted value (say 1 hour) don't start the download/import.
finally, regarding onCreate() call, i think it's not called everytime, only when app is re-created, like 1st run after reboot, or after being killed or forced close.
In Android it is generally a good practice to perform no database operation (or at least complex ones) in UI-Thread. I have an activity with a complex form and I want to ensure that all data is saved when the activity goes in the background (e.g. the user presses the home button or a phone call comes in). In the activity’s onPause()-method I can start an AsyncTask which stores the data in database but I can never be sure that the task finishes successfully because android can kill the process before the task finished because the activity and the whole app is in background.
I can save data synchron in the onPause-method but then it’s possible to run in to an ANR.
I know that Android restores the views after the activity was killed but this works only correct when View Ids are unique. I have a lot of programmatically added Views where I cannot ensure the Id’s uniqueness and to use the saveInstanceState-functionality is nearly impossible because I have to save very complex models.
Is there any possibility to ensure that data will be saved before android kills a process without doing it in the UI-Thread?
I created an application once where I had similar data consistency concerns. What I did there is delegate the storing of the data objects to a Service I created just for that purpose. Although this makes the starting/stopping/initialization of your Activity a lot harder (once the activity is started again, you will have to wait for the service to complete its previously started save action), this was the only "Android" way I could think of to deal with this problem.
You might look into using a service for that if you are afraid that the system kills your background-processes before they are completed. This might be over-kill, but will definitely work as expected =) Just google "Android Service Tutorial" if you are unsure how to use them.
-Services won't be killed unless you want them to!
Indeed, if you're running an AsyncTask in onPause(), Android can kill your applications's process without waiting for the worker thread to finish. But it won't kill the process if there's a running Service. So a nice solution here is to implement database synchronization logic using an IntentService.
I'm facing the same question here, when to save data: while the user completes a form or when the activity pauses. Also we must take into consideration screen rotations or other events that might result in data loss.
Here is what I found on the Android developer site:
For content provider data, we suggest that activities use a "edit in
place" user model. That is, any edits a user makes are effectively
made immediately without requiring an additional confirmation step.
Supporting this model is generally a simple matter of following two
rules:
When creating a new document, the backing database entry or file for
it is created immediately. For example, if the user chooses to write a
new e-mail, a new entry for that e-mail is created as soon as they
start entering data, so that if they go to any other activity after
that point this e-mail will now appear in the list of drafts.
When an activity's onPause() method is called, it should commit to the backing
content provider or file any changes the user has made. This ensures
that those changes will be seen by any other activity that is about to
run. You will probably want to commit your data even more aggressively
at key times during your activity's lifecycle: for example before
starting a new activity, before finishing your own activity, when the
user switches between input fields, etc.
This model is designed to
prevent data loss when a user is navigating between activities, and
allows the system to safely kill an activity (because system resources
are needed somewhere else) at any time after it has been paused. Note
this implies that the user pressing BACK from your activity does not
mean "cancel" -- it means to leave the activity with its current
contents saved away. Canceling edits in an activity must be provided
through some other mechanism, such as an explicit "revert" or "undo"
option.
You need to start a backgrounds service daemon with a notification to make sure your data is saved and shut down the service and notification as soon as the data is saved. The notification will be shown until the background service is running as it is mandatory to show services of background service otherwise your application would crash.
I’m developing application for most major Mobile OS like iOS, Windows Phone and Android. I have a request from my client that simply possible to implement in iOS and WP but sounds really tricky in Android.
In iOS and WP, an application lifecycle is controlled through events which an object like UIApplication and Application receives.
In iOS, for ex., applicationDidEnterBackground:, applicationWillEnterForeground:, applicationWillTerminate: and the like, clearly define application states such as Inactive, Active and Background and make the app state management logic really straight forward.
In WP, Application receives well understanding events such as Launching, Deactivated, Activated, and Closing which make it really simple to decide what should be done in each app state logically to save as restore application wide object model.
But in Android, application state management sounds really difficult with Activities’ state changes such as onCreate, onRestart… onDestroy method overriding. My problem arises where I want to control the whole application state when the user session goes expired and I want to redirect user to the sign in activity and shuts down other open activity.
Regarding the fact that calling finish() in an activity’s onCreate(), onRestart() or onResume() is ignored by Android (according to the documentation) .
Even if I override android.app.Application and put the logic there, it sounds like controlling open activities is not possible.
I almost tried all possible combinations of activity launch mode (such as SingleTask and SingleInstance) though I cannot produce behavior like those exist in iOS and WP.
There is another post related to this question which may clarify my problem more.
The question exactly is, “Is it possible to produce iOS or WP application behavior in Android anyway?”
So essentially, once a "session" expires, no matter what the user tries to do, you want them to be redirected to a login activity, yes?
Assuming you have a method you can call which tells you whether or not a session has expired, why no simply check that method in onResume() etc. and if the session has expired, redirect the user to the login Activity?
There's an answer here about the application state that may interest you:
Checking if an Android application is running in the background
With Application, you get the onCreate and you can put some logic here.
So yeah, it's not as straight forward as in iOS but it's doable.
If it's just a session state, create a base activity that check against the session state
and inherit all your activities from it.
You can close all your activties by using the Android SDK before going to the login page or... lock the back button.
I'm trying to implement some automatic logout code for my Application on Android.
I need to detect if all the activities belonging to an Application have entered the background as opposed to working with onPause() and onResume() for each individual activity. iOS has a helpful applicationDidEnterBackground: method that I could utilize, but I'm unable to find a similar function in Android's Application class.
One approach seems to be to have an AtomicInteger counter and increment it once an activity becomes visible and decrement it when it's finished or onStop() gets called. So if the counter becomes zero, I can start a service that runs in the background and handles the logout. Is this how it's usually done?
There is no global callback for this, but for each activity it is onStop(). You don't need to mess with an atomic int. Just have a global int with the number of started activities, in every activity increment it in onStart() and decrement it in onStop().
You really don't want to log out the user when the "application" goes in the background, any more than you log out the user of a Web app when the user switches to another tab or minimizes their browser window for a moment. If you were to do either of those things in a Web app, your users would consider your Web app to be an epic fail. Similarly, if the user gets a phone call with a wrong number, or the alarm clock goes off, they'll be rather irritated with you if they have to immediately go back in and sign in when they were just using your app 5 seconds ago. Here, by "irritated", I mean one-star ratings on the Market and nasty comments.
A Web app automatic log out is based upon inactivity, using a server session cookie.
Similarly, when I build a secured Android app, I'll be implementing an inactivity-based mechanism, perhaps something like this:
Step #1: Create a Session class with a static singleton instance. The Session object holds the last-accessed timestamp.
Step #2: In each activity's onResume(), see if the Session singleton exists. If not, it's a brand-new process, so if this isn't the authentication activity, immediately do a startActivity() to bring up the authentication activity.
Step #3: Back in each activity's onResume(), if the Session object exists, call something like extend(). This would return a boolean, true indicating the session is still good (and the timestamp has been updated to now), false otherwise. If it returns false, do the same stuff as if the Session object were null.
Step #4: Your authentication activity, upon success, sets up the singleton Session object with the current timestamp.
Step #5: Your Session class' extend() method is where you make the determination if the session is too old.
No matter how the user gets into your application, if the session is too old (or it's a brand-new process), they are forced to authenticate. Yet, if the user briefly is interrupted -- where you and/or the user can define "briefly" -- they don't have to re-authenticate.
I think your suggestion is probably the best way to go. Unfortunately I don't think there's an API call to detect if your app is in the background or not. You'll just have to manipulate the onPause() and onResume() methods. Just keep in mind that you'll need need to account for transitions between activities, so once your AtomicInteger reaches 0, I'd wait a short amount of time and recheck that it's still 0 to make sure it wasn't just transitioning activities.
Create an Application class and include in the manifest
<application
android:name="com.example.hello.MyApplication"
public class MyApplication extends Application implements
ActivityLifecycleCallbacks, ComponentCallbacks2
override the following method
#Override
public void onTrimMemory(int level) {
// this method is called when the app goes in background.
// you can perform your logout service here
super.onTrimMemory(level);
}
this is valid of API level 14 and above.
You can even perform the the logout based on the amount of time the app is in background, which i would suggest is a better option. here is what you can do to create as "session timeout"
save the time stamp in SharedPreferences inside the onTrimMemory(int level) method
on all your activities onStrat() get the time stamp from sharedPref and compare it with current time. based on this you can perform a logout.
and clear the shared pref on onCreat of MyApplication