I'm trying to implement an efficent navigation for my app; basically it's a product catalog, I mean:
list Product -> detail
list Product (serach button in interface - startActivityForResult ) -> searchAct (cal finish) -> back to list Product (filtered)
but i need to open searchAct by the HW search button, and also from detail!
is it possible to use startActivityForResult from detail to open searchAct and when searchAct finish forward to list product?
Also, if i open searchAct then press back i need to get back to detail!
if i use always:
startActivity()
then the user needs to press BACK button repeatedly, see all the steps...
for example if the usage is like this:
list (startActivity) ->detail (startActivity)->search (startActivity)->list (startActivity) ->detail
the back button works fine but i have to BACK 5 TIMES FOR EXIT!!
i try:
list (startActivity) ->detail (startActivity and finish() )->search (call finish()) ->list
BUT this way Back button in search is 'broken' because i got to list instead detail....
maybe i can try this:
detail (startActivityForResult) -> search
in detail if i got result_ok i finish() and get back to the list, if i got result_cancel i stay in detail?
i think i got it!!! in list activity i have 'classic' startActivityForResult then 'classic' onActivityResult
in detail activity i launch serach with startActivityForResult then:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
finish();
}
}
finishing the detail i got back to list.... i don't know if it's ok but i like it!
It's quite hard to understand whats your problem about, so im just guessing your need.
In your searchAct activity you can return data like this:
Intent returnIntent = new Intent();
String strData = "your data";
returnIntent.putExtra("data", strData);
setResult(RESULT_OK, returnIntent);
finish();
Then in your detail activity, from where you are starting searchAct, you have a function which is triggered when searchAct finish.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {}
From the product detail activity, you are starting the search activity via startActivityForResult. In which case you can call finish() in the onActivityResult of the product detail activity when the search activity returns the correct code.
This way, the product detail will finish after a search and you'll end up back at the list activity.
If you start the product detail with startActivityForResult as well, you can return the data that your product activity gets given from the search activity.
I guessing this is what you want?
Related
So I have activity 1, which is a main menu activity. Then I have activity 2 which is a store page. The store activity starts with the current user balance. When the user is in the store, he can purchase several things.
I want to send the updated balance back to the main menu activity after the user purchased things. I am using StartActivityForResult but the issue is that I don't know when activity 2 (the store) will end. I don't use a 'finish' button or anything that takes the user back to the main menu. The user just goes back to the main menu by clicking the back button on his phone.
How would I tackle this problem and send back the updated balance to activity 1?
Thank you in advance,
Alexander
Activity1 should launch Activity2 using startActivityForResult().
Every time the user does something in Activity2, call setResult() with an Intent containing the current balance in an "extra".
When the user presses the BACK button, onActivityResult() will be called in Activity1 with the last Intent that you passed to setResult(). You can then extract the current balance from the "extra" in the `Intent.
You don't need to override anything.
There are multiple ways to achieve this and you can use any.
1) You can override the onBackPress method of Activity2 to detect when the user is pressing the back button and set your result there.
2) You can fetch the updated balance from your database when your Activity1's onStart method get called. (Or you can use live-data/Data binding for single source of truth)
3) You can use a singleton class to maintain the current balance. Update it in Activity2 and fetch it in Activity1.
According to official doc
you can call second activity like this:
Intent pickContactIntent = new Intent(Intent.ACTION_PICK, Uri.parse("content://contacts"));
pickContactIntent.setType(Phone.CONTENT_TYPE); // Show user only contacts w/ phone numbers
startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST);
and then in your first activity waiting for result in this way:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// Check which request we're responding to
if (requestCode == PICK_CONTACT_REQUEST) {
// Make sure the request was successful
if (resultCode == RESULT_OK) {
// The user picked a contact.
// The Intent's data Uri identifies which contact was selected.
// Do something with the contact here (bigger example below)
}
}
}
This may sounds simple, but I am so bewildered by it. I have searched but not found any solution.
My question is: How to return to two activities when back button pressed?
Like this: let me say that I have activities A, B and C (A -> B -> C). What I want to achieve is when I am on activity C and press the back button, It should return me to activity A. When I am on B and press back, it should return me to A too.
It may be implemented into a project with many activities, so I assume that I don't need to set the class name of where to return, It should be recorded automatically by the android. How to achieve this?
Thank you
A possible solution is calling startActivityForResult() from Activity B, so that on the callback of the created Activity C, the previous Activity B gets finished as well. The callback function is called onActivityResult(), and in that, you want to call finish().
Example:
ActivityB:
Intent i = new Intent(this, ActivityC.class);
startActivityForResult(i, 0);
...
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
this.finish();
}
ActivityC:
//do stuff
This way, when you press Back (or call finish()) in ActivityC, it will call back on ActivityB's onActivityResult() function, and it will end them both.
You can override the onBackPressed method and sent an intent to the activity you want.
#Override
public void onBackPressed()
{
// code here to send intent to the activity A
}
One thing, I'm not sure if this goes well with the activity stack but you can alway try.
you can finish activity B , when you are starting intent for activity C, then activity stack will have activity A, and when you press back on activity C, activity A will be displayed.
just override onBackPressed in Activity C, and finish() it.
You can call the Activity that you want to go back to with a special flag (FLAG_ACTIVITY_CLEAR_TOP) from your onBackButtonPressed which will skip/remove the other activities in between. This way you can go back from C to A.
See: http://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_CLEAR_TOP
I think this is better than messing around with the finish() or starting activity for result when there is no result to return.
A --> B --> C
Intent intent = new Intent(this, A.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
This will launch a new intent for Activity A and clears all the other activities from Stack.
My Android app is for a hiking club and starts with a Home screen, which is the main activity.
The home screen shows the house-style and has some buttons to the core functionalities: list of upcoming hikes, history of hikes, last reactions and also a message board.
THe activity flow is pretty straightforward, you can i.e. navigate from:
Home -> Hike list -> Hike Details
And back using the Back button. Going back from the Home activity will ask for closing the app.
I already use the FLAG_ACTIVITY_CLEAR_TOP flag to prevent several instance of the same activity.
But my problem is I have also implemented a Menu to navigate to the core functionalities directly.
So for example, when in the Hike Detail screen, one can choose to go to the Message board. But I do not want to keep the Hike List -> Hike Detail activities on the stack.
So when pressing Back from the message board, I always want to return to the Home activity.
IS there a clean possibility to pop the stack and only keep the Home activity before launching a new activity? I guess that would solve my issue.
I found something similar on SO that might work.
Check out: FLAG_ACTIVITY_TASK_ON_HOME
Pre API 11:
Start all of your activities from home using startActivityForResult(). When you navigate to a parallel stack via the global menu. Call this on your current activity:
// startParallelActivity();
setResult(KILL_YOURSELF);
finish;
Where every activity on top of home implements onActivityResult() like so:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == KILL_YOURSELF) {
setResult(KILL_YOURSELF);
finish();
}
}
This will destroy all the activities in the current stack, leaving just the home activity that will be there when the user hits "back"
What Is Working Fine
I have 2 activities in my app. First activity calls second actifity for results.
Second activity shows a new layout and lets user perform certain actions. There is a "OK" button. When user presses this button, second activity is finished and user goes back to first activity.
Under the hood, first activity calls second ativity like this:
Intent intent = new Intent(this, NextAct.class);
intent.putExtra("input", input);
this.startActivityForResult(intent, 99);
On "OK" button press, second activity returns with result like this:
Intent intent = new Intent();
intent.putExtra("output", output);
setResult(RESULT_OK, intent);
finish();
After that, first activity's onActivityResult is called with results successfully:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// requestCode is 99
// resultCode is -1
// data holds my output
}
Above setup is working perfectly
What Is Not Working
Now I had a simple requirement, I wanted the user to close the second activity not with an "OK" button, but in a natural way with "HARDWARE BACK" button.
I tried moving the setResult logic in onStop and onDestroy methods of second activity, but it turned out that onActivityResult of first activity is called before onStop or onDestroy methods of second activity and as a result setResult logic does not get a chance to run at all.
Then I tried moving the setResult logic in onPause method of second activity like this
protected void onPause() {
super.onPause();
Intent intent = new Intent();
intent.putExtra("output", output);
setResult(RESULT_OK, intent);
//finish(); enabling or disabling this does not work
}
But although onPause is being called well before onActivityResult and setResult logic runs properly, still I get all null values in onActivityResult
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// requestCode is 99
// resultCode is 0
// data comes as null
}
I need to know why this is happening and if onResume is not a proper place to put setResult logic, what is the most natural way to do it?
Thanks much.
Now I had a simple requirement, I wanted the user to close the second activity not with an "OK" button, but in a natural way with "HARDWARE BACK" button.
That is not usually "natural" for a startActivityForResult() scenario. The BACK button should allow the user to tell you "No, it is not OK" (i.e., cancel).
This does not mean you necessarily have to have an OK button. For example, if NextAct were a ListActivity, a typical pattern is for clicking on a list item to be considered "OK" (i.e., call setResult() and finish() from onListItemClick()), and BACK to mean "I didn't really mean to start NextAct, sorry".
I need to know why this is happening
You are calling setResult() too late. If the user presses BACK, by the time of onPause(), the result (RESULT_CANCELED) has already been determined.
if onResume is not a proper place to put setResult logic
onResume() would not be a proper place to "put setResult logic"
what is the most natural way to do it?
Possibly what you have with the OK button is the "most natural way to do it".
However, if for some strange reason you really do want the BACK button to mean "OK", override onBackPressed() and call setResult() there before chaining to the superclass with super.onBackPressed().
The best way I found is to override finish() method:
#Override
public void finish() {
Intent data = new Intent();
data.putExtra(INTENT_PARAM_OPTIONS, options);
setResult(RESULT_OK, data);
super.finish();
}
In that case, your activity will always return data, even if the user presses back button (or activity bar up button).
And I think its perfectly natural to do this in some circumstances. If you have an activity that is made to edit one big entity (shipping order for instance), and a smaller activity inside that activity that modifies 1 small part of big entity (shipping address), you might aswell always save any changes inside smaller activity, because user can cancel all the changes by cancelling the big activity.
You can try to override onBackPressed or onKeyDown, and setResult(RESULT_OK, intent) there.
I have a main Activity A that can kick off sub-Activities B, C, or D. I start them using startActivityForResult(newIntent, REQUEST_CODE);
The user can choose to navigate between B, C, and D once one is displayed. Activity A controls that navigation. When they choose swap between screens 'A' first calls finishActivity(REQUEST_CODE); on the one displayed and then call startActivityForResult(newIntent, REQUEST_CODE); for the next one.
In my onActivityResult I've got
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
// these logs are just for my debugging
Log.w(this.toString(), "onActivityResult returned to by " + requestCode);
Log.w(this.toString(), "result code = " + resultCode );
// the Activity set this value if it was returning normally
if (RESULT_OK == resultCode)
{
Log.i(this.toString(), "---- the sub-activity returned OK ----");
// do some stuff
}// end if (RESULT_OK == resultCode)
// Else we got here because the user hit the back button or something went
// went wrong (RESULT_CANCELED). Either way we do not want to display this
// blank screen to the user. Take them back to the device connection screen.
else if (RESULT_CANCELED == resultCode)
{
finish();
}
}
For some reason I'm getting back a zero or RESULT_CANCELED everytime even though in my sub-activities B,C,D I only set that result if the user chooses to hit the back button (I display an "are you sure" dialog and they choose to exit. In B,C,D I have the following in onPause. The userExiting is a flag I set from the Exit dialog.
protected void onPause()
{
Log.i(this.toString(), "onPause");
// hack to try to setResult for an activity whose finishActivty was called
if ( !this.exiting )
{
Log.i(this.toString(), "======== RESULT_OK ========");
Intent returnIntent = new Intent();
setResult(RESULT_OK, returnIntent);
finish();
}
displayed = false;
super.onPause();
}
Any ideas?
Edit - to be clear the issue is that after calling finishActivty on the old Activity, since a result was never set, Activity A always thinks it should exit. One weird side items. This doesn't happen until the user navigates two times. In other words B is displayed and they choose to go to C. Works, but I can see in the log that onActivityResult hasn't been called. User selects to go from C to D, boom, I see two calls to onActivtyResult, 'A; exits and D is left displayed and the user is unable to nav away.
Update: Since this has been getting a lot of views I thought I'd post this update. The project evolved such that sometimes a single Activity is displays and sometimes a group are displayed as tabs. When the user packs out of the tab in some cases data needed to be returned to the Activity that kicked off the tabs. Before I added the code below RESULT_CANCELED would always be returned. Also make sure that setResult is called before finish.
if (getParent() == null)
{
setResult(Activity.RESULT_OK, intent);
}
else
{
getParent().setResult(Activity.RESULT_OK, intent);
}
I'm not quite following everything you are doing here, but it doesn't sound like you are navigating between activities properly. I would highly suggest reading through the notepad example thoroughly so that you understand the android way of moving between Activities.
Here is what I understand regarding what you are trying to accomplish: Activity A can navigate to B, C or D. From B, C or D you can navigate to any of the others.
You are somehow trying to using Activity A as a controller, having it finish other Activities. Don't do this. Each Activity should be responsible for finishing itself at the proper point.
If you want to go from having A -> B on the stack to A -> C, then I would do this:
A starts B for result. When user selects something in B asking to go to C you have a few choices. You could have B start C not for result, then finish. This would have the effect of B being removed from the stack when C exits. Or, you could have B finish itself, passing back a note that C should be loaded in the results intent. A could then load C for result.
I'm really not sure why you want this behavior though. As an Android user, if I go from A -> B -> C, I expect hitting back to take me back to B.
As an aside, your "is exiting" hack doesn't make any sense. By the time you get to onPause, the result has been set. You cannot change it here. You need to properly set the result when you are finishing, before onPause.