Execute method when user leaves and then starts application - android

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?

Related

MyApplication.java did not run at the second time app started?

I have 1 application custom class MyApplication.java and 1 activity MainActivity.java.
At the first time when I start app, class MyApplication.java run correctly. Then I exit app by finish the activity
MainActivity.this.finish();
Then I click the app icon in screen to start it again. But this time, MyApplication.java do not run. It means that I can't exit app by finishing all activities?
I can't explain why.
P/s: Here is my code
MyApplication.java
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate: ");
}
MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate: ");
}
#Override
public void onBackPressed() {
this.finish();
}
In the Application class, the onCreate() method is called only if the process was ended when you exited the application. Usually the process is stopped when the system needs memory or if you exit the app using the back button instead of the home button. However, you cannot rely on it being terminated.
If you really want to kill your process when exiting the application, you can call System.exit(0); when the user presses the back key on your first activity.
#Override
public void onBackPressed() {
MainActivity.this.finish();
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
getParent().finish();
}
Note: This is definitely not recommended since it means fighting against the way the Android OS works and might cause problems.
it's because this line
MainActivity.this.finish();
will only close the activity but the application is still running as you don't have the privilege to close the app completely and as a prove of that after you click the button which runs MainActivity.this.finish();
try to see the background apps on your device you will see your app Finally the application class runs once the app starts and get along till the app is closed from the device apps stack manually.

Application onCreate not called when Notification Access Enabled

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
}

Android Lifecycle Behavior

Having an issue with lifecycle events and need some help if possible. I have read the other posts with similar issue and error however, still stuck .... Explaination may be a little long.
I have an App that requires the user to login when any 'backgrounding' event occurs (App switch, screen sleep, phone call and so on). Previously I was using the method of 'getRunningTasks' to check is my app is no longer top of stack to trigger the login flags and activity. I am now using a suggested timer method via onPause / onResume in my Application class which works great.
Now the issue at hand, and the questions:
App into background by Device Home button.
App is in the background, all my checks and flags are properly set. When I relaunch the app (Icon press), it loads the last activity, then from the onResume function - performs a startIntent for the login activity - based on the flag set in the timer event. The user logs in, and returns to the activity they were on (Stock List). All Good.
App into background by App Switch
timer event fires and all login flags are properly done as previous example.
--> Click 'device Home'button, then App icon --- App loads properly and loads the Login Activity, users logs in -- all good.
Problem area
2b. App into background by App Switch --> Example, Android pull down menu, jump to device settings - then return to app via the device back button
timer event fires and all login flags are properly done as previous example.
--> Click device 'return/back' button to return directly to the app.
User goes to Login screen, clicks 'Login' button - gets app crash due to :
java.lang.RuntimeException: Performing pause of activity that is not resumed
followed by
java.lang.RuntimeException: Performing stop of activity that is not resumed
My own system Logs in the lifecycle events all seem to fire in the appropriate order.
Basic overview from app re-launch:
-> DashBoard onResume
-> check for login flag and call intent for Login activity
Dashboard onPause
Login onResume
Login - user login hit button
Login onPause --- activity finish
Return to Dashboard onResume
-> Load details
The only diff is in the last senario ... the DashBoard onPause happens after the Login onResume. Not sure if this is the problem, or an Async delay issue with the lifecycle events.
My Manifest includes:
android:minSdkVersion="10" --- Maintaining old API due to clients with older devices
android:targetSdkVersion="19"
Any help or suggestions on what may be out of whack here? or how to avoid this error.
Thanks
--
Some code:
From BaseActivity.java
~~~~~~
private AppPreferences mAppPrefs;
protected MyApplication mMyApp;
#Override
protected void onPause() {
super.onPause();
//start timer
mMyApp.startActivityTransitionTimer();
}
#Override
protected void onResume() {
super.onResume();
//update current Activity Name
mMyApp.setCurrentActivity(this);
mMyApp.stopActivityTransitionTimer();
mAppPrefs = new AppPreferences(getApplicationContext());
if (mAppPrefs.getAppDestroyed() == true
|| mAppPrefs.getExitType() == AppPreferences.EXITTYPE_FULLEXIT) {
// we want to fully exit/close the app
this.finish();
} else {
if (mAppPrefs.getForceLoginState() == true) {
//~~~~ process login events
Intent intent = new Intent(this, LoginScreen.class);
startActivity(intent);
return;
}
}
}
DashboardActivity extends BaseActivity
{
#Override
protected void onPause() {
super.onPause();
if (((MyApplication)this.getApplication()).getProcessingLogout()){
// if we are already processing a login, do not continue here
return;
}
// ~~~ activity specific onPause event such as unregisterReceivers
((MyApplication)this.getApplication()).startActivityTransitionTimer();
}
#Override
protected void onResume() {
super.onResume();
if (((MyApplication)this.getApplication()).getProcessingLogout()){
// if we are already processing a login, do not continue here
return;
}
// ~~~ activity specific onResume events such as registerReceivers
}
}

Activity opened twice

I have an application that uses Urban Airship for push notification. When a notification arrives and the user clicks on it, activity A in my application should open and do something.
I've installed the BroadcastReceiver as is shown in the docs, and it's almost working.
When my app is in the foreground I don't let the user see the notification at all, and just handle it automatically.
When my app is not running at all, the activity opens up just fine.
When my app is in the background (which always happens when A is the top activity), a second instance of Activity A is created.
This is, of course, a problem. I don't want two A activities, I just want one of them. Here's the relevant BroadcastReceiver code:
#Override
public void onReceive(Context ctx, Intent intent)
{
Log.i(tag, "Push notification received: " + intent.toString());
String action = intent.getAction();
int notificationId = intent.getIntExtra(PushManager.EXTRA_NOTIFICATION_ID, -1);
if(action.equals(PushManager.ACTION_NOTIFICATION_OPENED))
{
Intent intentActivity = new Intent(ctx, ActivityA.class);
intentActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
UAirship.shared().getApplicationContext().startActivity((intentActivity);
}
}
UPDATE:
I tried to bypass this bug by calling System.exit(0) when the user presses Back on Activity A. The process ended, but then it was restarted immediately! My BroadcastReceiver is not called again in the second instance. What's happening?
UPDATE 2:
#codeMagic asked for more information about the app and activity A.
This app lets its user review certain items and comment on them. Activity A is started when the app is launched. If the user's session isn't valid any more, a Login activity is started. Once the user logs in, activity A becomes active again. A only has a "No items to review" message and a "Try now" button.
When the user logs in, the server starts sending push notifications whenever a new item is available for review. When the app gets the notification, activity A accesses the server and gets the next item to review. The item is shown in activity B. Once the review is submitted to the server, activity B finishes and activity A is again the top activity.
The server knows when a user is reviewing an item (because activity A fetched it), and doesn't send push notifications until the review is submitted - meaning a notification can't come if the user isn't logged in or if the user is viewing activity B.
While I agree there is a subtle race condition here, it is not causing the problem I'm seeing - in testing I am 100% positive there's no race condition - the push notification is only sent after Activity A becomes active again.
The solution was to add a launchMode='singleTask' to the activity in AndroidManifest.xml . As a result, instead of a new activity, onNewIntent of the same activity instance is called.
You can use one of several Intent Flags. FLAG_ACTIVITY_REORDER_TO_FRONT being one of them. This will bring the Activity to the front of the stack if it is already in the stack and if not then it will create a new instance. I believe you will still need FLAG_ACTIVITY_NEW_TASK if you aren't calling it from an Activity
Intent.FLAG_ACTIVITY_CLEAR_TOP should also work. But this will clear any other Activities on the stack. It just depends on what other functionality you need. Look through the Intent Flags and see which of these will work best for you
There are multiple scenarios when this could happen. One of them can be handled this way. Please see my answer here: https://stackoverflow.com/a/44117025/2959575
Ok, two notes on this :
You can register a broadcast receiver via the manifest so it is independent of any parts of your app. and use a Singleton pattern (keep a static reference to your activity somewhere in your app) that way you can check if their is an activity viewing or not and process accordingly.
// your activity A
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
myActivityReference = this;
}
public void onPause() {
super.onPause();
if (isFinishing()) {
myActivityReference = null;
}
}
or you can keep everything as it is and use activity lunching modes flags in your manifest such as singleTop, singleInstance ... etc. take a look here android activity lunch modes

Notification to restore a task rather than a specific activity?

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
}
}

Categories

Resources