I'm calling context.startActivity(intent) from within a seperate OnClickListener class. In order for this to work I had to set the FLAG_ACTIVITY_NEW_TASK on the intent.
That all works as expected, but I'm wondering if there are any implications to doing this that I'm not aware of. Will this create any problems in terms of performance? Does it reflect poor design on my part?
What do you think?
From the Android docs: "This flag is generally used by activities that want to present a "launcher" style behavior: they give the user a list of separate things that can be done, which otherwise run completely independently of the activity launching them."
More from the Android docs: "Note that if this method is being called from outside of an Activity Context, then the Intent must include the FLAG_ACTIVITY_NEW_TASK launch flag. This is because, without being started from an existing Activity, there is no existing task in which to place the new activity and thus it needs to be placed in its own separate task."
As you are starting a new activity each time and adding this to the stack, if you leave that activity and then start another with the onClickListener you might run the risk of starting another activity instead of resuming the previous activity. I think changing the flag to FLAG_ACTIVITY_RESET_TASK_IF_NEEDED should fix this.
Related
I would like to stop an activity started with implicit intent(using Intent.ACTIN_CALL etc). Is there a way to do this?
Also when we use "startActivity()" function of Context(abstract class), how does it actually start it?
Thanks.
No, you cannot stop an activity.
To answer your second question, when you call startActivity() the Intent that you pass as a parameter is given to the Android framework. The framework performs the appropriate Intent resolution using the contents of the Intent to determine which activity to actually start. Then, depending on the activity that needs to be started, it may need to create a new OS process, instantiate the Application object for that application and finally instantiate the activity object and call onCreate() on it. However, there are other things that may or may not happen during this process, depending on the state of the task that contains the activity, the Intent flags used, the launchMode of the activity as defined in the manifest, etc.
does the launchMode of the launcher activity in the manifest get ignored?
The android documentation says that the default launchMode is "standard" but this isn't logic for me if this would be applied to the main activity of an app because each time you start the app, another task would be created in the instance of the app.
Well, I delved into Android sources myself and found the following thing.
The launcher starts apps using the method startActivityAsUser in LauncherAppsService. The intent is constructed using these lines:
Intent launchIntent = new Intent(Intent.ACTION_MAIN);
launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
launchIntent.setComponent(component);
launchIntent.setSourceBounds(sourceBounds);
launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
According to Android documentation, the flag FLAG_ACTIVITY_NEW_TASK means:
When using this flag, if a task is already running for the activity you are now starting, then a new activity will not be started; instead, the current task will simply be brought to the front of the screen with the state it was last in.
This effectively and unconditionally overrides launchMode specified (or omitted to default behaviour) in the app, and ignores this attribute.
I think this demonstrates that the documentation is not clear (or complete) enough. Without such deep investigations of the core source codes everyone can get unexpected results now and then.
You are confusing two things. One is launchMode and the other is "what happens when the user selects an app icon from the HOME screen, or selects a task from the list of recent tasks". These are 2 completely different things.
launchMode
Each Activity has a specified launchMode (the default is "standard" or "multiple". This tells Android how to start this Activity, and there are many factors that can contribute to the "interpretation" of the launchMode. It depends on what other flags may have been specified in the Intent used. It depends on which task requested the launch of the Activity (or if the launch was requested from a non-activity context, like from a Service or BroadcastReceiver). It depends on whether or not an existing instance of the Activity is already active in the specified task, etc.
Behaviour on selecting an app icon from the HOME screen or list of installed applications
When the user selects an app icon, startActivity() is called with an Intent containing the following data:
ACTION=MAIN
CATEGORY=LAUNCHER
Component is set to the package name and the class name of the Activity that is defined in the manifest with ACTION=MAIN and CATEGORY=LAUNCHER
Flag FLAG_ACTIVITY_NEW_TASK and FLAG_ACTIVITY_RESET_TASK_IF_NEEDED are set.
Regardless of the launchMode definition of the Activity to be launched, calling startActivity() with an Intent like this causes the following behaviour:
If there is already an existing task whose task affinity matches the Activity being started (in simple terms, if the app is already running), Android will simply bring the existing task to the foreground. That's it. It doesn't create an instance of any Activity. It doesn't call onNewIntent() on any Activity. It does nothing other than bringing the existing task to the foreground. This is why, even if you specify launchMode="standard" for your launcher Activity, Android doesn't create a new instance every time you click on your app icon.
If there isn't already an existing task whose task affinity matches the Activity being started (in simple terms, if the app isn't already running), Android will create a new task and launch the Activity into that task. launchMode doesn't play a role here, since there is absolutely no difference between the launch modes when launching a single Activity into a new task. Android always creates a new task and always creates a new instance of the Activity as the root of that task.
This behaviour is also the same when the user selectsa task from the list of recent tasks. If the task is still running, Android just brings the task to the foreground, does not start any new Activity instances and does not call onNewIntent(). If the task is no longer running, Android creates a new task and launches the launcher Activity into that task. The only difference here is that the flag FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY is also set in the Intent if the user selected a task from the list of recent tasks.
I hope this answers your question.
See this answer for a very detailed explanation of FLAG_ACTIVITY_RESET_TASK_IF_NEEDED and task reparenting in general.
Think of everything except the opening activity as an abstract implementation. Declaring an activity as
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
Will cause it to open first. Subsequent activities are Overriden at the time an Intent is formed to navigate between activities. The overrides are represented as intent flags.
A list of intent extras:
http://developer.android.com/reference/android/content/Intent.html
With flags being commands you'd otherwise have written in the Manifest.
You are right.The default mode is "standard".
According to android documentation
*In standard mode ,Every time there's a new intent for a "standard" activity, a new instance of the class is created to respond to that intent. Each instance handles a single intent.
*.If the parent activity has launch mode standard (and the up intent does not contain FLAG_ACTIVITY_CLEAR_TOP), the current activity and its parent are both popped off the stack, and a new instance of the parent activity is created to receive the navigation intent.
The behavior of Activity set to standard mode is a new Activity will always be created to work separately with each Intent sent. Imagine, if there are 10 Intents sent to compose an email, there should be 10 Activities launch to serve each Intent separately. As a result, there could be an unlimited number of this kind of Activity launched in a device.
Behavior on Android pre-Lollipop
standard Activity would be created and placed on top of stack in the same task as one that sent an Intent.
For example, when we share an image from gallery to a standard Activity, It will be stacked in the same task as described although they are from the different application.
If we switch the application to the another one and then switch back to Gallery, we will still see that standard launchMode place on top of Gallery's task. As a result, if we need to do anything with Gallery, we have to finish our job in that additional Activity first.
Behavior on Android Lollipop
If the Activities are from the same application, it will work just like on pre-Lollipop, stacked on top of the task.
But in case that an Intent is sent from a different application. New task will be created and the newly created Activity will be placed as a root Activity like below.
Source from here
I have a MainActivity class, which launches a RaceActivity at some point. If, later, the RaceActivity exits, I want the MainActivity to return, with all its views. However, it seems to be created anew each time. I have implemented the proper section of onOptionsItemSelected, but when I click the back button, I get a new instance each time, or at least the programmatically added views are gone. What can I do to fix this?
Edit for clarification:
I am fine using onCreate with a bundle to restore these views, but I thought that happened automatically if you recreate the same instance of an object. I want to keep programmatically created views when the activity is recreated. Alternatively, I want the activity to stop being destroyed when the user returns to it. (I tested, and it gets destroyed as soon as the use returns.)
Accept my answer if it helps you. it take hours to find the solution..
override onBackPressed()
Intent intent = new Intent(FromAnyActivity.this, CurrentActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
and insert the code in it.. It will reorder your Activity from stack and your views and data will remain where it was. There was another way by adding SingleInstance launch mode.. read these link may help..
Add the following to your MainActivity declaration in the AndroidManifest file:
android:launchMode="singleTask"
According to the Android APIs, this addition is for: "The system creates the activity at the root of a new task and routes the intent to it. However, if an instance of the activity already exists, the system routes the intent to existing instance through a call to its onNewIntent() method, rather than creating a new one."
If the above doesn't work, I believe you can also try adding this as well to the MainActivity in your AndroidManifest file:
android:alwaysRetainTaskState="true"
According to the Android APIs, this addition is for: "Whether or not the state of the task that the activity is in will always be maintained by the system — "true" if it will be, and "false" if the system is allowed to reset the task to its initial state in certain situations. The default value is "false". This attribute is meaningful only for the root activity of a task; it's ignored for all other activities."
I ran into a similar issue with the recent list in that there seem to a handful of conditions where an app will be completely destroyed but some other process will launch the app cold from the last activity that was being used. Since my app has a state that is built up over several designated activities I need to prevent this (i.e. null refs from onCreate()).
Without checking for state is all my onCreate() functions is there a way to just prevent this?
Also, other than the launcher, recents, the back button from other apps - are there more conditions where another thing can launch my app if I have not giving manifest permission to launch it explicitly with an intent?
Thanks!
If I understand this correctly, you have initializations in activity B that rely on activity A having passed them in. If an intent launches activity B first, without it being active, or being launched by A first, your activity will crash.
Easiest solution I can come up with is make your activity A (I assume your main activity) the broadcast listener for all the intents you wish to handle, and based off the intent action, dispatch to the appropriate child activities (B, C, whatever). That way activity A does all your initialization, and you can still launch into the appropriate activity to handle the original intent you wanted to.
Alternatively. If you detect your children activities are in an invalid state, you could put initialization into a parent activity that all your activities extend from. That way you should be able to initialize properly if the activity is a fresh launch. I'm not really a fan of this, I prefer making sure my activities are dependency injected with appropriate data.
I'm simply trying to change between xml files/layouts.
In my main activity I have startActivityForResult(new Intent(this,playlist.class), 0);
I've added the class to my manifest, created the class where the package is com.site.mainactivity, and superclass is android.app.Activity.
I didn't "extends playlist" in my main activity
My logcat only shows "showStatusIcon on inactive InputConnection", "InputConnection = android.view.imputmethod.BaseInputConnection#40532b90, active client = false"
When I try to start the new activity/switch layout, my home screen shows, but my app is still running in the background. When I go back to it, the app takes me back to the main screen.
What am I doing wrong?
Thanks
This sounds like a problem with how the Activity stack is being maintained. Specifically this is because based on the Manifest properties, an Activity can have different properties that specify how the Activity should be treated by the manifest ie. if it is included in the Activity stack or not and/or Also this could include where the main entrance of the application is, and whether or not an external intent can go to a specific screen in the application.
With manipulation of this it is easy to control. Look up the ActivityManager and how tasks are retrieved and maintained and analyze the design flow of your application. You must fully understand how you want it to work to fully solve your problem. A flow chart would aid you in this diagnosis.
Learn to control your flow properly.
If you just want to change the layout, you can either:
call setContentView again
use singleTop and launch the same activity but with a different layout
close the first Activity with finish() after launching the second
What I did to bypass this hurdle was simply use getLayoutInflater().inflate(R.layout.main, null); as a View and then setContentView(v)
I just need to reinitialize events, views, etc so that the program runs as it did before it changed the view.