Reputation: 3589
First of all, I'm new to Android Development so please have patience with me.
I'll start from the UI, I have a button that once you tap it, starts an activity for a result.
public class GUIActivity extends Activity
@Override
public void onClick(....){
Intent intent = new Intent(getApplicationContext(), GetImageActivity.class);
intent.putExtra("action", FROM_CAMERA);
startActivityForResult(intent, GET_IMAGE);
}
@Override
onActivityResult(int requestCode, int resultCode, Intent data){
Log(TAG, "onActivityResult");
//handle result
}
}
The GetImageActivity
class is a wrapper for two other activities, one to capture an image from the camera and other to get it from the gallery. It returns and Uri object of the selected image.
public class GetImageActivity extends Activity{
private Uri mediaUri;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
int action = extras.getInt("action");
Log.d(TAG, "onCreate");
switch(action){
case FROM_CAMERA:
mediaUri = Uri.fromFile(new File(....));
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT, mediaUri);
Log.d(TAG, "Calling camera activity"
startActivityForResult(intent, action);
break;
case FROM GALLERY:
//...
}
}
@Override
onActivityResult(int requestCode, int resultCode, Intent data){
Log.d(TAG, "onActivityResult");
switch(requestCode){
case FROM_CAMERA:
if(resultCode == Activity.RESULT_OK){
Intent data = new Intent();
data.putExtra("uri", mediaUri);
setResult(Activity.RESULT_OK, data);
finish();
}else{
Log.e(TAG, "Camera activity failed!");
setResult(Activity.RESULT_CANCELED);
finish();
}
break;
case FROM_GALLERY:
//...
}
}
}
This is what is expected to happen when the user clicks on the button:
Sometimes (it's usually a 50% chance) it works at expected, but other times this is what happens:
I've added a couple of debug log lines to follow the sequence of events. When I get the bad behaviour this is the output I get:
The camera opens, and once I've taken a picture it says:
The camera opens for the second time. The user takes another picture and:
So my question is... what could cause the GetImageActivity
to be called twice?
Upvotes: 11
Views: 16813
Reputation: 372
Add this to your Activity definition in AndroidManifest.xml:
android:launchMode = "singleTask"
Upvotes: 8
Reputation: 185
Add this to your Activity definition in AndroidManifest.xml:
android:launchMode = "singleInstance"
Upvotes: 2
Reputation: 1756
The problem is improper handling of the Activity
lifecycle.
The second call to onCreate
is for handling the result.
Android may choose to destroy an Activity
that is waiting for the call to onActivityResult
; especially when free memory is running low. Some devices appear more aggressive about destroying Activitys that are on the task stack. I can reliably recreate the issue on a Samsung device set to a debugging mode called "strict mode".
You can verify whether this is your issue by logging calls to onCreate
& onDestroy
.
In the case of a destroyed activity, when the activity result needs to be processed, Android will recreate the Activity
, passing a savedInstanceState
to onCreate
. So, the remedy is to check the value of savedInstanceState
in your GetImageActivity.onCreate
. If it is not null
then don't make any calls to startActivity
because your Activity
is being recreated to call onActivityResult
.
Optionally, if you need to preserve any state then override onSaveInstanceState(Bundle outState)
and put data you need into outState
.
Upvotes: 10
Reputation: 32758
When you call startActivityForResult
it is telling Android that you want the result to be delivered to the Activity
which is making that call. Which explains what you see when you logged GetImageActivity - onCreate (again)
.
Since you call startActivityForResult
in your first activity, that is, GUIActivity
than you should be calling setResult
in GetImageActivity
to properly pass back the result.
So in GetImageActivity.onActivityResult()
right before you call finish()
you should call setResult
so that when you return back to GUIActivity
it can handle the expected result.
Upvotes: 0