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.
Related
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()
}
}
How can I dynamically select the starting Activity of my application?
Take for example this scenario: the first time the user opens the app, he will see the AuthenticationActivity, after that, he will see the MainActivity. If he logs out, he will see the AuthenticationActivity again.
I don't want to use a splash screen or something similar and I'm wondering if there is any way of doing this.
I was thinking of checking if there are any accounts in the onCreate method of the MainActivity, before calling setContentView, and display the AuthenticationActivity if not, but it doesn't feel ok to me.
You could do something like this:
public class NavigatorActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent;
if (isAuthenticated) {
intent = new Intent(NavigatorActivity.this, MainActivity.class);
} else {
intent = new Intent(NavigatorActivity.this,
AuthenticationActivity.class);
}
startActivity(intent);
finish();
}
}
And launch your app with this NavigatorActivity.
You could also set MainActivity the parent of LoginActivity, set LoginActivity as Main/Launcher and call finish() if already logged in.
<application ... >
...
<!-- The main/home activity (it has no parent activity) -->
<activity
android:name="com.example.myfirstapp.MainActivity" ...>
...
</activity>
<!-- A child of the main activity -->
<activity
android:name="com.example.myfirstapp.LoginActivity"
android:label="#string/title_activity_login"
android:parentActivityName="com.example.myfirstapp.MainActivity" >
<!-- Parent activity meta-data to support 4.0 and lower -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.myfirstapp.MainActivity" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
Instead of getting back to the last activity, it launch the parent one.
In Android Lollipop, when you long press a Notification, it gives you access to settings for that Notification's app, such as priority, or simply blocking it. Is there an intent that I can use to access those settings?
Found the answer here - https://plus.google.com/+CyrilMottier/posts/YY6tbJrJMra
You need to add this to the activity you want to be attached to that settings icon
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.NOTIFICATION_PREFERENCES" />
</intent-filter>
In addition to the correct answer from #shmuel :
In case you want this "App settings" system button to jump to one specific fragment of your app's Settings activity deriving from PreferenceActivity, you can create a dummy intermediary activity to handle the intent-filter as details above, and then in this activity you simply do:
public class DeepSettingsFragmentDummyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent settingsIntent = new Intent(this, SettingsActivity.class);
// Standard mechanism for a PreferenceActivity intent to indicate
// which fragment to activate automatically.
settingsIntent.putExtra( PreferenceActivity.EXTRA_SHOW_FRAGMENT,
YourTargetPreferenceFragment.class.getName());
startActivity(settingsIntent);
finish();
}
}
This code automatically launches the YourTargetPreferenceFragment fragment, and then dismisses itself (finish()) so as to not remain in the activity stack when the user hits Back.
Your Manifest must contain:
<activity
android:name=".DeepSettingsFragmentDummyActivity"
android:label="...">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.NOTIFICATION_PREFERENCES" />
</intent-filter>
</activity>
I am developing an Android Home Screen, I seem to be experiencing problems. Whenever I start an application from that home screen, its lifecycle ends up to being destroyed(I Knew this because I used LogCat and it does print my code in the OnDestroyed method). I only want it to only be paused not completely destroyed because I am running a little long processes in the oncreate. I only wanted the onCreate to be called once, which is when the device boots. In my case, since whenever my home screen starts an application, it is destroyed. And whenever I press the HOME button, it goes through from on create -> on start -> on resume.
The following is my codes, can you state if I am doing something wrong. Thanks.
My Code in Starting an Application:
public void startAppByAppName(String appName) {
String mainActivity = "";
String packageString = "";
Intent intent = getPackageManager().getLaunchIntentForPackage(appName);
mainActivity = intent.getComponent().getClassName();
packageString = intent.getComponent().getPackageName();
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setComponent(new ComponentName(packageString, mainActivity));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
My Manifest:
<application
android:allowBackup="true"
android:icon="#drawable/home_icon"
android:label="#string/app_name"
android:theme="#style/AppTheme" android:persistent="true">
<activity
android:name="com.steven.welcomescreen.WelcomeScreenActivity"
android:launchMode="singleTask"
android:clearTaskOnLaunch="true"
android:stateNotNeeded="true"
android:screenOrientation="landscape"
android:theme="#android:style/Theme.Black.NoTitleBar">
<intent-filter>
<category android:name="android.intent.category.HOME"/>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
If there is some parts of my code which you want to clarify, just comment below so I could supply you with information. I really need help. Thanks you very much.
I'm trying to create a simple app, whose main task is to open the browser on defined URL.
I've created first Activity:
public class MyActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
Intent myIntent = new Intent(Intent.ACTION_VIEW,
Uri.parse("http://my.url.tld"));
startActivity(myIntent);
}
Here's my AndroidManifest.xml:
<manifest ...>
<application ...>
<activity android:name=".MyActivity" ...>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
This code is fully functional, but before it opens the browser, it displays a black background - blank app GUI. I didn't figured out, how to go directly do the browser (without displaying the GUI).
Anyone knows?
Add this theme declaration to your activity definition in you manifest
<activity android:name=".MyActivity"
android:theme="#android:style/Theme.Translucent.NoTitleBar"
>
Be careful with this, you must call finish(); from your activity after you are done with it otherwise users could get stuck with an invisible activity that prevents them from interacting the phonetop.