I want to detect each time the user opens the app, by tap on home / desktop icon. There seem not to be a straight forward way to do it. Found a few workarounds but nothing seems to be really reliable.
Things like, extend application object and use method "onCreate()", but this is not what I need because it's not called always when the user taps on the app's icon (can be just brought from the background, launching doesn't necessarily recreate the application), and also the application may be destroyed and recreated while running. Then Application.onCreate() will also be called.
There war also some approaches involving BroadcastReceiver and checking intent flags but everything seems to be also not quite reliable?
I need this because I want to track with Google Analytics, when the user opens the app.
Thanks
Whenever your application is launched by normal way [if user taps on icon on home launcher] then main Activity for which
<activity
android:name=".xyz"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
is defined, in this application onCreate method will surely be called. So here you can put you Google Analaytics tracking code.
In other ways, like broadcast receiver it really depends upon which activity is called upon and whether it is start of application. There too you can put in onReceive method
As far as i feel, Android has definate way of start an app, and its always reliable. Only lifecycle of Android are bit tricky.
Try to look into "android application lifecycle".
But onResume is launched every time you start your activity
Else try : onStart which is called every time your application has been sent to "background". It really does state so in the developer docs.
Related
Tested on Pixel 3a (both emulator and physical device (my used device)) API 30 (11.0).
Repo:
https://github.com/amdreallyfast/AndroidStartOnBootExample
Goal:
I'm trying to launch an android app on startup, but failing.
Note: I am well aware that this should not be done for apps designed for the general public. This is not that. At the moment, this is just concept exploration for a personal project. The larger goal is to tinker with a used Pixel 3a and turn it into a home utility device. I don't want to start the app manually every time I need to turn it on and would rather have it starting automatically, so I'm trying to find a way to launch the app at startup.
Also Note: Because this is a project to start on boot, I can't use the debugger for most of this and have to rely on notifications instead to detect progress.
Progress:
I've got a BroadcastReceiver that responds to the BOOT_COMPLETED intent by launching a Service. The service's onCreate(...) function creates a simple intent to start another app (at the moment, just Google Maps, which is readily available without additional software installation).
I've also got MainActivity, a simple program that has a button that uses an intent to launch the same Service. I use this to compare behavior between starting the service at startup and starting the service from an already-running activity.
Already tried setting the intent flag Intent.FLAG_ACTIVITY_NEW_TASK.
Problem:
Google Maps does not launch from the service when called during startup. I know that the service's code is correctly set up to launch the map intent because launching the MainActivity and pressing the button will launch the service and then start Google Maps just fine. I also know that the code running on startup got through to the point where it launched the map intent because notifications indicate as such.
The only difference that I'm noticing between not working and working seems to be the manner in which the service is started.
Documentation:
I found this android docs page: https://developer.android.com/guide/components/activities/background-starts. It says (in part):
Apps running on Android 10 or higher can start activities only when one or more of the following conditions are met:
The app has a visible window, such as an activity in the foreground.
<other possible conditions>
Why doesn't this start? Am I misunderstanding this? Google Maps most certainly has a visible window, so I am expecting to be able to start it.
Note: Again, I'm not planning on releasing my app to the general public. This is just for me.
The larger goal is to tinker with a used Pixel 3a and turn it into a home utility device
Write a launcher app (i.e., have your activity respond to ACTION_VIEW/CATEGORY_HOME) and set it as your default launcher. It will automatically start when the phone starts, just as your current default launcher does. And, you can put a button or something in your own launcher that launches the real launcher via an explicit Intent.
This would allow you to skip the on-boot receiver and the service.
Why doesn't this start?
You do not qualify for a background activity start.
Google Maps most certainly has a visible window, so I am expecting to be able to start it.
First, presumably it does not have a visible window right after boot.
Second, you are not writing the Google Maps app, and Google Maps is not trying to start an activity from the background. You are writing your own app, and your own app is trying to start an activity from the background. And, since your own app does not have a visible window right after boot, it does not qualify for a background activity start under the "app has a visible window" rule.
Following up on the answer by #CommonsWare, here is my activity's configuration in my app's manifest file (just for the sake of completeness):
<activity
android:name="com.example.androidstartonboot.MainActivity"
android:launchMode="singleTask"
android:stateNotNeeded="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Note: Strictly speaking, launchMode and stateNotNeeded are not necessary for MainActivity to successfully launch on startup, but my understanding is that it is good practice to add them to a launcher. Documentation: https://developer.android.com/guide/topics/manifest/activity-element
To enable:
Run the app (or run the debugger) to install.
Press the "Home" button (solid dot on Android 11). Android should present an option for which app to use to respond to the LAUNCHER intent. There should be two options: "Pixel Launcher" (the Android default) and the app who's MainActivity is configured as above.
Select your app and choose "Always use this app".
Now, every time you press the "Home" button, your app should run.
Note: To restore the "Pixel Launcher" as the default launcher:
Swipe down from top
-> Settings
-> Apps & Notifications
-> All Apps
-> Pixel Launcher
-> Advanced
-> Home (should say "No" at this point)
-> <choose "Pixel Launcher">
This was tested on Android Studio Bumblebee | 2021.1.1 Patch 2, in a Kotlin project.
Note: This does not work if there is also a BroadcastReceiver that the manifest is configuring to respond to the intent filter <action android:name="android.intent.action.BOOT_COMPLETED". I tried it. Disabling the BroadcastReceiver allowed this to work. Re-enabling it prevented MainActivity from launching on startup. So that needs to be commented out/removed before this launcher will work.
I'm developing an Android application and I would like to emulate the same behavior of the official Google Plus app when it is opened, which is:
If the app is still in the Recent Apps list and you open it (from icon or from recent apps, it doesn't matter) you will resume the app from where you left.
If the app is no longer in the Recent Apps list and you open it, you will be greeted with a splash screen and then directed to the Home page.
My app has one activity that uses a navigation drawer and several fragments as pages. My goal is to retain the current fragment and display it when the app is resumed from the Recent Apps. I can manage to do so using SharedPreferences by storing the tag of the current fragment and loading it when the user reopens the app. The problem with is solution is that this kind of data is persistent so the user will always be greeted to the last page even if he first removes the app from the Recent Apps list and reopens it.
So how can I detect whether the app is already in the Recent Apps list or not? Or is there any method that is called when an app is removed from that list so I can clear the last fragment tag from SharedPreferences? Or am I using the wrong approach?
Thank you for you patience in reading this.
When you return to your app through the recent-tasks list, there are three possibilities:
It has been a long time, over 30 minutes, and your process is not running. In that case, Android just launches your app as if the user tapped on your home screen launcher icon. You are not given your saved instance state, as it is deemed to be stale.
It has not been a long time, so Android wants the user to think that your app has been running since they left it. However, due to memory pressure, Android terminated your process while it was in the background. In this case, Android forks a new process for you, creates an instance of your activity, and passes to you your saved instance state Bundle in onCreate() and onRestoreInstanceState().
Your process is already running. In that case, your activity is just brought back to the foreground. You do not need your instance state, as your activity instance is still running. Android has not touched your widgets, and so if your UI is not the way you want it to be, that is your own fault, because you did something (e.g., in onPause() or onStop()) that screwed up your UI. From your descriptions, I am interpreting it that you are testing this scenario, in which case onRestoreInstanceState() is not called, because it is not needed.
So, as long as you do not screw up your own UI, your app will work as you described it for Google Plus, so long as you handle the saved instance state for scenario #2 above.
On Android 5.0+, there are related scenarios tied into the PersistableBundle that you can use with variations of onSaveInstanceState() and kin. I have not played with the PersistableBundle much and so I do not have any particular advice related to it.
As it turns out, the behavior I mentioned is automatic and there was a problem with my project that prevented it: this was the activity in my AndroidManifest.xml
<activity android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar"
android:noHistory="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
android:noHistory needs to be set false:
A value of "true" means that the activity will not leave a historical trace. It will not remain in the activity stack for the task, so the user will not be able to return to it. - Documentation
I have found very strange bug with the Android application, while installing the application in Android Device with given flow.
Installed the app from playstore(old version).
Launched the application(Now I'm in the HomeScreen,.i.e., HomeActivity).
Now, I upgraded the app by installing the latest build(under production build, yet to be released to playstore).
Click the launcher icon, wait till Home Screen becomes visible and keep the app in the background by pressing menu button.
Now, Launch the application by clicking launcher icon.
In this case, Splash Screen(Activity) gets launched and then takes me to the home screen. In the logs, call goes to onStop() of the HomeActivity. This means Activity is not destroyed. So, When I click launcher icon, it should resume the HomeActivity, instead it recreates the splashActivity. But when i launch the app from background, activity resumes and no splash screen gets displayed.
Is it a correct behavior? If so, then I'm not getting the callback to onDestroy().
Below is my activity code in the manifest:
<activity
android:name="com.app.ui.HomeActivity"
android:label="#string/app_name"
android:launchMode="singleTask"
android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustNothing">
</activity>
<activity
android:name="com.app.ui.SplashActivity"
android:label="#string/app_name"
android:screenOrientation="sensorPortrait"
android:theme="#android:style/Theme.Translucent.NoTitleBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
I did not set any launch mode to SplashActivity. And after some time, it becomes proper and splash screen is not shown.
Also, when i launch the app from background or press back button and then click the app icon, this bug is not reproduced. This happens only when I click launcher icon, keeping app in the background and after some time, it becomes proper.
Also, when I installed the application without updating, this issue didn't occur. Only when I update the apk, this happens
Why this happens in the initial launches..Is it a bug in the android..?If so, How to avoid this issue..
The reason the app is closed after some time in the background is because your device's kernel is killing the process in order to run more processes in it's place. I am assuming you are accessing other apps while your app is running in the background, and that is why it is getting killed (and therefore skipping the onDestroy() call in the Android lifecycle!).
From the documentation on Android Developer's guide to Activity Lifecycle for onDestroy():
Note: do not count on this method being called as a place for saving data! For example, if an activity is editing data in a content provider, those edits should be committed in either onPause() or onSaveInstanceState(Bundle), not here. This method is usually implemented to free resources like threads that are associated with an activity, so that a destroyed activity does not leave such things around while the rest of its application is still running. There are situations where the system will simply kill the activity's hosting process without calling this method (or any others) in it, so it should not be used to do things that are intended to remain around after the process goes away.
Link to documentation
I am creating a cross platform app in Adobe Flex with AIR 3.3 SDK. For Android, I have created a native extension which launches a native android activity with a simple view in it by firing an Intent.
The issue is that when we minimize the app and resume it by either choosing the app icon from apps menu or by long pressing home button to get list of recent apps, Android automatically calls the onDestroy of the native android activity and kills it. The same scenario works perfectly fine on Android 4.0. The problem is happening only on Android 2.x devices. We haven't been able to test honeycomb yet.
After reading the Android documents, I understand that onDestroy is either called when someone calls finish on the activity or if the device is running low on space. And, to distinguish between the both, one can use the isFinishing() method. This would return true if activity has been destroyed by calling finish.
In our case, in the scenario described above, activity's finish function is not called. onDestroy is called when the app resumes but isFinishing() still returns true. This suggests that the app is not low on memory. I have tried adding all kind of Flags to the intent but nothing changes the behavior.
I have no idea from where else can the onDestroy function be called? I need to figure out a way to stop the native activity from being destroyed on app resume.
The code to launch the native activity is something like this:
Intent intent = new Intent("android.intent.action.K12");
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("params", parameters);
context.getActivity().startActivity(intent);
The entry for the activity in the manifest goes like this:
<activity android:name="com.k12.main.MainActivity">
<intent-filter>
<action android:name="android.intent.action.K12" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
I have read a lot of blogs and SO questions but could not get around this issue. Please help.
I'm developing an android service application, which reacts on some intents. As you know, intents won't trigger until the app is launched for first time. Because my app is not interactive, I'd like it not to be shown in the launcher (app list). I can do this by removing
<category android:name="android.intent.category.LAUNCHER"/>
from the manifest file, but after that, how do I execute the app, as it is not shown anywhere? :|
Thanks.
What about disable the launcher icon after the application was launched the first time?
http://www.helloandroid.com/tutorials/removing-app-icon-launcher
Although this
the icon will only disapper when the launcher is restarted, so likely on next phone reboot, forcing the launcher to restart is not recommended"
doesn't sound good...
how do I execute the app, as it is not shown anywhere?
So you have to use BroadcastReceiver So similar topic where your can find similar solution. Check this
If your application is serviced based, responding to intents, why do you need to execute it? Won't the intents start your application?
Make sure you include the right intent filters in your manifest. Without them intents won't trigger your services.
http://developer.android.com/guide/topics/manifest/intent-filter-element.html