My Application onCreate is not calling when the notification access enabled.It calls only when I update the app or When I disable the notification access of my app.Here are the scenarios I found by debugging the app.
Condition 1 - onCreate Not Calling when Notification Access Enabled
i) I tried to kill the app.But Application onCreate not called
ii) It calls only One time when the app is launching
Condition 2 - onCreate called
i) It calls when I kill the app
ii) Notification Access disabled
When you open the activity onCreate will execute once. So next time you open the same activity from Notification which you have already opened it wont execute the onCreate.So use onNewIntent
manifest
<activity android:name="ActivityName" android:launchMode="singleTask">
then in your Activity
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
//here you will get the intent
}
Related
The Android OS kills processes when it's low on memory. Scenario: Android kills the app process and I re-open it through either the Android launcher or the recent-task list (long press home button). I can check if Android killed my app process in the onCreate() method of the most recently viewed activity using:
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
// Re-initialise things that killing the app would have destroyed
}
}
However, if Android kills the app process and I re-open it through a Notification using an Intent packaged inside a PendingIntent, I don't know how to determine if the app process was killed by Android. Subsequently I do not re-initialise things that killing the app process would have destroyed.
Is there a way to determine if Android killed the application process when opening a new Activity from a Notification?
I have found one hacky solution to this problem. Using: Android: always launch top activity when clicked on notification I can open the activity on top of the stack which is passed a savedInstanceState if Android killed the app process and deal with re-initialisation. Each activity is then responsible for redirecting the user to the appropriate activity using Extras in the original Notification Intent. Intent setup for this scenario is below:
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.setAction(Intent.ACTION_MAIN);
notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
Is there an Action, Category or Flag I can set on an Intent that will emulate re-opening the app process as if done by the user but on a new Intent / Activity?
EDIT: To clarify the last question (although it seems my infant understanding of Android is failing me so it probably doesn't make sense): Is there an Action, Category or Flag I can set on an Intent, like in the snippet above, that will allow me to determine if the app process has been killed by the OS?
The easiest way to determine if Android has killed the process and then created a new process is as follows:
In your root Activity (the one with ACTION=MAIN and CATEGORY=DEFAULT) create a public static boolean variable like this:
public static boolean initialized;
in onCreate() of your root Activity, set this variable to true.
In onCreate() of all your other activities, you can check if Android has killed/recreated the task by checking the state of the boolean, and if the app hasn't been initialized, you can redirect to the root Activity or call an initialization method or whatever... like this:
if (!RootActivity.initialized) {
// Android has killed and recreated the process and launched this
// Activity. We need to reinitialize everything now
... redirect to root activity or call reinitialize method
}
Since the process id will change when app is being killed and restarted, you can use this to check it:
In onSaveInstanceState(Bundle outState) get current process id and save it in outState:
onSavedInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
outState.putInt("my_pid", Process.myPid());
}
Then in onCreate(Bunde savedInstanceState) compare the saved process id and the current process id:
onCreate(Bundle savedInstanceState){
if(savedInstanceState!=null){
if(savedInstanceState.getInt("my_pid",-1)==android.os.Process.myPid())
// app was not killed
else
// app was killed
}
}
I have an activity that shows some information based on the intent that initiates the activity. The app icon starts this activity without any extra information and the activity displays correctly. The app widget also starts this activity, but with some extra information and is handled correctly. In this scenario, the app does not work as expected:
The user enters the activity using home screen shortcut.
The user uses the home key to send the app to the background.
The user uses the widget shortcut to enter the app
in this scenario, in onResume() the intent is the old one not the one from widget.
How can I solve this problem?
This is exactly why onNewIntent() exists: it is called:
when the activity is re-launched while at the top of the activity stack instead of a new instance of the activity being started, onNewIntent() will be called on the existing instance with the Intent that was used to re-launch it.
An activity will always be paused before receiving a new intent, so you can count on onResume() being called after this method.
Note that getIntent() still returns the original Intent. You can use setIntent(Intent) to update it to this new Intent.
Therefore add code such as:
#Override
protected void onNewIntent (Intent intent) {
setIntent(intent);
}
And/or move your code from onResume() into a method such as handleIntent() and call it from both your onCreate() and from onNewIntent().
I have a question about the android lifecycle. This is my onCreate method of my main application:
#Override
public void onCreate(Bundle b) {
super.onCreate(b);
decode = new Decode(this);
adjustToDimensions();
setLoadingScreen("Zorgdossier wordt geladen...");
initReceiver();
startCommunicationWithServer();
}
I set the screen to a loading screen, initialize a broadcastReceiver and send a message to the server.
Now, when I press the home button and start my application again I always want to start this activity so I've added
android:clearTaskOnLaunch="true"
To the manifest.
But now I want the startCommunicationWithServer() to be executed when the user starts the application again. This method sends a message to the server, and the server on the other hand sends a message that I receive in the receiver.
With this message I decide which screen to show.
I've tried to put it in the onRestart method:
#Override
protected void onRestart() {
Log.d("MainActivity", "activity restarted");
startCommunicationWithServer();
super.onRestart();
}
But this activity is shown multiple times troughout the application, so the onRestart method is executed each time. But I only need the startCommunicationWithServer() to be executed at the start of the application.
So long story short, how can I call the startCommunicationWithServer() method when the user exits and subsequently starts my application?
I have a foreground service that keeps a connection open with the server as long as the user is logged into the application. This is so that the connection is kept alive and can receive messages directly from the server even when the application has been sent into the background by the user pressing Home.
The application has a number of Activities, any of which could be the active one when it is sent into the background.
I would like to allow the user to click on the notification to restore the current Activity. I understand how to restore a particular activity, but wondered if there is a way to restore the last Activity that the user was on? Of course I could keep track of the the last one, and then call that from the Notification callback, but thought there might be a way at a task level?
Thanks for any advice you can offer.
What you need is just a simple Activity that does nothing. Here is an example:
public class NotificationActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Now finish, which will drop the user in to the activity that was at the top
// of the task stack
finish();
}
}
Set up your notification to start this activity. Make sure that in the manifest the task affinity of this activity is the same as the task affinity of the other activities in your application (by default it is, if you haven't explicitly set android:taskAffinity).
When the user selects this notification, if your application is running, then the NotificationActivity will be started on top of the topmost activity in your application's task and that task will be brought to the foreground. When the NotificationActivity finishes, it will simply return the user to the topmost activity in your application (ie: wherever the user left it when it went into the background).
This won't work if your application isn't already running. However, you have 2 options to deal with that:
Make sure the notification isn't present in the notification bar when your application is not running.
In the onCreate() method of the NotificationActivity, check if your application is running, and if it isn't running call startActivity() and launch your application. If you do this, be sure to set the flag Intent.FLAG_ACTIVITY_NEW_TASK when starting the application so that the root activity of the task is not NotificationActivity.
Works very well, thanks David! The following class checks if the application is already running and if not, starts it before finishing (as suggested by David in option 2).
public class NotificationActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// If this activity is the root activity of the task, the app is not running
if (isTaskRoot())
{
// Start the app before finishing
Intent startAppIntent = new Intent(getApplicationContext(), MainActivity.class);
startAppIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startAppIntent);
}
finish();
}
}
There is a simpler solution that does not require the extra activity. See this post for details. Basically, the notification starts the (possibly existing) task the same way it is started when you click the launcher icon while the app ist in the background.
My solution, which emulates the behaviour of the launcher (bringing up the task to the foreground):
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setClassName(MyApplication.class.getPackage().getName(), MainActivity.class.getName());
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
This works, no doubts about it but the problem is when you set your intent as ACTION_MAIN. Then you will not be able to set any bundle to the intent. I mean, your primitive data will not be received from the target activity because ACTION_MAIN can not contain any extra data.
Instead of this, you can just set your activities as singleTask and call your intent normally without setting ACTION_MAIN and receive the intent from onNewIntent() method of your target activity.
But be aware if you call, super.onNewIntent(intent); then a second instance of the activity will be created. Just don't call super method.
I combined David Wasser's and Raginmari's solution by doing that approach to the root activity of your app then it will work for both cases when your app was already started or haven't been started.
public class YourRootActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (!isTaskRoot()) // checks if this root activity is at root, if not, we presented it from notification and we are resuming the app from previous open state
{
val extras = intent.extras // do stuffs with extras.
finish();
return;
}
// OtherWise start the app as usual
}
}
I would like to put a notification with an intent.
My intent is basically action = DEFAULT and category = LAUNCHER in order to bring the activity that was launched into the front.
When the app is not shown, there is no problem, the intent works perfectly and launches the last activity seen but when there is already an activity launched, onNewIntent is not called (activity is in singleTop mode).
I'm wondering how to relaunch the app from an intent to the last activity seen and call onNewIntent when the activity is already launched.
the problem is that your activity is defined as
android:launchMode="singleTop"
when there is already an activity
launched, onNewIntent is not called
implement the onDestroy method::
#Override
public void onDestroy(){
super.onDestroy();
}