I am trying to use Adobe Image Edit SDK to edit a photo then redirect to another activity, from my custom camera activity.
This works from another activity, simply by creating the Image edit Intent, using startActivityForResult, then treating the "Done" callback in said activity, in the method onActivityResult.
Intent imageEditorIntent = new AdobeImageIntent.Builder(mContext)
.setData(selectedImageUri)
.withToolList(tools)
.withOutput(new File(mLastSavedFilePath))
.build();
startActivityForResult(imageEditorIntent, 2);
and then
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (requestCode == 2) { // i get here
However, when I do this from my Custom Camera Activity, the activity ends when I click "done" in the image edit sdk (its onDestroy is called) before it gets to the result
Intent intent = FileUtils.getInstance().SavePhoto(data, mContext); //this returns an AdobeImageIntent
startActivityForResult(intent, 1);
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
//this never gets called, because activity finishes, but why?
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
So why is the activity finishing, if the other one does not?
Turns out this was my fault, I did not notice I had android:noHistory="true"
in the manifest for the second activity
I have a Fragment that contains a RecyclerView which uses a custom RecyclerAdapter. I have an onClickListener inside my custom RecyclerAdapter - when a position is clicked I want it to start startActivityForResult. So far this works in as such as when it is clicked it starts the Activity as desired. However when I press the back button to go to the Fragment containing the RecyclerView onActivityResult is never called. I have passed in a context to the custom RecyclerAdapter. Is this something that is possible? Or does the Activity/Fragment initiating startActivityForResult be the one that intercepts it? If not I will end up handling the onClick in the Fragment with a gesture detector or something similar, but before that I wanted to give this a fair crack! Note: I have included onActivityResult in the MainActivity which has the Fragment container so the Fragment does receive onActivityResult if startActivityForResult is initiated from the Fragment. My code:
RecyclerAdapter onClickListener:
#Override
public void onClick(View v) {
String titleId = titlesListDataArrayList.get(getLayoutPosition()).getTitle_id();
Intent intent = new Intent(context, CreateItemsActivity.class);
intent.putExtra("TITLE_ID", titleId);
((Activity) context).startActivityForResult(intent, Constants.NEW_ITEMS_REQUEST_CODE);
}
CreateItemsActivity.class - onBackPressed()
#Override
public void onBackPressed() {
Intent intent = new Intent();
setResult(Constants.NEW_ITEMS_REQUEST_CODE, intent);
finish();
}
MyListsFragment.class (contains RecyclerView)
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.e("CALLED", "OnActivity Result");
// if requestCode matches from CreateItemsActivity
if (requestCode == Constants.NEW_ITEMS_REQUEST_CODE) {
Log.e("REQUEST CODE", String.valueOf(requestCode));
populateRecyclerView();
}
}
Also I have this in the MainActivity:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// included to allow fragment to receive onActivityResult
}
Your calling Activities onActivityResult will only be called when the second activity finishes and a setResult has been executed.
Since the user is hitting the back button the 2nd activity is finishing without setResult being called.
You'll need to override onBackPressed so you can execute your setResult code.
I see you have implemented this but I think the crux of the issue is that you need to return Activity.RESULT_OK not your request code.
#Override
public void onBackPressed() {
Intent intent = new Intent();
setResult(RESULT_OK, intent);
super.onBackPressed();
}
In this case you don't need to explicitly return your requestCode of Constants.NEW_ITEMS_REQUEST_CODE because Android will forward that automatically.
OK, so IF by any chance somebody else has this problem here is my
solution. I added this code into the MainActivity onActivityResult (note I have a frame container which is where all fragments are inflated):
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// get current fragment in container
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.frameContainer);
fragment.onActivityResult(requestCode, resultCode, data);
}
I believe this works as the MainActivity is top in the hierarchy and intercepts the onActivityResult, so basically I just point it where I want it to be used.
In first activity, there is empty ListView and Button.
When I press button, it starts second activity that has ListView of categories.
After I click into one of listElements it will start third activity that has ListView with elements that are belong to my chosen category.
When I choose element of third ListView it must send me back to first activity, where my chosen element is added to my empty ListView
Use Intent.FLAG_ACTIVITY_FORWARD_RESULT like this:
FirstActivity should start SecondActivity using startActivityForResult().
SecondActivity should start ThirdActivity using this:
Intent intent = new Intent(this, ThirdActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
startActivity(intent);
finish();
This tells ThirdActivity that it should return a result to FirstActivity.
ThirdActivity should return the result using
setResult(RESULT_OK, data);
finish();
At that point, FirstActivity.onActivityResult() will be called with the data returned from ThirdActivity.
Though I'd implore you to change your architecture design, it is possible to do it like this:
File ActivityOne.java
...
startActivityForResult(new Intent(this, ActivityTwo.class), 2);
...
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(resultCode == RESULT_OK && data != null) {
//Collect extras from the 'data' object
}
}
...
File ActivityTwo.java
...
startActivityForResult(new Intent(this, ActivityTwo.class), 3);
...
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(resultCode == RESULT_OK && data != null) {
setResult(resultCode, data);
finish();
}
setResult(RESULT_CANCELLED);
}
...
File ActivityThree.java
...
//Fill the Intent resultData with the data you need in the first activity
setResult(RESULT_OK, resultData);
finish();
...
In my MainActivity, I launch a second activity:
Button button = (Button) findViewById(R.id.btnPush);
button.setOnClickListener(new View.OnClickListener(){
public void onClick(View view){
Intent nowStart = new Intent(getApplicationContext(), AddPillScheduleActivity.class);
startActivityForResult(nowStart, RESULT_OK);
//startSecond();
}
});
Then inside my Second Activity, I would like to return a value back to the main activity.
Intent i=new Intent();
i.putExtra("ANSWER", ans);
setResult(RESULT_OK,i);
finish();
That seems to execute fine, but back in my MainActivity, I would like to grab the value. This is where I am having trouble. My debugger never stops on my onActivityResult, which is:
#Override
protected void onActivityResult(int requestCode ,int resultCode ,Intent data ) {
super.onActivityResult(requestCode, resultCode, data);
String name = getIntent().getExtras().getString("ANSWER");
if (resultCode == RESULT_OK) {
Toast.makeText(this, name, Toast.LENGTH_LONG).show();
}
Can someone shed a little light? Thanks.
You're not getting the value from the right intent, the one that comes with the method. Modify your code to the following:
#Override
protected void onActivityResult(int requestCode ,int resultCode ,Intent data ) {
super.onActivityResult(requestCode, resultCode, data);
String name = data.getStringExtra("ANSWER");
if (resultCode == RESULT_OK) {
Toast.makeText(this, name, Toast.LENGTH_LONG).show();
}
}
Use the getStringExtra method as you put a String in your intent and not a bundle. Also, not the best practice use the same code for the requestCode and resultCode.
String name = getIntent().getExtras().getString("ANSWER");
is accessing the wrong intent. getIntent() returns the intent that started the activity. You want
String name = data.getExtras().getString("ANSWER");
Also, the second parameter of startActivityForResult() is a request code, so using RESULT_OK -- althought it still works -- is confusing.
I have been using the new nested fragment API that Android includes in the support library.
The problem that I am facing with nested fragments is that, if a nested fragment (that is, a fragment that has been added to another fragment via the FragmentManagerreturned by getChildFragmentManager()) calls startActivityForResult(), the nested fragment's onActivityResult() method is not called. However, both the parent fragment's onActivityResult() and activity's onActivityResult() do get called.
I don't know if I am missing something about nested fragments, but I did not expect the described behavior. Below is the code that reproduces this problem. I would very much appreciate if someone can point me in the right direction and explain to me what I am doing wrong:
package com.example.nestedfragmentactivityresult;
import android.media.RingtoneManager;
import android.os.Bundle;
import android.content.Intent;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends FragmentActivity
{
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
this.getSupportFragmentManager()
.beginTransaction()
.add(android.R.id.content, new ContainerFragment())
.commit();
}
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
// This is called
Toast.makeText(getApplication(),
"Consumed by activity",
Toast.LENGTH_SHORT).show();
}
public static class ContainerFragment extends Fragment
{
public final View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState)
{
View result = inflater.inflate(R.layout.test_nested_fragment_container,
container,
false);
return result;
}
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
getChildFragmentManager().beginTransaction()
.add(R.id.content, new NestedFragment())
.commit();
}
public void onActivityResult(int requestCode,
int resultCode,
Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
// This is called
Toast.makeText(getActivity(),
"Consumed by parent fragment",
Toast.LENGTH_SHORT).show();
}
}
public static class NestedFragment extends Fragment
{
public final View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState)
{
Button button = new Button(getActivity());
button.setText("Click me!");
button.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
startActivityForResult(intent, 0);
}
});
return button;
}
public void onActivityResult(int requestCode,
int resultCode,
Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
// This is NOT called
Toast.makeText(getActivity(),
"Consumed by nested fragment",
Toast.LENGTH_SHORT).show();
}
}
}
test_nested_fragment_container.xml is:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</FrameLayout>
I solved this problem with the following code (support library is used):
In container fragment override onActivityResult in this way:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
List<Fragment> fragments = getChildFragmentManager().getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
fragment.onActivityResult(requestCode, resultCode, data);
}
}
}
Now nested fragment will receive call to onActivityResult method.
Also, as noted Eric Brynsvold in similar question, nested fragment should start activity using it's parent fragment and not the simple startActivityForResult() call. So, in nested fragment start activity with:
getParentFragment().startActivityForResult(intent, requestCode);
Yes, the onActivityResult() in nested fragment will not be invoked by this way.
The calling sequence of onActivityResult (in Android support library) is
Activity.dispatchActivityResult().
FragmentActivity.onActivityResult().
Fragment.onActivityResult().
In the 3rd step, the fragment is found in the FragmentMananger of parent Activity. So in your example, it is the container fragment that is found to dispatch onActivityResult(), nested fragment could never receive the event.
I think you have to implement your own dispatch in ContainerFragment.onActivityResult(), find the nested fragment and invoke pass the result and data to it.
Here's how I solved it.
In Activity:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
List<Fragment> frags = getSupportFragmentManager().getFragments();
if (frags != null) {
for (Fragment f : frags) {
if (f != null)
handleResult(f, requestCode, resultCode, data);
}
}
}
private void handleResult(Fragment frag, int requestCode, int resultCode, Intent data) {
if (frag instanceof IHandleActivityResult) { // custom interface with no signitures
frag.onActivityResult(requestCode, resultCode, data);
}
List<Fragment> frags = frag.getChildFragmentManager().getFragments();
if (frags != null) {
for (Fragment f : frags) {
if (f != null)
handleResult(f, requestCode, resultCode, data);
}
}
}
For Androidx with Navigation Components using NavHostFragment
Updated answer on September 2, 2019
This issue is back in Androidx, when you are using a single activity and you have nested fragment inside the NavHostFragment, onActivityResult() is not called for the child fragment of NavHostFragment.
To fix this, you need manually route the call to the onActivityResult() of child fragments from onActivityResult() of the host activity.
Here's how to do it using Kotlin code. This goes inside the onActivityResult() of your main activity that hosts the NavHostFragment:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.your_nav_host_fragment)
val childFragments = navHostFragment?.childFragmentManager?.fragments
childFragments?.forEach { it.onActivityResult(requestCode, resultCode, data) }
}
This will make sure that the onActivityResult() of the child fragments will be called normally.
For Android Support Library
Old answer
This problem has been fixed in Android Support Library 23.2 onwards.
We don't have to do anything extra anymore with Fragment in Android Support Library 23.2+. onActivityResult() is now called in the nested Fragment as expected.
I have just tested it using the Android Support Library 23.2.1 and it works. Finally I can have cleaner code!
So, the solution is to start using the latest Android Support Library.
I have search the FragmentActivity source.I find these facts.
when fragment call startActivityForResult(), it actually call his parent FragmentActivity's startAcitivityFromFragment().
when fragment start activity for result,the requestCode must below 65536(16bit).
in FragmentActivity's startActivityFromFragment(),it call Activity.startActivityForResult(), this function also need a requestCode,but this requestCode is not equal to the origin requestCode.
actually the requestCode in FragmentActivity has two part. the higher 16bit value is (the fragment's index in FragmentManager) + 1.the lower 16bit is equal to the origin requestCode. that's why the requestCode must below 65536.
watch the code in FragmentActivity.
public void startActivityFromFragment(Fragment fragment, Intent intent,
int requestCode) {
if (requestCode == -1) {
super.startActivityForResult(intent, -1);
return;
}
if ((requestCode&0xffff0000) != 0) {
throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");
}
super.startActivityForResult(intent, ((fragment.mIndex+1)<<16) + (requestCode&0xffff));
}
when result back.FragmentActivity override the onActivityResult function,and check if the requestCode's higher 16bit is not 0,than pass the onActivityResult to his children fragment.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
mFragments.noteStateNotSaved();
int index = requestCode>>16;
if (index != 0) {
index--;
final int activeFragmentsCount = mFragments.getActiveFragmentsCount();
if (activeFragmentsCount == 0 || index < 0 || index >= activeFragmentsCount) {
Log.w(TAG, "Activity result fragment index out of range: 0x"
+ Integer.toHexString(requestCode));
return;
}
final List<Fragment> activeFragments =
mFragments.getActiveFragments(new ArrayList<Fragment>(activeFragmentsCount));
Fragment frag = activeFragments.get(index);
if (frag == null) {
Log.w(TAG, "Activity result no fragment exists for index: 0x"
+ Integer.toHexString(requestCode));
} else {
frag.onActivityResult(requestCode&0xffff, resultCode, data);
}
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
so that's how FragmentActivity dispatch onActivityResult event.
when your have a fragmentActivity, it contains fragment1, and fragment1 contains fragment2.
So onActivityResult can only pass to fragment1.
And than I find a way to solve this problem.
First create a NestedFragment extend Fragment override the startActivityForResult function.
public abstract class NestedFragment extends Fragment {
#Override
public void startActivityForResult(Intent intent, int requestCode) {
List<Fragment> fragments = getFragmentManager().getFragments();
int index = fragments.indexOf(this);
if (index >= 0) {
if (getParentFragment() != null) {
requestCode = ((index + 1) << 8) + requestCode;
getParentFragment().startActivityForResult(intent, requestCode);
} else {
super.startActivityForResult(intent, requestCode);
}
}
}
}
than create MyFragment extend Fragment override onActivityResult function.
public abstract class MyFragment extends Fragment {
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
int index = requestCode >> 8;
if (index > 0) {
//from nested fragment
index--;
List<Fragment> fragments = getChildFragmentManager().getFragments();
if (fragments != null && fragments.size() > index) {
fragments.get(index).onActivityResult(requestCode & 0x00ff, resultCode, data);
}
}
}
}
That's all!
Usage:
fragment1 extend MyFragment.
fragment2 extend NestedFragment.
No more different.Just call startActivityForResult() on fragment2, and override the onActivityResult() function.
Waring!!!!!!!!
The requestCode must bellow 512(8bit),because we spilt the requestCode in 3 part
16bit | 8bit | 8bit
the higher 16bit Android already used,the middle 8bit is to help fragment1 find the fragment2 in his fragmentManager array.the lowest 8bit is the origin requestCode.
For Main Activity you write OnActivityForResult with Super class like as
#Override
public void onActivityResult(int requestCode, int resultCode, Intent result) {
super.onActivityResult(requestCode, resultCode, result);
if (requestCode == Crop.REQUEST_PICK && resultCode == RESULT_OK) {
beginCrop(result.getData());
} }
For activity Write intent without getActivity()
like as
Intent pickContactIntent = new Intent(Intent.ACTION_PICK, Uri.parse("content://contacts"));
pickContactIntent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE); // Show user only contacts w/ phone numbers
startActivityForResult(pickContactIntent, 103);
OnActivityResult for fragment
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 101 && resultCode == getActivity().RESULT_OK && null != data) {
}}
I faced the same problem! I solved it by using static ChildFragment in the ParentFragment, like this:
private static ChildFragment mChildFragment;
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
mChildFragment.onActivityResult(int requestCode, int resultCode, Intent data);
}