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.
Related
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.
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.
So I have an Activity A that is defined in the AndroidManifest.xml as defined below:
<activity
android:name=".activity.A"
android:screenOrientation="landscape"
android:windowSoftInputMode="stateAlwaysHidden"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
This Activity launches a welcome Screen which we will call Activity B.
If you launch the application the Welcome screen is displayed and then once the user is done with it Activity A comes back.
The issue I am having is when I push the "Home" button from the welcome screen I go back to the Home Screen as expected. Now when I reclick on the Application Icon the application won't launch. Instead both my Activity A & B get destroyed. If I click on the icon again then the application relaunches as expected.
Now if I'm on the welcome screen and push the back arrow and reclick on the App icon it launches the application as expected. I don't have to push it twice.
Unfortunately I have to use the launchMode="singleTask" since it is a requirement for integration with another team. I have read the Android API's for Tasks and Back Stacks numerous times. Any pointers or suggestions would be greatly appreciated.
I came across a blog indicating there is an undocumented bug with using singleTask and intent-filters together but didn't find any official documentation on this.
Thanks
EDIT
Launching Activity B like this:
Intent intent = new Intent(context, B.class);
startActivityForResult(intent, CONST_VAR);
I tried making two activities which launches ActivityB from Activity A. I see no such problem as described in the question. PFB my manifest. Also, when you say home button, is it Phone home button or your app specific home button. PFB my manifest
<activity
android:name="com.android.testsingletask.MainActivity"
android:launchMode="singleTask"
android:screenOrientation="landscape"
android:windowSoftInputMode="stateAlwaysHidden"
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="com.android.testsingletask.WelcomeActivity"
android:screenOrientation="landscape"
android:windowSoftInputMode="stateAlwaysHidden"
android:label="#string/app_name" >
</activity>
I have 2 activities in my app. The A activity is the launcher one. When I run the app the very first time, the launcher activity runs, but when I press the home button and restart the app from there by clicking the app icon, I always get the B activity running.
I want to make sure that the activity A should always run when starting the app.
This is the manifest code:
<application
android:icon="#drawable/icon"
android:label="#string/app_name" >
<activity
android:name="com.velosys.smsManager.Activities.a"
android:launchMode="singleInstance"
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="com.velosys.smsManager.Activities.b" />
</application>
Using android:launchMode="singleInstance" serves my purpose,but it makes the movement from one activity to another really very slow.Can you please suggest me any option for `android:launchMode="singleInstance".Please help me.Thanks in advance.
you can try to override onUserLeaveHint() method in B activity (this will register Home button pressed event) and then create intent
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(startMain);
which isn't really an ideal solution
EDIT:
yeah sry, best solution would be that you call finish() inside onPause() method of B activity
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....!!!!