I'm launching an activity using startActivityForResult() from a button handler, and my onActivityResult() is being called instantly, even before the onCreate() for the target activity is being hit.
public void onGraphNext (View target) {
Intent i = new Intent(this, AddCommentActivity.class);
startActivityForResult(i,6); // 6 is arbitrary request code
}
. . .
protected void onActivityResult(int requestCode, int resultCode,
Intent returnData) {
if ( (resultCode == RESULT_OK) && (requestCode == 6) ) {
Bundle extras = returnData.getExtras();
comment = extras.getString("comment");
}
}
The result code returned is 0 and the request code is 6. Elsewhere on StackOverflow I've seen people report this problem and the solution was to not use singeInstance for the launchMode in the manifest. But I'm using standard . . .
<activity android:name="AddCommentActivity"
android:configChanges="orientation"
android:screenOrientation="portrait"
android:launchMode="standard"></activity>
Thanks in advance for any insights!
EDIT: I made a simple test program and I can reproduce the problem reliably when the caller ("launcher") - the activity with the onActivityResult - is a singleInstance and the Activity being invoked ("launchee") is standard. i.e.,
<activity android:name="Launcher"
android:screenOrientation="portrait"
android:launchMode="singleInstance"></activity>
<activity android:name="Launchee"
android:screenOrientation="portrait"
android:launchMode="standard"></activity>
This is a problem for me because in the real app, the called must be a singleInstance for other reasons, but it wants to have buttons to start up other activities to request user input. How else to do this if I can't use startActivityForResult?
You cannot use startActivityForResult() if the activity being started is not running in the same task as the activity that starts it. This means that neither of the activities can have launchMode="singleInstance". If you require that these 2 activities run in different tasks, then you need to use a different mechanism. The documentation for startActivityForResult() sorta-kinda hints at this:
"For example, if the activity you are launching uses the singleTask
launch mode, it will not run in your task and thus you will
immediately receive a cancel result."
What you can do is to simply start the activity using startActivity() and have the called activity call startActivity() to return to your activity, sending back data as necessary as extras in the Intent it uses.
However, you might consider whether you really need these special launchModes. In general they are only necessary for HOME-screen replacements and other very special applications. Most developers who use singleInstance or singleTask launch modes are using them incorrectly.
Related
The app has SplashActivity which is launched both normally and via deep link. In later case the SplashActivity creates an Intent, sets the data from deeplink, and launches MainActivity. MainActivity checks the data and behaves differently for normal launches and deep link launches.
When I enable "Don't keep activities" and launch the app via deeplink then when I go to background and return to the MainActivity it is recreated with deeplink intent.
I tried to modify the Intent in onDestroy and onSaveInstanceState with removeExtra and setIntent, but when I go to background and back the intent is still the same from deeplink and the extra is still there. I also tried to check intent flags for LAUNCHED_FROM_HISTORY but when I debugged the app flags were 0 every time.
I don't need the app to behave like it was launched with deeplink when it was launched from history. Is it possible to preserve intent modifications in that case?
You need to modify your intent in onPause, everything you do after onPause will not be saved, you may even consider modify your intent just after you consumed it to make your deeplink, i guess this will work as well
In onCreate block, Try removing the deep-linking keys in the Intent that you send to the activity
int flags = getIntent().getFlags();
if ((flags & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
// The activity was launched from history
// remove extras here to prevent the app from retaining the deep linking intent
getIntent().removeExtra(key);
} else {
// get data from intent normally
String s = getIntent().getStringExtra(key)
}
This should prevent the Activity from retaining the previous Intent.
I am launching the android setting activity, from an android service.
Intent LaunchIntent = getPackageManager().getLaunchIntentForPackage("com.android.settings");
startActivity(LaunchIntent);
I am searching, how I can detect if the setting activity is closed,As I need some callback method.
If there is a callback method to know the settings or any other app like browsers,if launched in this method to know if the launched activity is exit its own.
Since settings and browsers are general code we can't put broadcast code in these activities.
Use startActivityForResult to launch the settings activity like so:
Intent LaunchIntent =
getPackageManager().getLaunchIntentForPackage("com.android.settings");
startActivityForResult(LaunchIntent, 42);
Usually, you would use a specific request code as the second argument, but in this case, you have no control over what the settings Activity could return as a result, and you only want to know when it finishes, so you can essentially make up a request code. It must be greater than 0, however. The docs state this here:
requestCode If >= 0, this code will be returned in onActivityResult() when the activity exits.
Then, you can override the onActivityResult method to handle what happens when the settings activity closes:
#Override
protected void onActivityResult (int requestCode, int resultCode, Intent data){
// Do whatever you would like to do
}
If you had used a specific request code when you started the Activity, this is where you would check if the result code exists, but since we aren't expecting any real result, the result code will likely be equal to RESULT_CANCELLED, but that's okay since you at least know that the Activity was cancelled.
I am launching a media intent to take a photo. After the user took a picture and gets back to the previous activity the whole application has restarted.
As this doesn't happen all the time, I think my application goes to the background and android kills it when the device has low memory.
Is there any way to keep my application from going to the background?
Thanks!
This is normal behavior in Android, all activities currently not visible on screen (after onStop) can be killed without notice (i.e. onDestory) if the system has low memory.
This usually happens to our app on one of our test devices which has memory issues regardless of our app.
You can usually recreate this behavior when you open the camera via the intent, and then rotate the device (portrait to landscape), this will also kill and re-create your app.
To solve this you need to extend onSaveInstanceState and use the savedInstanceState parameter in your onCreate to pass from your killed instance to your new instance some important information (like "we're in the middle of getting a pic from the camera").
I can think of two possibilities...
It's not killing the activity, but the intent launches a new activity. You can stop this by putting a tag in your manifest.xml as an attribute in the activity tag like this:
<activity
android:name=".nameOfActivity"
android:launchMode="singleTop" />
Make sure that the media intent is under the activity to handle the photo, and not a main/launcher activity.
IMO two options:
Implement onSaveInstanceState/onRestoreInstanceState
or
Make your activity a service.
I faced this issue and got a solution after R&D for it.
Set Target Android 4.0 and then add this line in AndroidManifest.xml of activity:
android:configChanges="screenLayout|uiMode|orientation|screenSize|smallestScreenSize"
It works for me.
When you start media intent use following method instead of startActivity(intent)
startActivityForResult(intent, REQUEST_CODE); //private int REQUEST_CODE = 232
When the started activity finishes, your calling activity will be started. You need to handle this using following function
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
//Perform your task
}
}
The activity started need to override follwoing method
#Override
public void onBackPressed() {
Intent intent = new Intent();
setResult(REQUEST_CODE, intent);
super.onBackPressed();
}
startActivityForResult() is an special way for starting activity for a specific task and get the desired result. The called activity will send the data back.
You can use the method putExtra() & getExtra in intent to send and receive data between two activity.
This will solve your problem hopefully.
If you have doubts comment. And if possible share your code so it can be more clear.
I am relatively new to Android programming. I have been given a task at work where I need to create a Custom Home activity launcher. I did a bit of research and found the example on the Android developer website (home sample). This was the start for my prototype.
The custom Home activity will need to require the user to authenticate (enter some simple credentials). My thought was to launch a sub-activity from the Home activity and pass back the results in the intent to the Home activity. I need to be able to capture information about these credentials and that information was going to be passed back to the Home activity. However, I have problems when trying this. I get a log in the LogCat that says the following: "Activity is launching as a new task, so canceling activity result."
I am aware of the startActivityForResult method, but that does not seem to be working for me. Here is where I launch the activity from my Home activity:
#Override
protected void onResume() {
super.onResume();
bindRecents();
Intent iii = new Intent(this, Login.class);
startActivityForResult(iii, STATIC_LOGIN_INTEGER_VALUE);
}
When that code executes, I get the above mentioned log from the ActivityManager tag.
My Login activity has a button that the user will hit once they have entered their credentials. If the credentials are good, then I try to do the following (I put in several logs so that I could try to figure out what is going on):
public void onClick(View src) {
// check for authentic credentials
if(IsValid())
{
Intent loginAuth = new Intent("Login");
loginAuth.putExtra("userRole", userRole);
Log.d("LOGIN", "Setting result...");
if (getParent() == null) {
Log.d("LOGIN", "Parent was null");
setResult(Activity.RESULT_OK, loginAuth);
}
else {
Log.d("LOGIN", "setting result on parent...");
getParent().setResult(Activity.RESULT_OK, loginAuth);
}
Log.d("LOGIN", "Finishing the activity");
finish();
}
}
I defined these activities in my manifest file as the following:
<activity android:name="Home"
android:theme="#style/Theme"
android:launchMode="singleInstance"
android:stateNotNeeded="true">
<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>
<activity android:name="Login"
android:label="Login"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
</intent-filter>
</activity>
I was playing around with the intent filter on the Login activity. I had originally had it set to nothing. I also had the launchMode blank (which defaults to standard I believe). I have played around with most of these options and nothing seems to change the fact that the ActivityManager seems to want to launch the activity as a new task and wants to ignore the returned intent (which I need).
The problem is that you declared your activities with launchMode="singleInstance", so Android creates a new task (i.e. a new process) when it launches the Login activity. Activities in different tasks cannot return results to each other. From the Activity.startActivityForResult() docs:
For example, if the activity you are
launching uses the singleTask launch
mode, it will not run in your task and
thus you will immediately receive a
cancel result.
singleInstance is like singleTask but even more restrictive. Try removing the launchMode attribute from your manifest so that the Login activity will launch in the same task, then using FLAG_ACTIVITY_NEW_TASK when you need to launch a different activity in a separate task.
Barry
The documentation says
For example, if the activity you are launching uses the singleTask
launch mode, it will not run in your task and thus you will
immediately receive a cancel result.
THIS IS WRONG.
You can use the singleTask just fine, what you can't use is singleInstance.
Let's return to the problem. What is the problem?
The problem is that when you call startActivityForResult() on an activity, the caller activity and the activity you are launching must be on the same task for the startActivityForResult() to work properly that means that you can't call startActivityForResult() to an activity using the Intent.FLAG_ACTIVITY_NEW_TASK.
why singleInstance isn't working?
Because a "singleInstance" activity stands alone as the only activity in its task. If it starts another activity, that activity will be launched into a different task regardless of its launch mode — as if FLAG_ACTIVITY_NEW_TASK was in the intent. In all other respects, the "singleInstance" mode is identical to "singleTask".
Why singleTask is working?
Because singleTask doesn't require the creation of a new task for the new activities being launched.
I quoted from this answer to explain the difference between the two launch modes.
Have you declared the setResult(int resultCode, Intent data) in your Login activity.
Android Documentation says
"Note that this method should only be used with Intent protocols that are defined to return a result." If it is not or some other conditions matches as in the documentation of Activity.startActivityForResult(), it will not run in your task and thus you will immediately receive a cancel result."
I am facing with a problem related startActivityForResult()
To start SecondActivity from FirstActivity :
Intent intent = new Intent();
intent.setClass(FirstActivity.this, SecondActivity.class);
intent.putExtra("key1", "12345");
startActivityForResult(intent, 0);
And handles result :
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//TODO handle here.
}
To send the message to FirstActivity from SecondActivity :
in SecondActivity :
setResult(0);
I can't handle the result on onActivityResult in FirstActivity.
It never works for my application.
My OS is : 1.5
What is wrong here?
startActivityForResult is meant to be used for situations where you want to select a piece of data, or perform some sort of action that your Activity or application cannot do.
For example, you want to pick a contact, so you launch the contacts application, the user chooses the person they want, and you get sent the result. Or you want to take a photo, so you launch the camera application and ask it to send you the photo once it's done. This action is completely separate from your first activity that calls startActivityForResult.
The Activity you're launching will not send you the result until that Activity has completed, i.e. finish() has been called.
So in your case, you need to call this in SecondActivity:
setResult(...);
finish();
before FirstActivity will receive the result in its onActivityResult method. Of course, this means that SecondActivity is now gone and FirstActivity is top of the stack again.
It's not possible to send the result to FirstActivity then close it while keeping SecondActivity still active. In this case you should just handle whatever this 'result' is in SecondActivity, or send it off to a Service you define to do whatever processing it is you want.
I was stuck here for a while. Adding my problem here to make sure that you don't scratch your head as well.
The second parameter of this function has to be 0 or higher.
startActivityForResult(intent, 0); // <- this is OK
I was setting the second parameter to RESULT_OK, which is -1, and my onActivityResult callback was never getting called. So if you get stuck like me, you can also check if your second parameter is correct.
startActivityForResult(intent, RESULT_OK); // <- this is wrong
The above line will fail to call onActivityResult.
I was also stuck on the same problem - but due to a different reason as matangs. Apparently startActivityForResult only works if you have android:launchMode set to standard for main activity (in manifest). Hope it helps someone.
Your code seems ok, but do you stop your second activity ?
Try this in it :
setResult(0);
finish();
If you are doing actions on onPause (like unbinding a service) try to comment it and see if onActivityResult is called (I wasted few good hours on this..)
Thanks to #johndodo (that point to the manifiest) - I find my solution for the same problem.
removing android:noHistory=true at the manifiest" solved this problem for me.