I'm a bit confused really. When it says that
Activities with singleInstance launchmode uses the singleton pattern, and that instance will be the root activity of a new task
When it says new task, does it mean that the launching activity will get executed in a new thread??? Or the android system just uses flags to control activities navigation internally with datastructures within the Main Thread
Activities with singleInstance launchmode uses the singleton pattern
This is misleading. Activities, whatever the launchmode, should never be considered singletons. True, there is only one instance of the Activity when using singleInstance, but the normal Activity lifecycle still occurs and it is not safe to keep a static reference to any Activity.
When it says new task, does it mean that the launching activity will get executed in a new thread???
No, all Activities live in the main thread and you should only interact with them there. The confusion comes from the usage of the word task, which does not refer to threading in this case. It refers to a group of Activities. There's a useful reference concerning this subject in the official docs.
does it mean that the launching activity will get executed in a new thread???
No it does not.
All app's activities (and services and receiver) are executed on a single thread called the main thread.
You can find a good read on the Android threading model here.
Related
The question, How can I get the current Activity? has been asked dozens of times on Stackoverflow and other sites and there are many proposed approaches. However, all of them have drawbacks in one form or another.
In this posting, I am assuming that there is no solution provided for this in Android's APIs, e.g., something like: Application.getTask().getRootActivity().
Wouldn't it be nice if there was :-)?
So, to be clear, I'm not asking for an answer to How can I get the current Activity?
Instead, I am asking for the reason that such a capability has not been provided. Given that each running app has a task (assuming that the task hasn't been emptied) and each such task has a root Activity, it would seem to be easy to provide access to that root Activity.
The fact that that such access is not provided, when it is so clearly desired, implies to me that there is something fundamental about the Android architecture that I don't understand.
What is it that I'm missing? Why is this information not provided by the Android APIs?
For background, here is a section summarizing some of the approaches that have been proposed. I found the following two links particularly informative (each of the approaches below is presented at one or both of the links).
Links
How to get current foreground activity context in android?
Android: How can I get the current foreground activity (from a service)?
Approaches
Static Hook
Reflection
ActivityManager
Other (Instrumentation, AccessibilityService, UsageStatsManager)`
ActivityManager
The ActivityManager approach only provides the name of the Activity class, not the current Activity instance. E.g., for a Context instance c:
c.getSystemService().getActivityManager()
.getAppTasks().get(0).getTaskInfo()
.topActivity().getClassName()
Reflection
My favorite is reflection, as proposed by _AZ, but that approach is fragile, given that it relies on internals. What I would like to see from Android is this approach provided via a standard API that developers could then safely rely on.
Static Hook
The most common approach is using a static hook to save a reference to the currently running Activity. The hook can be either per-Activity or per-Application. Memory leaks can be avoided by saving/destroying the hook's value (e.g., in onCreate()/onDestroy(), onStart()/onStop(), onPause()/onResume()). However, issues can arise when multiple Activities are involved (e.g., due to overlapping lifecycles -- see below).
I implemented a static hook approach which does the following (to be perfectly transparent, I haven't implemented #1 yet -- I am currently using a per-Activity static hook, which is a bug).
Provides a class that extends Application to provide the hook. The hook contains a Stack; each node in the stack is a simple ActivityInfo class which contains a reference to an Activity instance as well as the state of that instance (CREATED, STARTED, RESUMED).
Provides a class called ActivityTracker that extends Activity. I then extend each of my Activities with ActivityTracker. ActivityTracker uses its lifecycle callbacks to push/pop itself to/from the stack and to update its state -- my other Activities don't have to do anything.
In theory, this would allow me to always know the full state of the task's back stack -- the full set of Activities, including the root Activity, as well as their current state. In practice, however, there is a twist -- when one Activity starts another Activity, their lifecycles overlap. During that period, peeking at the stop of the stack can yield an unexpected Activity instance.
From: https://developer.android.com/guide/components/activities/activity-lifecycle.html#soafa, "Coordinating activities":
Here's the order of operations that occur when Activity A starts
Acivity B:
Activity A's onPause() method executes.
Activity B's onCreate(), onStart(), and onResume() methods execute in sequence. (Activity B now has user focus.)
Then, if Activity A is no longer visible on screen, its onStop() method executes
Of course, this could be managed also. The bottom line is that we do have a global context available for storing information (the Application) and we do have full information about Activity lifecycle transitions, so with enough effort I believe that this static stack-based approach could probably be made pretty bullet-proof.
But in the End
But in the end it feels like I am simply rewriting code which probably already exists internally for managing an Activity back stack, which is why I ask (in case you've forgotten):
Why is there no Android API for getting the current Activity?
UPDATE
In this update, I'll summarize what I've learned from this thread and my own experiments and research. Hopefully, this summary will be useful to others.
Definitions
I'm going to use the following definitions for "Activity Visibility States", based on the Activity State definitions at https://developer.android.com/guide/components/activities/activity-lifecycle.html.
-----------------------------------
Visibility State Definition
-----------------------------------
Not Visible Created+Stopped
Partially Visible Started+Paused
Fully Visible Resumed
-----------------------------------
Issues
The very definition of "Current Activity" is murky. When I use it, I mean the single Activity in the Fully Visible state. At any given instant, there may or may not be such an Activity. In particular, when Activity A starts Activity B, A's onPause() gets called and then B's onCreate(), onStart() and onResume(), followed by A's onStop(). There is a stretch between A's onPause() and B's onResume() where neither is in the Fully Visible state, so there is no Current Activity (as I define it). Of course, there are also situations where a background thread may want to access a Current Activity and there may or may not be an Activity at all, much less a Current Activity.
I've also realized that I may not always need a Current ("Fully Visible") Activity. In many cases, I may simply need a reference to an existing Activity, whether or not it is currently visible. In addition, that reference might be to just any Activity (for situations where I need to pass a generic Activity reference to some API method) or it might be to a specific Activity subclass instance (so that I can trigger some code specific to that Activity subclass).
Finally, there is the need to understand when Activity lifecycle callbacks are called by the main UI looper and how events like configuration changes are handled. For example, if I create a DialogFragment using an Activity intance which is currently in the "Not Visible" state, will it ever get displayed and, if so, when? Along similar lines, it turns out that the onDestroy() and onCreate() methods caused by a configuration change are contained in the same message in the UI's message queue (see Android UI Thread Message Queue dispatch order), so no other messages will be processed between those two callbacks (during a configuration change). Understanding this level of processing seems to be critical, but documentation on it is sorely lacking, if not missing completely.
Approaches
Here is a collection of approaches that can be used to address most of the above situations.
Background
For discussion, assume Activity A and Activity B, where A creates B.
Generally speaking, a "global" variable can be created by making it
"public static" on pretty much any class. Conceptually, extending
the Application class and adding it to the extended class would be
good, but if that's too much work it could be included (for
instance) in one of the Activity classes.
Generic Activity Reference
Useful whenever a generic Activity is needed.
Create a global variable. In both A and B, have onCreate() set it to "this" and onDestroy() set it to null.
Topmost Activity Reference
Useful whenever you want to access the currently visible Activity.
Create a global variable. In both A and B, have onResume() set it to "this". This approach works fine unless all Activities exit, in which case you may need to create a separate flag to indicate that situation. (That flag could be the Generic Activity Reference implementation mentioned above.)
Specific Activity Reference
Useful whenever a handle to a specific Activity subclass instance is needed.
In both A and B: create a global variable in the Activity subclass itself. Have onCreate() set it to "this and onDestroy() set it to null.
Application Context
Useful whenever a Context spanning the lifecycle of the entire app is needed or when you don't care about using a specific Activity Context (e.g., to create a Toast from a background thread).
You can get this from Activity's getApplication() and store it on a static hook.
Handling Configuration Changes
There may be times when you want to stop/start a background thread only across an Activity "session", where I define "session" to include the series of Activity instances which may be created and destroyed due to configuration changes. In my particular case, I have a Bluetooth Chat Activity and an associated background thread to handle the network connection. I don't want to have the connection destroyed and created each time the user rotates the device, so I need to create it only when one doesn't exist and destroy it only if a configuration change isn't underway. The key here is understand when onDestroy() is called due to a configuration change. This can be done with or without fragments. As is often the case, I prefer the non-fragment approach since the fragment approach doesn't seem worth the extra complexity to me.
Approach 1: Without Fragments
In onCreate(), create the background thread if it doesn't exist yet. In onDestroy(), destroy the background thread only if isFinally() returns false.
Approach 2: With Fragments
This works well because the FragmentManager will store fragment instances across configuration changes if setRetainInstance(true) is used. For an excellent example of this, see http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html. The example is for AsyncTasks, but can also be applied to managing a background thread (just create the thread instead of an AsyncTask in the fragment's onCreate() and then destroy the thread in the fragment's onDestroy()).
Closing
Fully understanding these issues requires a deep understanding of how the UI looper processes its message queue -- when Activity callbacks are called, how other messages are interleaved with them, when display updates occur, etc. For instance, if a DialogFragment is created using an instance of a non-visible Activity, will it get displayed at all and, if so, when?
Perhaps some day Android will provide a deeper API to Tasks and their associated backstacks, along with documentation describing the UI's message processing and associated mechanisms in more detail. Until then, more "source code and/or ... empirical analysis" :-).
Thanks,
Barry
If all you want you want to know is which Activity is foremost and accepting user interactions, just create a BaseActivity that extends Activity and override onResume() and save a reference to "this" in a static variable. All of your other activities should extend BaseActivity. You're done.
The short answer I would guess is that only one activity can ever be active at a time in a given app, and that activity obviously knows who it is (it is itself) -- so the only answer any activity can get to "what activity is currently active" can only ever be "you are, silly".
For simple apps with a clear division between the different activity classes, this works fine, and so that's a great percentage of most of the apps in the play store. It doesn't work so hot when you're getting real clever with encapsulation and polymorphism, as I'm sure you've discovered, but I don't think Google is really targeting those types of developers.
Just my $0.02, I don't think you'll get an "official" answer here.
Need to do a transition from one activity to an other. Need startActivity(intent); executed on main thread on it can be a worker thread? I would choose main thread concept, because there are GUI related operations. What do you think?
Yes, it should, but as others stated is not required to do so.
Basically, "where", in the sense of Context, your new Activity should be placed in its stack or under/above others.
From documentation:
Launch a new activity. You will not receive any information about when the activity exits.
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.
Previous answers have revealed that the startActivity method itself ensures the relevant operations are run on the main thread, so it doesn't actually matter where you call it: Is it safe to launch and activity from a non-ui thread?
If i'm not wrong... startActivity() internally executes in the UI thread so there's no discussion :)
I have an app that is very hierarchical (activities are similar to League > Team > Position > Player) and so I've made each activity singleTop in order to keep navigation sensible and to prevent duplicate instances.
Now I'm making my second app and I've seen it suggested to declare my application to be singleTask to prevent duplicate instances. Could someone help explain the advantages of each approach?
My new app is just an activity with 3 fragments and then I'll probably add a settings activity and maybe a FAQ.
EDIT: I just realized that singleTask is NOT preventing duplicate instances of my app, as I had thought. Now looking for the right way to handle this...
I think your definition of singleTop and singleTask is a little off. SingleTop could produce a duplicate instance. Lets use your example, League > Team > Position > Player. If there is a button in the player screen that will take you to the league screen, it will become League > Team > Position > Player > League.
Whereas singleTask guarantees that only one instance of the activity can exist.
Android activity launchMode
4 modes...
"standard"
"singleTop"
"singleTask"
"singleInstance"
The default mode is "standard".
The modes fall into two groups. standard and singleTop comes in one side and singleTask and singleInstance comes in another side.
The main difference between standard and singleTop is in standard, every time a new intent for standard activity, a new instance is created. In case of singleTop too, a new instance is created but an instance of the activity is already in top of the stack, it wont create a new instance.
Actually, the issue comes , when we download an application from a server and launch it and open it from there itself. After launching the application, press home button. Then click the all programs and select the icon of the application from home screen. Then another activity will be created in the case of standard, but in singleTop , no new instance will be created.
The "singleTask" and "singleInstance" modes also differ from each other in only one respect:
A "singleTask" activity allows other activities to be part of its task. It's at the root of the activity stack, but other activities (necessarily "standard" and "singleTop" activities) can be launched into the same task.
A "singleInstance" activity, on the other hand, permits no other activities to be part of its task. It's the only activity in the task. If it starts another activity, that activity is assigned to a different task — as if FLAG_ACTIVITY_NEW_TASK was in the intent.
http://smartandroidians.blogspot.in/2010/04/activity-launch-mode-in-android.html
I found the answer here:
http://www.intridea.com/blog/2011/6/16/android-understanding-activity-launchmode
"singleTop":
The difference from 'standard' is, if an instance of activity already exists at the top of the current task and system routes intent to this activity, no new instance will be created because it will fire off an onNewIntent() method instead of creating a new object. Let's take the Twitter-oauth integration as example.
"singleTask":
A new task will always be created and a new instance will be pushed to the task as the root one. However, if any activity instance exists in any tasks, the system routes the intent to that activity instance through the onNewIntent() method call. In this mode, activity instances can be pushed to the same task. And if the user clicks the BACK key from the singleTask activity, the system will return the user to the previous activity.
From Understanding Activity launch mode:
standard (default) :- Multiple instances of the activity class can be
instantiated and multiple instances can be added to the same task or
different tasks. This is the common mode for most of the activities.
singleTop :- The difference from standard is, if an instance of the
activity already exists at the top of the current task and the system
routes the intent to this activity, no new instance will be created
because it will fire off an onNewIntent() method instead of creating a
new object.
singleTask:- A new task will always be created and a new instance will
be pushed to the task as the root. However, if any activity instance
exists in any tasks, the system routes the intent to that activity
instance through the onNewIntent() method call. In this mode, activity
instances can be pushed to the same task. This mode is useful for
activities that act as the entry points.
singleInstance:- Same as singleTask, except that the no activities
instance can be pushed into the same task of the singleInstance’s.
Accordingly, the activity with launch mode is always in a single
activity instance task. This is a very specialized mode and should
only be used in applications that are implemented entirely as one
activity.
I did not find any thread on StackOverflow that answer my question. I have already seen this Android singletop singleinstance and singletask but that question is related to his project scenario.
What are the differences between singleTask and singleInstance?? I have read the docs but could not understand..
I have read this thread also Android singleTask or singleInstance launch mode? but I could not understand. Sorry
What is unclear from the docs ?
The "singleTask" and "singleInstance" modes also differ from each
other in only one respect: A "singleTask" activity allows other
activities to be part of its task. It's always at the root of its
task, but other activities (necessarily "standard" and "singleTop"
activities) can be launched into that task. A "singleInstance"
activity, on the other hand, permits no other activities to be part of
its task. It's the only activity in the task. If it starts another
activity, that activity is assigned to a different task — as if
FLAG_ACTIVITY_NEW_TASK was in the intent.
singleTask :- A new task will always be created and a new instance will be pushed to the task as the root. However, if any activity instance exists in any tasks, the system routes the intent to that activity instance through the onNewIntent() method call. In this mode, activity instances can be pushed to the same task. This mode is useful for activities that act as the entry points.
singleInstance:- Same as singleTask, except that the no activities instance can be pushed into the same task of the singleInstance’s. Accordingly, the activity with launch mode is always in a single activity instance task. This is a very specialized mode and should only be used in applications that are implemented entirely as one activity.
SingleInstance is just like a singleton and also its stack is like final class can't be extended.
Its always single in its stack.and always there.
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.