Unable to fully close activity when using "singleTask" as launch mode - android

I'm trying to create a separate activity and use it to receive data from other applications. This SecondaryActivity is being launched through intent.action.SEND and android.intent.action.SEND_MULTIPLE in the manifest. I have also set it to use launchMode="singleTask" to avoid a duplicate app problem (if you keep selecting the app in the android share sheet and clicking back you can spin up multiple instances of the app).
launchMode="singleTask seems to work so far but I cannot get it to close even when adding finish() and finishAffinity() in onBackPressed(). When i look at the back stack, it says that SecondaryActivity is closed, but upon pressing the navigaton button, I can still see the activity.
<application
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/Theme.TestProject">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".SecondaryActivity"
android:launchMode="singleTask"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*" />
</intent-filter>
</activity>
</application>
My SecondActivity looks like this
class SecondaryActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_secondary)
}
override fun onBackPressed() {
finish()
finishAffinity()
}
}
This problem happens when the app is completely closed and is launched through sharing a file. I cannot get the SecondaryActivity to not show up in the navigation screen even after closing it by pressing the back button. adb says there are no activities in the stack but i still see it in the navigation.

This is called Recents screen which is a system-level UI that lists recently accessed activities and tasks even if the application has finished.
If you don't want to see the app in the recent apps after pressing back button, using finishAndRemoveTask
override fun onBackPressed() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
finishAndRemoveTask()
} else {
finish()
}
}

Related

What can cause startTaskLock to pin then immediately unpin an activity?

I've been attempting to use the android 6.0 task locking/pinning to lock down my activity. It seems to work unreliably. Sometimes when I start my application it will pin and everything is hidden like it should. Other times it attempts but it doesn't really take. For example I get a toast that says "Screen Pinned" followed immediately by one that says "Screen Unpinned". The end result is the app isn't fully pinned (hiding the home and task switcher icons). But once it is in this cycle, it doesn't seem to work even if I keep trying. This is also an issue on boot, similar to what is reported here:
Android pin activity on boot
Is there any way to tell what is causing android to unpin my activity? It is frustrating because it doesn't give any indication why it doesn't work.
Our Lenovo tablet wasn't able to pin a task where the Home activity lived. The solution was to have two activities in two different tasks.
The Home Activity
This activity is started on boot as a launcher and it sole responsibility is to open the main activity immediately. Notice that it's transparent and has different task affinity.
<activity
android:name=".HomeActivity"
android:clearTaskOnLaunch="true"
android:configChanges="orientation|screenSize"
android:launchMode="singleTask"
android:resumeWhilePausing="true"
android:stateNotNeeded="true"
android:taskAffinity="${applicationId}.home"
android:theme="#android:style/Theme.Translucent.NoTitleBar.Fullscreen">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.HOME"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
The activity will launch the Main Activity in its onCreate and onNewIntent as well (because it's a singleTask activity). Here's the code in Kotlin:
class HomeActivity : Activity() {
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
handleIntent(intent)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
handleIntent(intent)
}
private fun handleIntent(intent: Intent) {
val i = packageManager.getLaunchIntentForPackage(packageName)
startActivity(i)
}
}
The Main Activity
This is your main activity - main entry point to your app, it can be started from any launcher. It has the default task affinity (which is equal to the application ID).
<activity
android:name=".webview.activity.RealWebViewActivity"
android:clearTaskOnLaunch="true"
android:configChanges="orientation|screenSize"
android:exported="false"
android:launchMode="singleTask"
android:resumeWhilePausing="true"
android:stateNotNeeded="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>

inexplicable behaviour of activity backstack

I have simple app with two activities. Here is manifest:
<application>
<activity
android:name=".ActivityA"
android:theme="#style/AppTheme.NoActionBar.Map">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".ActivityB"
android:theme="#style/AppTheme.NoActionBar">
<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="https://stackoverflow.com/"
android:scheme="http"
android:pathPrefix="/questions/ask"
/>
</intent-filter>
</activity>
</>
as u can see, when link "https://stackoverflow.com/questions/ask" will be clicked - my app will open second activity.
In the ActivityB I override onBackPressed method:
override fun onBackPressed() {
if(isTaskRoot){
startActivity(Intent(this, MapActivity::class.java))
finish()
} else {
super.onBackPressed()
}
}
so when second activity started from link and I click on back btn, ActivityA is opened and ActivityB is finished.
for the first look everything looks fine, but if after this i press home btn, and then relaunch app from stack - ActivityB is opened again instead ActivityA.
Please explain me why it happen and how to fix this issue. Thanks!
UPDATE
after onBackPressed in ActivityB, ActivityA is opened, and then i click onBackBtn instead HomeBtn, so app is closed. in this case after relaunch from stack ActivityB is opened.
When you press the home btn in ActivityB, Android calls the onPause() method on activity lifecycle, and in this moment your app is paused on activityB. It are not destroyed like you did overriding onBackPressed(). So when you relaunch your app again, the SO will be call onResume() on ActivityB that is in backstack.
To change this behavior, you have to override the onPause() method on finish the activity manually.

Android Back Navigation ParentActivityName not working

i tried using this tutorial on how to provide a back navigation as in this code
https://developer.android.com/training/implementing-navigation/temporal.html
<activity android:name=".controller.general.AccountPickerScreen"
android:parentActivityName="ph.edu.upm.agila.extendthelife.controller.general.LogInScreen">
<intent-filter>
<action android:name="ph.edu.upm.agila.extendthelife.controller.general.AccountPickerScreen" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
I already specificied the parentActivityName but whenever I press the back button the app exits? any solutions?
tried this
public void onBackPressed() {
Intent intent = NavUtils.getParentActivityIntent(AccountPickerScreen.this);
startActivity(intent);
finish();
}
it does work however i want to know if it is the right way of doing it?
what does finish() do exactly
You may need to override the onBack for the activity and use NavUtils to accomplish what you want with a line like:
Intent intent = NavUtils.getParentActivityIntent(AccountPickerScreen.this);
for api level below 16 try adding
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="fully qualified path to Activity Class Name" />
in activity tag in androidmanifest.xml
<activity android:name=".controller.general.AccountPickerScreen">
<intent-filter>
<action android:name="ph.edu.upm.agila.extendthelife.controller.general.AccountPickerScreen" />
<category android:name="android.intent.category.DEFAULT" />
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="ph.edu.upm.agila.extendthelife.controller.general.LogInScreen" />
</intent-filter>
</activity>
override onBackPressed with `
NavUtils.navigateUpFromSameTask(this);`
I had an issue where the parent button worked on some activities but not others.
The problem was my onOptionsItemSelected function. It was returning true by default, which blocked the call from completing. You should call super.onOptionsItemSelected(item).
See https://developer.android.com/guide/topics/ui/menus.html

Acitivity SingleTask behaviour with SplashScreen

In my App I have:
-SplashScreen (SSc) preparing the application (starting services and so on)
-MainActivity (MA) the most relevant part of the app handling most actions
-and some other activities which are not that relevant
For my App I'd like to have the behavior like launchMode singleTask, so that my App is always started as a new Task, even when opened through a link click in SMS/EMail app. The best would be to have only one Instance of my Activities as they are all serially navigable.
However when I start SSc as singleTask it is the root of the stack and navigating to the MainActivity, pressing home, click on the Launcher icon again the app is fully restarted. So SSc is shown again and so on. In this Situation, I would like the MainActivty to be brought to the front instead.
my wish would be:
launcherclick -> SSc ->MA ->HOME -> launcherclick -> bring MA to front -> HOME-> relaunch from recents -> bring MA to front
Click on link ->SSc/MA (whether it is first start) with the same instances
In my App it does not make sense to have multiple instances, as the background service only handles one MainActivity at a time because it polls data frequently just for the seen "Thing".
Do you have any recommendations to achieve this goal?
my first idea was a LauncherActivity with launchMode singletask without layout to route the intents to the other activities (which most likely will be singleTop !?, because its only in one task then) like:
public class LauncherActivity extends Activity {
private boolean firstStart = true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
protected void onResume() {
super.onResume();
if(firstStart){
startActivity(new Intent(this, SplashScreen.class));
firstStart = false;
} else {
Intent i = new Intent(this, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(i);
}
}
}
Manifest xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="x.startintenttest">
<application
android:allowBackup="true"
android:allowTaskReparenting="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name">
<activity
android:name="x.startintenttest.MainActivity"
android:label="#string/app_name"
android:launchMode="singleTop"></activity>
<activity
android:name="x.startintenttest.MainActivity2"
android:label="#string/title_activity_main_activity2"></activity>
<activity
android:name="x.startintenttest.SplashScreen"
android:label="#string/title_activity_splash_screen"
android:launchMode="singleTask">
<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="*.xyz.de"
android:pathPattern="/...-........."
android:scheme="https" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Its simple, I also did the same. I was using singleTask for my splash and the main activity. So that I faced the same issue(Splash was showing at every wakeup). But I solved this by removing the singleTask from the splash and kept it for the MA alone(I used to finish the splashActivity when the MA starts). Try this trick.
The solution provided Sripathi fixes the issue, but you end up with the link-opening-app having the splash screen layout in its preview. My solution to this is to have a LinkEntryPointActivity with no layout that then delegates the received intent to the splash screen.
class LinkEntryPointActivity : MyBaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val intentClone = intent.clone() as Intent
val componentName = intentClone.component
val newComponentName = ComponentName(componentName.packageName, SplashActivity::class.java.name)
intentClone.component = newComponentName
startActivity(intentClone)
finish()
}
}
And declare it in AndroidManifest.xml as
<activity android:name=".ui.LinkEntryPointActivity"
android:launchMode="singleTask" <-- This forces to open the link in a new task
android:screenOrientation="portrait">
<!-- Intent filters here -->
</activity>
The original splash screen activity should still be handling the MAIN action in the LAUNCHER category as usual.

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