Intent for activity brings another activity to front - android

I'm creating an intent for a custom app shortcut like following:
Intent.ShortcutIconResource icon = ...;
Intent intent = new Intent();
Intent launchIntent = new Intent(getThis(), HandleShortcutActivity.class);
// add a few user settings
And the activity handles the intent like following:
public class HandleShortcutActivity extends AppCompatActivity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_helper);
// get data from intent
// ...
// handle the action
// ...
// finish this activity instantly again
finish();
}
}
And here's my manifest:
<activity
android:name=".activities.MainActivity"
android:windowSoftInputMode="adjustPan"
android:launchMode="singleTask"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".activities.HandleShortcutActivity"
android:configChanges="orientation|screenSize"
android:excludeFromRecents="true"
android:noHistory="true"
android:theme="#style/Theme.Transparent"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
Problem
If MainActivity is runnning in background and my shortcut intent is started, my MainActivity is broought to front. Why? How can I avoid this?

What you need here is to set a 'Task Affinity' so that your task is created as a part of a new stack that is not related to your MainActivity. Then, when you finish() it, it would close the HandleShortcutActivity as opposed to going "back" to MainActivity
From the official docs:-
android:taskAffinity
The task that the activity has an affinity for. Activities with the
same affinity conceptually belong to the same task (to the same
"application" from the user's perspective). The affinity of a task is
determined by the affinity of its root activity. The affinity
determines two things — the task that the activity is re-parented to
(see the allowTaskReparenting attribute) and the task that will house
the activity when it is launched with the FLAG_ACTIVITY_NEW_TASK flag.
By default, all activities in an application have the same affinity.
You can set this attribute to group them differently, and even place
activities defined in different applications within the same task. To
specify that the activity does not have an affinity for any task, set
it to an empty string.
If this attribute is not set, the activity inherits the affinity set
for the application (see the element's taskAffinity
attribute). The name of the default affinity for an application is the
package name set by the element.
HandleShortcutActivity in your Manifest file after adding taskAffinity:
<activity
android:name=".activities.HandleShortcutActivity"
android:configChanges="orientation|screenSize"
android:excludeFromRecents="true"
android:noHistory="true"
android:theme="#style/Theme.Transparent"
android:launchMode="singleTask"
android:taskAffinity="">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
To explain what would happen in this case, see the below diagram with task #1 being your calling task/activity and task #2 being your HandleShortcutActivity
I found this article very useful when understanding the different Android Launch modes, and explains various scenarios you might face quite coherently.

Update your manifest...
<activity
android:name=".activities.MainActivity"
android:windowSoftInputMode="adjustPan"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

Remove android:launchMode="singleTask" from your Activity declaration in manifest file.
this launch mode search Activity in task stack and if it's available takes from the stack and not created a new instance of MainActivity.

Related

Android Deep linking and singleInstance/singleTask

Possible Duplicate Deep linking and multiple app instances. I have implemented Deep Linking in my app. I have Splash activity that is launcher and MainActivity that handles the Intent as defined in manifest:
<application
android:name=".MyApplication"
android:allowBackup="true"
android:fullBackupContent="true"
android:icon="#drawable/app_logo"
android:label="#string/app_name"
android:largeHeap="true"
android:theme="#style/AppTheme">
<activity
android:name=".ActivitySplash"
android:configChanges="orientation|screenSize"
android:label="#string/app_name">
<intent-filter>
<!-- Launcher activity -->
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ActivityMain"
android:alwaysRetainTaskState="true"
android:configChanges="orientation|screenSize"
android:exported="true"
android:label="#string/app_name"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="www.mywebsite.com"
android:pathPrefix="/something"
android:scheme="http" />
</intent-filter>
</activity>
<activity
android:name=".ActivitySignIn"
android:configChanges="screenSize|orientation" />
<activity android:name=".ActivitySignUp" />
</application>
I have set launch mode singleTask to handle onNewIntent(). Now what i want to achieve is that if user opens activity from DeepLinking and there is already some task going on in MainActivity I prompt user a dialog either he want to cancel current task and start new task (which is from deep linking). The issue is If i open another activity from MainActivity and user comes from DeepLinking Intent. Then it would kill the second activity and directly open MainActivity. What i want to achieve is that if app/activity is not running then Intent from DeepLink open as is. And if activity/app is already running then i prompt user to either close current task and perform DeepLink task/intent.
This doesn't really work the way you think it does. You are trying to use launchMode="singleTask", but since you haven't also set "taskAffinity", Android pretty much ignores your launchMode.
You should not need to use either of the special launch modes "singleTask" or "singleInstance" to get what you want.
Try using singleTop launch mode and see if this solves your problem. If ActivityMain is already open and you launch ActivityMain again using your deep-link, onNewIntent() should be called in ActivityMain.
You can also look at my answer to this question which describes a way to determine what Activity to show based on using a static variable to decide whether another Activity is in the stack or not.

singleTask activity not loading properly

I have an activity 'A' defined in Manifest like below:
<activity
android:name=".A"
android:launchMode="singleTask"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
When I launch my APP, that activity is always loaded from the start. It wont start from my prev activity.
When I remove android:launchMode, then it works as I expect.
Since you set android:launchMode="singleTask", the activity A will always be the root of your activities.
From DOCS:
In contrast, "singleTask" and "singleInstance" activities can only begin a task. They are always at the root of the activity stack. Moreover, the device can hold only one instance of the activity at a time — only one such task.
Default mode is standard. So, when you remove android:launchMode="singleTask", your APP returns to standard launch mode.
That's why if you app is always starting Activity A.
If you would like to start a different Activity on launch replace that in the xml name attribute that contains LAUNCHER
<activity
android:name=".ActivityB"
android:launchMode="singleTask"
android:screenOrientation="portrait"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Where Activity B is an alternate activity.

Root Activity is getting called again and again when coming from background to foreground instead of last activity in stack

I am developing an hybrid app using IBM worklight where I have to open another webview on the top of existing webview(Cordova webview),so i created a new activity(WebView Activity) to load my external page,but when i am going to background from webview activity by pressing home button and again coming to foreground my MainActivity getting called and restarts the app,I have used singleTop for my MainActivity in manifest file
<activity android:name=".MainActivity"
android:label="#string/app_name"
android:configChanges="orientation|keyboardHidden|screenLayout|screenSize"
android:launchMode="singleTop"
>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="com.main.sample.NOTIFICATION"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name=".WebViewActivity"
android:label="#string/app_name"
android:configChanges="orientation|keyboardHidden|screenLayout|screenSize"
android:launchMode="singleTop"
android:theme="#style/Theme.Transparent">
</activity>
I don't know why it is happening,I want my last activity to get resumed instead of main activity
Read documentation for the modes.This will explain you about what is happening:
"singleTask" and "singleInstance", should be used only when the > activity has an ACTION_MAIN and a CATEGORY_LAUNCHER filter. > Imagine, for example, what could happen if the filter is missing: An > intent launches a "singleTask" activity, initiating a new task, and > the user spends some time working in that task. The user then presses > the Home button. The task is now sent to the background and is not > visible. Now the user has no way to return to the task, because it is > not represented in the application launcher.
This is one potential solution.There are multiple ways to do this.
Try using the following code in the onCreate method of the activity that is specified as the Launcher Activity in the Manifest:
if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
finish();
return;
}
This will finish your Launcher Activity before it is displayed by detecting that there is already a task running, and your app should instead resume to the last visible Activity.

How to add flags to an APPWIDGET_CONFIGURE intent?

I have an activity registered on APPWIDGET_CONFIGURE:
<activity android:name="com.tahanot.activities.NearbyStops">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
However this activity does not behave as expected. It opens inside of an existing stack, and when I press the Back button, it takes me to other activities instead of closing the task. Ideally, I would like the APPWIDGET_CONFIGURE intent to include FLAG_ACTIVITY_NEW_TASK and FLAG_ACTIVITY_MULTIPLE_TASK.
Is it possible to specify flags in AndroidManifest.xml, and if not, what workaround would you suggest?
Consider specifying launchMode attribute to the activity element.
<activity android:launchMode="singleTask" android:name="com.tahanot.activities.NearbyStops">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
As per the official docs,
FLAG_ACTIVITY_NEW_TASK
Start the activity in a new task. If a task is already running for
the activity you are now starting, that task is brought to the
foreground with its last state restored and the activity receives the
new intent in onNewIntent().
This produces the same behavior as the "singleTask" launchMode value,
discussed in the previous section.
Since you mention you want FLAG_ACTIVITY_NEW_TASK behavior so singleTask launchMode might work for you.
USe this java code when you start your activity
Intent intent = new Intent(this,
activityname.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Here you can add flag with your intent object like this.
And you can also add multiple flag.
This is the manifest declaration that I used, following appsroxcom's idea for android:launchMode:
<activity
android:name="com.tahanot.activities.NearbyStops"
android:configChanges="orientation"
android:label="#string/title_activity_stops_nearby"
android:launchMode="singleTop"
android:taskAffinity="com.tahanot.tasks.widgetConfiguration" >
<!-- android:launchMode makes sure the Back button doesn't navigate to another NearbyStops activity.
android:taskAffinity makes sure the Back button doesn't navigate to some other activity. -->
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>

How do I close my application when it goes to background (via Home key)?

I want to close my application when it goes background.
My current method is to call finish() in the OnPause() of one of the main activity.
However, in my application there are several activities. When it jump to another activity from my main activity, my main activity will be closed.
It's not what I excepted. I want my applications closed only when the entire applications goes to background (e.g. via Home key)
Thanks.
You don't have to do that.. Android does it by itself when you press Home key.. and when it needs Resources... read this for more http://developer.android.com/reference/android/app/Activity.html
You can kill your own app's process using Process.killProcess(Process.myPid()). If you can't rely on a callback to you activity to tell you when your app has lost focus, and given that you can't rely on onPause (as noted above), you could in principle post yourself a suicide note during onPause:
_runnable = new Runnable() {
#Override
public void run() {
Process.killProcess(Process.myPid());
};
_handler = new Handler().postDelayed(_runnable, 3000);
and then have one your other activities intercept and cancel it during onResume:
_handler.removeCallbacks(_runnable);
(You'll need a way to provide access to the variables across multiple activities.) If the cancelation never comes, then your app will eventually be killed.
Kludgy, but possible, I think.
Now lets consider this is how ur manifest looks like. Main activity Hello starts Hello2 which starts Hello3 and so on.
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".Hello" android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="Hello2"></activity>
<activity android:name="Hello3"></activity>
<activity android:name="Hello4"></activity>
</application>
Now create dummy Launcher activity(HelloStarter) which starts ur Hello activity.
See updated manifest.
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".HelloStarter" android:label="#string/app_name"
android:clearTaskOnLaunch="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="Hello"></activity>
<activity android:name="Hello2"></activity>
<activity android:name="Hello3"></activity>
<activity android:name="Hello4"></activity>
</application>
In ur Hello activity's onDestroy() add this:
System.exit(0);
This works....!!!!

Categories

Resources