How to trigger a method during app launch? (Android) - android

I'm trying to call a method when a user launch my application (no matter it is a fresh launch, or a return to it after hiding by home buttton)
For iOS, we can put the method in "applicationDidBecomeActive" in AppDelegate.m, so the method will be called when app launches.
However, for Android, if we put the method in onResume() in the 1st activity, not only app launch will call the method, backing to the the 1st activity from other activities in the same app will also call the method. I don't want this happen, I just want the method to be called when app launches.
I've asked it in the past but seems no answer on Android.
Any solutions? Thanks a lot.

You can implement your own Application class. MyApplication extends Application and set it as your Application in the manifest file AndroidManifest.xml.
<application
android:name="MyApplication"
.
.
. >
</application>
In MyApplication Class, implement onCreate() and onTerminate() methods.
onCreate() method called when the application is starting, before any activity, service, or receiver objects (excluding content providers) have been created.
See the docs for Application.

There is no method that is called only when the app returns from background, but you could implement something that you could implement something like this to see if the app started from background or it was first started. Create a general activity that will be extended by all the other activities and override onStart():
public abstract class CustomActivity extends FragmentActivity {
public static int ACTIVITIES_RUNNING = 0;
#Override
protected void onStart() {
super.onStart();
if (ACTIVITIES_RUNNING == 0) {
//app came from background
//start whatever you want
}
Const.ACTIVITIES_RUNNING++;
}
}

First create singleton for counting activities in foreground
public class ActivitiesCounter {
public interface ApplicationLaunchListener{
public void onLaunch();
}
private int mCounter = 0;
private ApplicationLaunchListener mListener;
private static ActivitiesCounter mInstance = new ActivitiesCounter();
public static ActivitiesCounter getInstance(){
return mInstance;
}
public void increase(){
if(mCounter == 0){
if(mListener != null){
mListener.onLaunch();
}
}
mCounter++;
}
public void decrease(){
mCounter--;
}
public void setApplicationLaunchListener(ApplicationLaunchListener listener){
mListener = listener;
}
}
Then activity:
public class MyActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ActivitiesCounter.getInstance().setApplicationLaunchListener(new ActivitiesCounter.ApplicationLaunchListener() {
#Override
public void onLaunch() {
Toast.makeText(MyActivity.this, "launched", Toast.LENGTH_LONG).show();
}
});
findViewById(R.id.btn_activity_b).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MyActivity.this, ActivityB.class);
startActivity(intent);
}
});
}
#Override
protected void onStart() {
super.onStart();
ActivitiesCounter.getInstance().increase();
}
#Override
protected void onStop() {
ActivitiesCounter.getInstance().decrease();
super.onStop();
}
}
Activity B also should increase and decrease counter
public class ActivityB extends Activity {
#Override
protected void onStart() {
super.onStart();
ActivitiesCounter.getInstance().increase();
}
#Override
protected void onStop() {
ActivitiesCounter.getInstance().decrease();
super.onStop();
}
}
It's better create BaseActivity (with onStart, onStop) for all activities in your app (then, you don't need override onStart, onStop every time)

You can define a superclass for all your activities and track the state of the app. If all activities are in stopped state - app in the background, otherwise - in the foreground. In onStart() and onStop() methods of your super activity you can increment and decrement the number of visible activites. Then in onStart() check if there was any currently visible activites. If no - app becomes active and you can call your method:
public class SuperActivity extends Activity {
private static int mVisibleActivitiesCount;
#Override
public void onStart(){
super.onStart();
if (mVisibleActivitiesCount == 0) {
onAppBecomesActive();
}
mVisibleActivitiesCount++;
}
#Override
public void onStop(){
super.onStart();
mVisibleActivitiesCount--;
}
private void onAppBecomesActive() {
// Do some staff
}
}

Open the androidManifest.xml from the Manifests Folder
Choose the Activity you want to open when app start
Add these codes to that Activity
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
Remember to removes this code from the activity in which its already present(usually MainActivity)

Related

How to know when you returned to an activity because of the back button?

My MainActivity leads to SecondActivity. If the user presses the phone's back button the app goes back to the MainActivity.
How can I execute something when this happens?
(I know I could put code in SecondActivity to add functionality to the back button so it passes a result to MainActivity, but I don't want to do that to every possible screen that could lead back to the MainActivity.)
Perhaps another way of asking, how can I know that MainActivity is showing because of pressing the back button rather than having been formally requested with an intent?
Background
I think here is the logic to implement this requirement:
When users press the back key on the current activity, we will remember that action.
When users go back to the previous activity, we will check whether there is a back key pressed action exits or not.
Implementation
Step 1. Create a base activity class named BaseActivity. Every activity in your app should extend from this class.
class BaseActivity extends AppCompatActivity {
public static String IS_BACK_KEY_PRESSED = "IS_BACK_KEY_PRESSED";
#Override
public void onBackPressed() {
// Remember the user's press of the back key action
getIntent().putExtra(IS_BACK_KEY_PRESSED, true);
// Call the super's method
super.onBackPressed();
}
/**
* Called when the activity has been resumed from an activity
* that has been destroyed because of user's press of the back key
*/
public void onGoBackFromAnotherActivity() {
}
}
Step 2. Create a class named MyApp that extends from the Application class. Its purpose is to listen to all activity lifecycle of the app by using registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks)
public class MyApp extends Application {
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacksImpl());
}
private static final class ActivityLifecycleCallbacksImpl implements ActivityLifecycleCallbacks {
boolean isBackKeyPressed = false;
#Override
public void onActivityCreated(#NonNull Activity activity, #Nullable Bundle savedInstanceState) {
}
#Override
public void onActivityStarted(#NonNull Activity activity) {
if (activity instanceof BaseActivity) {
if (isBackKeyPressed) {
((BaseActivity) activity).onGoBackFromAnotherActivity();
isBackKeyPressed = false;
}
}
}
#Override
public void onActivityResumed(#NonNull Activity activity) {
}
#Override
public void onActivityPaused(#NonNull Activity activity) {
if (activity instanceof BaseActivity) {
Bundle data = activity.getIntent().getExtras();
if (data != null) {
isBackKeyPressed = data.getBoolean(BaseActivity.IS_BACK_KEY_PRESSED);
} else {
isBackKeyPressed = false;
}
}
}
#Override
public void onActivityStopped(#NonNull Activity activity) {
}
#Override
public void onActivitySaveInstanceState(#NonNull Activity activity, #NonNull Bundle outState) {
}
#Override
public void onActivityDestroyed(#NonNull Activity activity) {
}
}
}
Remember to add this class to AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.kotlinapp">
<application
android:name=".MyApp"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SecondActivity" />
</application>
</manifest>
Usage
MainActivity.java
public class MainActivity extends BaseActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public void onGoBackFromAnotherActivity() {
// Your code logic goes here.
}
}
SecondActivity.java
public class SecondActivity extends BaseActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
}
}
Edit: Check if any activity (without knowing which) returned to desired activity
To check in Activity A, use:
#Override
protected void onResume() {
super.onResume();
// TODO: Work
}
As stated in the comment, onResume will be called on an activity/fragment when:
Activity runs for the first time
Activity comes back into focus (from another activity, launcher, recent, another app)
However, you cannot track what triggered it, or what happened before it.
---------- Outdated ----------
Between Activity A and Activity B
use
startActivityForResult(intent, CHOOSE_AN_INT_VALUE_TO_INDICATE_IT_REQUESTS_FOR_BACK_PRESS);
In Activity A, and in Activity B, use
#Override
public void onBackPressed() {
setResult(CHOOSE_AN_INT_VALUE_TO_INDICATE_IT_CAME_FROM_BACK_PRESS);
finish();
}
Then again in Activity A, use
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CHOOSE_AN_INT_VALUE_TO_INDICATE_IT_REQUESTS_FOR_BACK_PRESS && resultCode==CHOOSE_AN_INT_VALUE_TO_INDICATE_IT_CAME_FROM_BACK_PRESS) {
// TODO: Do your work
}
}
If these 3 portions are implemented, you don't need to check for which activity triggered back press, you can simply compare the request and result codes
I hope this helps!!

Application Level onResume Android

Problem
The idea is very simple. Whenever an user comes back to my app from the Recents I want to show a simple dialog prompting with the password.
I know how to prompt the dialog with password, but my problem is how do I understand that the user has entered my app from the recents. If I put the prompt in the onResume in every activity, then it will get triggered everytime even if the user doesn't enter from the Recents menu.
There are lots of activities and fragments in my app. So, I would love to have a more generic or application level solution.
Implement Application.ActivityLifecycleCallbacks, that will provide all activity callback in your application class.
public class AppController extends Application implements
Application.ActivityLifecycleCallbacks
{
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
#Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
#Override
public void onActivityStarted(Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
}
You could try with this flag FLAG_ACTIVITY_LAUNCHER_FROM _HISTORY:
if((getIntent().getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY )!=0){
Log.d(TAG, "Called from history");
//clear flag from history
Intent intent = getIntent().setFlags( getIntent().getFlags() & (~ Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY));
setIntent(intent);
}
Source : Android - detecting application launch from home or history
When "A" Activity is start from recent, this flag is present.
Now this flag will be also present if "A" activity call "B" activity and on "B" user press back.
So you have to check flag and when you detect it you have clear intent by removing this flag, source: Remove a Paint Flag in Android
Try below sample
/**
* TODO : After update to API level 14 (Android 4.0),
* We should implement Application.ActivityLifecycleCallbacks
*/
public class GlobalApplication extends android.app.Application
{
private boolean inForeground = true;
private int resumed = 0;
private int paused = 0;
public void onActivityResumed( Activity activity )
{
++resumed;
if( !inForeground )
{
// Don't check for foreground or background right away
// finishing an activity and starting a new one will trigger to many
// foreground <---> background switches
//
// In half a second call foregroundOrBackground
}
}
public void onActivityPaused( Activity activity )
{
++paused;
if( inForeground )
{
// Don't check for foreground or background right away
// finishing an activity and starting a new one will trigger to many
// foreground <---> background switches
//
// In half a second call foregroundOrBackground
}
}
public void foregroundOrBackground()
{
if( paused >= resumed && inForeground )
{
inForeground = false;
}
else if( resumed > paused && !inForeground )
{
inForeground = true;
}
}
}
Put below code in your all activities.
public class BaseActivity extends android.app.Activity
{
private GlobalApplication globalApplication;
#Override
protected void onCreate()
{
globalApplication = (GlobalApplication) getApplication();
}
#Override
protected void onResume()
{
super.onResume();
globalApplication.onActivityResumed(this);
}
#Override
protected void onPause()
{
super.onPause();
globalApplication.onActivityPaused(this);
}
#Override
public void onDestroy()
{
super.onDestroy();
}
}
I would suggest using LifecycleObserver. If your Application class implements this interface it marks a class as a LifecycleObserver, it does not have any methods, instead, it relies on OnLifecycleEvent annotated methods. The usage is simple:
public class AndroidApplication extends Application implements LifecycleObserver {
#OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onAppStart() {
//enter code here
}
#OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onAppStop() {
//enter code here
}
...etc
}
With Lifecycle.Event you can access all lifecycle states through Enum. It is part of androidx.

Detecting state of application resume from different navigation state android

I want to record state of application when it is resumed/created from different point of entry.
app is opened from app drawer
app is opened from notification
app is opened from open apps (Long home press)
app is resumed from other screen
I know it can be traced by generating a base activity and overriding resume/pause events, but I have bulk of activity present in app. so is there any short method to get the state of application?
I thought about creating a service and continuously checking current running tasks, but I can only use this approach if I found a way to run the service only when my activity is in visible state. (for that to bind service in each activity is not practical for me)
Your suggested solution sounds good to me:
public class YourBaseActivity extends Activity {
#Override
protected void onResume() {
super.onResume();
ActivityManager mgr = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = mgr.getRunningTasks(1);
tasks.get(0).topActivity.getClassName();
//Do what you need to do with it...
}
}
And let all your activities extends this one instead of Activity should work for you
EDIT
Another way to do it:
Create your own application class and implement Application.ActivityLifecycleCallbacks, a working example of the code:
public class ApplicationTest extends Application implements Application.ActivityLifecycleCallbacks {
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
Log.d("testing", "onActivityResumed");
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
#Override
public void onActivityStarted(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
}
}
And reference this class in your manifest:
<application
...
android:name="com.example.testing.ApplicationTest" >

Run code when Android app is closed/sent to background

I have an Android application which sends some data to a webservice. I need to send this data as soon as the application is closed or sent to background.. But how do I accomplish this?
My current solution is to run it on the OnPause() on my home activity, but I need this to run no matter which activity the user is on when closing the app.. Is this possible or do I have to add the OnPause method to all activities?
Check this solution first https://stackoverflow.com/a/5862048/1037294 before you decide to use the code below!
To check if your application is sent to background, you can call this code on onPause() or onStop() on every activity in your application:
/**
* Checks if the application is being sent in the background (i.e behind
* another application's Activity).
*
* #param context the context
* #return <code>true</code> if another application will be above this one.
*/
public static boolean isApplicationSentToBackground(final Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(context.getPackageName())) {
return true;
}
}
return false;
}
For this to work you should include this in your AndroidManifest.xml
<uses-permission android:name="android.permission.GET_TASKS" />
This is the method that I used and it seems to work pretty well:
I have a top level Application class of my own that extends Application as such
public class MyApplication extends Application implements Application.ActivityLifecycleCallbacks {
You also need to register this Application object in your manifest file:
<application android:label="#string/app_name" android:icon="#drawable/ic_launcher" android:name=".MyApplication">
Notice how I also implement the ActivityLifeCycleCallbacks interface. This interface has the following methods:
public static interface ActivityLifecycleCallbacks {
void onActivityCreated(android.app.Activity activity, android.os.Bundle bundle);
void onActivityStarted(android.app.Activity activity);
void onActivityResumed(android.app.Activity activity);
void onActivityPaused(android.app.Activity activity);
void onActivityStopped(android.app.Activity activity);
void onActivitySaveInstanceState(android.app.Activity activity, android.os.Bundle bundle);
void onActivityDestroyed(android.app.Activity activity);
}
You need to implement those methods and then register for these events in your applications onCreate() as follows
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(this);
}
This will then call the callback (the MyApplication object) whenever an activity lifecycle method happens such as onCreate(), onPause etc.
In your onActivityPaused() you can then check if the app was backgrounded or not by calling #peceps method : isApplicationSentToBackground(...)
This is what my code looks like then...
/**
* Application.ActivityLifecycleCallbacks methods
*/
#Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
#Override
public void onActivityStarted(Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
try {
boolean foreground = new ForegroundCheckTask().execute(getApplicationContext()).get();
if(!foreground) {
//App is in Background - do what you want
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
#Override
public void onActivityPaused(Activity activity) {
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
Create a new class to go the Foreground checking (which is an async. task). See check android application is in foreground or not? for more.
class ForegroundCheckTask extends AsyncTask<Context, Void, Boolean> {
#Override
protected Boolean doInBackground(Context... params) {
final Context context = params[0];
return isAppOnForeground(context);
}
private boolean isAppOnForeground(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
if (appProcesses == null) {
return false;
}
final String packageName = context.getPackageName();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
return true;
}
}
return false;
}
}
Edit
This answer only serves for one purpose, that is, running a code in onPause() for all activities. It doesn't let you run a code when your app is sent to background.
Original Answer
Make an Activity named YourBasicActivity and override its onPause() method and extend every Activity from YourBasicActivity
Maybe this can be helpfull, tell me if it worked for you.
only when you return from background the value of activities would be 0 (zero)
the rest of the times would be a number higher than 0(zero) when the onRestart()
is executed.
public class FatherClass extends Activity {
private static int activities = 0;
public void onCreate(Bundle savedInstanceState, String clase) {
super.onCreate(savedInstanceState);
}
protected void onRestart()
{
super.onRestart();
if(activities == 0){
Log.i("APP","BACK FROM BACKGROUND");
}
}
protected void onStop(){
super.onStop();
activities = activities - 1;
}
protected void onStart(){
super.onStart();
activities = activities + 1;
}
}
All of your classes must extend from this class for this to work.
Explanation: The onStart is executed one the activity is "visible" and the onStop when the activity is "not visible". So when your APP (it says APP not activity) goes to background all the activities are "not visible" so they execute the onStop method, so the idea behind this is to ADD ONE each time an activity es started, and SUBTRACT ONE each time an activity es hided, so if the value of the variable "activities" is zero that means that all the activities that where started in some point are now not visible, so when you APP returns from background and executes the onRestart method on the activity in "front" you can check whether comes from background or is just restarting an activity.
you can use onAppForegroundStateChange() method which call when app is open and closed.this method is only called when your app comes in foreground/background.
onAppForegroundStateChange() method is better then you used onPause() method because onPause method is also called every time when you go to other activity.
you can use this method like that
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
AppForegroundStateManager.getInstance().addListener(this);
}
#Override
public void onAppForegroundStateChange(AppForegroundStateManager.AppForegroundState newState) {
if (AppForegroundStateManager.AppForegroundState.IN_FOREGROUND == newState) {
// App just entered the foreground. Do something here!
} else {
// App just entered the background. Do something here!
}
}
}
override the onStop() method of your Home activity and run the code there.
I think you need to run your own thread which will check whether all running activities in background or destroyed.
MyBasicActivity extends Activity
{
private static ArrayList<MyBasicActivity> activities=new ArrayList<MyBasicActivities);
private boolean started;
public void onCreate()
{
activities.add(this);
}
public void onDestroy()
{
activities.remove(this);
}
public void onStart()
{
this.started=true;
}
public void onPause()
{
this.started=false;
}
public boolean isStarted()
{
return started;
}
}
MyThread implements Runnable
{
private ArrayList<MyBasicActivity> activities;
public MyThread(ArrayList<MyBasicActivity> activities)
{
this.activities=activities;
}
void run()
{
while(!stopped)
{
boolean inBackground=true;
for(MyBasicActivity activity:activities)
{
if(activity.isStarted())
{
inBackground=false;
break;
}
}
if(inBackground)
//run your code here;
sleep(10000); //10 secs
}
}
}
If you are trying to submit/save data the user input, there are better ways to go about it than doing it when he tries to close the app. There are many ways to close an app. The user could even turn down the phone. So it's hard to take precautions against all of them.
I'd suggest you submit the data everytime the user stops writing, every any number of seconds or when he presses a button for example if your call to the webservice is too slow.
This way it's more safeproof and it's easier to implement.

How to destroy an activity in Android?

While the application is running, I press the HOME button to close the application. When I start the application again, it resumes on the page displayed prior to clicking on HOME. I want the application to start with the initial display instead. I have used finish() to finish the activity but it is not working. Any suggestions?
Most likely you have several instances of the same activity. To resolve this kind of issues create your own parent Activity class e.g. MyRootActivity which will hold static list of all of available/alive activities:
public class MyRootActivity extends Activity
{
private static final String TAG=MyRootActivity.class.getName();
private static ArrayList<Activity> activities=new ArrayList<Activity>();
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
activities.add(this);
}
#Override
public void onDestroy()
{
super.onDestroy();
activities.remove(this);
}
public static void finishAll()
{
for(Activity activity:activities)
activity.finish();
}
}
For that all of your activities need to be children of MyRootActivity.
Then when you are about to sure that you're closing your application - just call MyRootActivity.finishAll();
Create a static Activity object which activity finish on other activity and assign activity in this i.e you can can add more activities
public class demoActivity extends AppCompatActivity {
public static Activity self_intent;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.demo_activity);
selfintent=this;
}
//Other functions--------------
}
do same for other activities
on other
public class finishingActivity extends AppCompatActivity {
public Button activityCloseBtn;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.finishing_activity);
activityCloseBtn= (Button) view.findViewById(R.id.activity_close_btn);
activityCloseBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
demoActivity.selfintent.finish(); //for finish demoActivityactivity
//for other activities Activity.selfintent.finish();
finish(); //for finish current activity
}
});
try calling super.onPause() first and later call finish() inside your onPause() stub

Categories

Resources