Using startActivityForResult, how to get requestCode in child activity? - android

I have four activities, say A, B, C and D.
My situation is A will start the activity B by startActivityForResult.
startActivityForResult(new Intent(this,B.class),ONE);
In another situation I will start activity B with a different request code, like:
startActivityForResult(new Intent(this,B.class),TWO);
In B, I need to call C or D depending on requestCode. I.e if ONE need to start C else D.
So I need to know how to check the requestCode in the child Activity (B here).
In other words, I want to get the request code that Activity B was started with.

You can pass request code by put extra.
intent.putExtra("requestCode", requestCode);
Or if you have used startActivityForResult many times, then better than editing each, you can override the startActivityForResult in your Activity, add you code there like this
#Override
public void startActivityForResult(Intent intent, int requestCode) {
intent.putExtra("requestCode", requestCode);
super.startActivityForResult(intent, requestCode);
}
So there is no need to edit all your startActivityForResult
Hope it helped you

The request code is not passed to the started activity automatically because it doesn't (and shouldn't) need to know this value. It only needs to know what to do and not where it was started from.
Starting an activity is really just another form of calling a method. When you call a method, you receive the result synchronously (right there where you made the call). In this case you are only passing in the information that method needs to do its work. You are not telling it where you called it from.
Starting an activity is the asynchronous analog of calling a method, in which case you receive the result in the special method onActivityResult(). In this method, you need to know what to do with the result you just received and you have the request code for this.
To make it a bit clearer why it isn't a good idea to pass the request code as a parameter, consider the example activity which is showing a product you can buy. On this activity there are two buttons labeled "Buy" and "Login" (as you are currently not logged in). Pressing "Login" will start an activity named "Login" which will try to log in the user using the provided information. Pressing "Buy" will first start the very same "Login" activity and if the login was successful, start the buy activity.
Now, the "Login" button uses request code 1 to start the login activity, but the "Buy" button can't use the same request code as it will have to do something different if the login is successful. So, the "Buy" button uses request code 2.
In the "Login" activity you might receive two different request codes depending on where it was called from, but you will need to do the very same procedure.
So, if you pass in the request code as a parameter, you will end up with code that needs to do the same stuff for a couple of different request codes, like:
if (requestCode == LOGIN || requestCode == BUY) {
// ...
} else ...
You will also end up with storing the request code constants in a central location e.g. a class named RequestCodes.
In short, the request code should only be used to decide what to do with the received result. This way you will end up with a more modular, easier to maintain and easier to extend code.

I ended up using custom Intent action to pass this kind of information to the launching Activity.
protected static final String ACTION_DO_C = "do_c";
protected static final String ACTION_DO_D = "do_d";
Then you'd go like:
final Intent intent = new Intent(this,B.class)
intent.setAction(ACTION_DO_C);
startActivityForResult(intent,ONE);
And in Activity B you get the action easily:
getIntent().getAction();

You can use getCallingActivity() to get the activity that started current activity and that will receive the result value with response code at the end.

Related

How to check another event occurred rather than the expected return code?

I use startActivityForResult with an intent and a specific REQUEST_CODE to launch activity B from A.
In activity B the user can edit the database entry, or delete it.
If I press the same button, and launch the activity using the same request code and intent,
how can I check if the user chose to save the entry they edited, or delete it?
As stated in the comments, I'd personally use different REQUEST_CODEs for different operations, but if you truly want to respond with the same one, and indicate something, simply pass a boolean (or any other useful type) in the response's intent that you can handle in the onActivityResult in the calling activity or fragment.

Android - Activity seems to not get called after the intent returns

I have an activity where you can click on a button that sends you to an activity where you can add pictures (using startActivityForResult). You can add a couple of pictures. Every picture you add, gets converted to a byte[] array, and gets stored as an extra in the result intent. When the second activity finishes, if i added one picture, and finish the activity, everything is fine, it returns to the previous activity with the button. If i add two or more pictures, and finish the second activity, the previous activity doesn't even get called. It takes me directly to an activity before the activity with the button, but first i see like a black screen that seems like the previous activity crashed, though no errors can be found in the logs. The onActivtiyResult in the previous activty does not get called as well. Any reason why this might be happening ?
Code sending intent to photo adding activity :
Intent addEditPicturesIntent = new Intent(getApplicationContext()
,AddOrEditPicturesOnProductActivity.class);
startActivityForResult(addEditPicturesIntent,33);
Code finishing the photo adding activity:
Intent returnIntent=new Intent();
if (hashMap.containsKey("one")){
Log.d(TAG,"Submit Button clicked and now putting extra in intent-->1");
returnIntent.putExtra("1",hashMap.get("one"));
}
if (hashMap.containsKey("two")){
Log.d(TAG,"Submit Button clicked and now putting extra in intent-->2");
returnIntent.putExtra("2",hashMap.get("two"));
}
if (hashMap.containsKey("three")){
Log.d(TAG,"Submit Button clicked and now putting extra in intent-->3");
returnIntent.putExtra("3",hashMap.get("three"));
}
setResult(Activity.RESULT_OK, returnIntent);
finish();
onActivityResult code in the activity with the button:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG,"onAcitivtyResult"); // <--- NOT EVEN THIS GETS CALLED when returning
if (//uninmportant stuff){
//Other uninporant stuff
else if(requestCode == 33){
Log.d(TAG,"[Test Return Code returned]!");
Log.d(TAG,data.getExtras().toString());
Bundle bundle=data.getExtras();
List<ProductImage> productImageList=new ArrayList<>();
for (Integer i=1;i<=3;i++){
if ( bundle.getByteArray(i.toString())!=null){
ProductImage productImage=new ProductImage();
productImage.setImageBytes(bundle.getByteArray(i.toString()));
productImageList.add(productImage);
}
}
addProductViewModel.fillUpMutableLiveData(productImageList);
addProductViewModel.updateCurrentId(0);
}
}
Every picture you add, gets converted to a byte[] array, and gets stored as an extra in the result intent.
That is a really bad idea.
though no errors can be found in the logs
You are probably getting "FAILED BINDER TRANSACTION" warnings.
Any reason why this might be happening ?
My guess is that you are attempting to pass too much data via IPC. The Intent that you supply to setResult() is passed from your app to a core OS process, then back to your app and the caller of startActivityForResult(). At best, you can pass 1MB in an IPC transaction, and depending on what else is going on at the time, the limit may be substantially lower.
Either:
Have one activity, not two, by using fragments for the individual bits of UI and using a shared ViewModel to expose the results of one fragment to another; or
Carefully hold onto these images in a shared cache, so you are passing cache keys as extras, not byte[]; or
Find some other architecture that you like that does not involve putting large byte[] values into an Intent for use with startActivity(), startActivityForResult(), or setResult()

Get request code in started activity [duplicate]

I have four activities, say A, B, C and D.
My situation is A will start the activity B by startActivityForResult.
startActivityForResult(new Intent(this,B.class),ONE);
In another situation I will start activity B with a different request code, like:
startActivityForResult(new Intent(this,B.class),TWO);
In B, I need to call C or D depending on requestCode. I.e if ONE need to start C else D.
So I need to know how to check the requestCode in the child Activity (B here).
In other words, I want to get the request code that Activity B was started with.
You can pass request code by put extra.
intent.putExtra("requestCode", requestCode);
Or if you have used startActivityForResult many times, then better than editing each, you can override the startActivityForResult in your Activity, add you code there like this
#Override
public void startActivityForResult(Intent intent, int requestCode) {
intent.putExtra("requestCode", requestCode);
super.startActivityForResult(intent, requestCode);
}
So there is no need to edit all your startActivityForResult
Hope it helped you
The request code is not passed to the started activity automatically because it doesn't (and shouldn't) need to know this value. It only needs to know what to do and not where it was started from.
Starting an activity is really just another form of calling a method. When you call a method, you receive the result synchronously (right there where you made the call). In this case you are only passing in the information that method needs to do its work. You are not telling it where you called it from.
Starting an activity is the asynchronous analog of calling a method, in which case you receive the result in the special method onActivityResult(). In this method, you need to know what to do with the result you just received and you have the request code for this.
To make it a bit clearer why it isn't a good idea to pass the request code as a parameter, consider the example activity which is showing a product you can buy. On this activity there are two buttons labeled "Buy" and "Login" (as you are currently not logged in). Pressing "Login" will start an activity named "Login" which will try to log in the user using the provided information. Pressing "Buy" will first start the very same "Login" activity and if the login was successful, start the buy activity.
Now, the "Login" button uses request code 1 to start the login activity, but the "Buy" button can't use the same request code as it will have to do something different if the login is successful. So, the "Buy" button uses request code 2.
In the "Login" activity you might receive two different request codes depending on where it was called from, but you will need to do the very same procedure.
So, if you pass in the request code as a parameter, you will end up with code that needs to do the same stuff for a couple of different request codes, like:
if (requestCode == LOGIN || requestCode == BUY) {
// ...
} else ...
You will also end up with storing the request code constants in a central location e.g. a class named RequestCodes.
In short, the request code should only be used to decide what to do with the received result. This way you will end up with a more modular, easier to maintain and easier to extend code.
I ended up using custom Intent action to pass this kind of information to the launching Activity.
protected static final String ACTION_DO_C = "do_c";
protected static final String ACTION_DO_D = "do_d";
Then you'd go like:
final Intent intent = new Intent(this,B.class)
intent.setAction(ACTION_DO_C);
startActivityForResult(intent,ONE);
And in Activity B you get the action easily:
getIntent().getAction();
You can use getCallingActivity() to get the activity that started current activity and that will receive the result value with response code at the end.

How to get back to the first activity when opening multiple activities

I have an app which have HomeActivity and 4 activities A,B,C,D.
I want when clicking on button start_activity_A_btn in HomeActivity to star activity A, and A starts B, B starts C, C starts D, then done button which takes me to HomeActivity.
NOTICE : in every activity (A,B,C,D) I have some data to save and get back to the HomeActivity after pressing done button.
What you need to do use the following flag in your intent (please check the link, it explains a similar situation to the one you are facing): FLAG_ACTIVITY_REORDER_TO_FRONT. So, in your activity D, in the onClickListener for the done button, here's the code you'd have to use:
Intent intent = new Intent(this, ActivityAname.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
intent.putExtra("data", dataYouReceiveFromABCD);
startActivity(intent);
This will get your A Activity to resume.
Now, regarding the "data" you will just have to keep accumulating this data in a String using some separator if that's possible (since you haven't told us what this data is exactly), so if it was a username and a password you could separate the two using a random combination of characters that will possibly never occur ("246#$^") and then just keep creating a string that you keep building in A, B, C and D and then finally in D you put that String as an extra in the intent (check the code I've posted above). If it's some other sort of data then you could perhaps serialize it if that helps. However, if you do use a String with a predetermined separator then all you will have to do is in Activity A you will have to use the following code in the onResume() method of Activity A.
if(this.getIntent().getExtras().getString("data") != null)
{
String data = this.getIntent().getExtras().getString("data");
//do some stuff here with that data
}
If you need data returning an Activity, you should use startActivityForResult to start ABCD. This works very much like your HomeActivity is opening up some dialog, and once the Activity finished (by pressing done or cancel, depends), you get onActivityResult in your HomeActivity.

Android, Finish all activities

I need to finish all the activities running in an Android application when an exit button is clicked. How can I do that?
What I want:
An option menu on screen with an EXIT option.
When I click the Exit menu, the application should close.
How to make a button for the user to immediately finish all Activities
When the user wishes to exit all open activities, have them press a button which loads the first Activity (passing in an intent to clear out all the other activities) that runs when your app starts. Then inside the one remaining activity (LoginActivity), place some code in onCreate to have it choose to self destruct.
Details:
Create a button and call it "exit", make a buttonlistener for that button, and put the following code in there. What it does is load the activity, makes it the only remaining activity by clearing all activities underneath it.
Intent intent = new Intent(getApplicationContext(), LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("EXIT", true);
startActivity(intent);
The above code clears all the activities under LoginActivity. The LoginActivity must be the first activity your app runs. So now we are left with only LoginActivity activated. Now we have to get LoginActivity to check the putExtra parameter, and if it has the value "EXIT" then destroy itself as well.
Put the following code inside the LoginActivity's onCreate and onResume, to check the "EXIT" parameter and finish when it is seen:
if (getIntent().getBooleanExtra("EXIT", false)) {
finish();
}
Why is this so hard, why isn't there just an exitAllActivites() function?
Android OS Developers make this hard because they don't want you to give the user an Exit button. They want the user never to care if their App is running or not. If they want it, they run it, if they don't want it, they stop using it. There are benefits to this model, because then an app can be destroyed to make room for a phone call and heavy map-usage, and then they re-run your app, they pick up right where they left off, rather than having to restart from scratch.
So if you use this code, try to cooperate with the Android Developers vision for Android and make it so that the App can be destroyed/recreated at any point, and the user always picks up where they left off. Requiring a user to 'exit' is a hassle.
use StartActivityForResult function for starting a new Activity and when user presses EXIT button, send a unique value as a resultcode. Check for this resultcode in onActivityForResult func and if you find the same unique code then finish the activity.
I don't understand the people who say that this should not be done. Closing an activity can be done quite easily using the built in method to do so.
There is no place in the official documentation that says this should not be done.
For those who think it should not be done for any purpose, maybe you can't think of a reason to do so. There are plenty of legitimate reasons to do this. And since it is a method built in to the Android code.. Google has also decided that you might need to depending on your use. Not all of us only create consumer applications for Android.
So to accomplish this task..shutting down all of the activities in your stack
public void quitApp(){
this.finishAffinity();
}
I created a kiosk app that was run as the default launcher. So I needed a way to exit the app to get to settings or other apps on the device. So in an admin Activity, I placed a pin number pad.. after the user inputs the correct pin, the app needed to exit to the original launcher. I used above code.
You should not implement an Exit button in an Android application.
Read http://groups.google.com/group/android-developers/browse_thread/thread/1bf0f7a4a9c62edd/a0a4aedf21ae5f76?pli=1
Cheers
How to close all activities in Android:
Why are the Android OS devs telling me not to create an Exit button?
If you give developers a hammer, they will use it, and everything becomes a nail, so don't give them a hammer. This is why there is no one-liner to exit all activities.
Why is an Exit button so bad?
You may be frustrated wondering why killing all activities in Android is so difficult. It's hard to do because you've got to bite the bullet and understand how you created the stack, and what it looks like. In what order should the Activities be destroyed? What if the user gets a phone call and needs to nuke your app ASAP? You NEED to have a plan for unwinding. It can't rely on the Activity Manager to babysit your app. If you want to kill your app, the OS devs are twisting your arm to create a unwinding plan because they don't want your application to have any errors when the Activity Manager nukes it.
This self destruct mechanism I go on to describe cooperates with the Activity Manager and causes a cascade effect that causes all activities to finish themselves no matter how they are organized.
To add this cascading self destruct to your app, do these three things:
If you are newbie to android and have never done this before, I suggest you create a brand new bare bones android project to test this out and get a feel for how it behaves. Only when you get the "aha" moment of understanding why this works, then can you extract the usefulness of the code below to delight the user.
Put this override method inside each one of your activities:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
//onActivityResult is called when a launched activity exits, giving
//you the requestCode, 1234, that you started it with. The resultCode
//it returned, 900, and any additional Intent data from it. The
//resultCode will be RESULT_CANCELED if the activity explicitly
//returned that, didn't return any result, or crashed during its
//operation.
switch(resultCode)
{
case 900: //Make 900 a final global variable if you want.
//900 means CLOSE_ALL_ACTIVITIES to me. It is
//a signal that the self destruct button has
//been initiated and all activities should end.
setResult(900); //setResult sets the resultCode that will be passed
//to onActivityResult in the activity that called
//this activity. this will immediately tell the
//parent to self destruct even before the next
//command, finish(), is run.
finish(); //Now stop this activity.
break;
}
super.onActivityResult(requestCode, resultCode, data);
}
If you have more than 3 activities, consider having each activity extending a "MyAppActivity" with the above code in there. If you catch yourself copy/pasting the above method into 15 different activities, slap yourself once, and take a class on good Object Oriented Programming. Then read this.
( Details about onActivityResult. ), ( Details about setResult. )
Whenever you have the user start a new activity, you must do it exactly this way:
Intent myIntent = new Intent(getBaseContext(), YourNewActivity.class);
startActivityForResult(myIntent, 1234);
//The 2nd parameter of startActivityForResult is what is sent to
//resultCode in the onActivityResult method. The code `1234`
//doesn't do anything here because it is a flag that is
//ignored in onActivityResult.
More information about startActivityForResult.
If you don't use startActivityForResult, then the self destruct unravelling won't work.
When you want to exit your application, initiate self destruct like this:
setResult(900); //900 is the self destruct code.
finish();
Then the activity stack unwinding plan cascades through the entire app.
you should do this on yourself. read this good blogpost: http://blog.radioactiveyak.com/2010/05/when-to-include-exit-button-in-android.html
Another solution to finish all activities works for me:
Somewhere in my Controller class, there is a method to initiate the shutdown:
/**
* Ask for application shutdown.
*
* <p>
* After the call, the system shall wipe the entire task and activities and
* then call {#link #onTaskWiped()} to finish the cleaning.
* </p>
*/
public void attemptShutdown() {
// wipe the task and its activities.
Application app = getApplication();
Intent intent = new Intent(app, ShutdownActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
app.startActivity(intent);
}
The ShutdownActivity is just performing data cleanup before finishing itself like it was told before.
/**
* This activity is started by {#link Controller#attemptShutdown()} to wipe the
* entire task and activities. It calls {#link Controller#onTaskWiped()} in
* {#link #onCreate(Bundle)} and finish immediately after.
*/
public class ShutdownActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// this is where you release the application data.
Controller.controller.onTaskWiped();
finish();
}
}
And finally the Manifest part. I have set the transparent style to avoid the small flash when the activity appears but it does not seem to work well.
<activity android:label="Exiting..."
android:name=".ShutdownActivity"
android:excludeFromRecents="true"
android:theme="#style/Theme.Transparent" />

Categories

Resources