onActivityResult() is not called when startActivit

2019-08-19 03:25发布

问题:

I have read through the related posts. In every quaestion I see that onActivityResult() of activity gets called at least..the problem is how to carry the result to the fragments or nested fragments. But issue I am facing is different.
I am implementing Settings page that will have tabs with TabLayout from new Design Support library. In my app I have a single Activity which holds other Fragments...so I added a SettingsTabFragment which has ViewPager and a FragmentPagerAdapter to it.This adapter holds fragments for each tab.
One of the tab is User Profile settings where user can add his profile pic. And I called startActivityResult() from child fragment with ACTION_PICK intent. I overriden the onActivityResult() in Activity, in parent fragment (that holds view pager) and in SettingsTabFragment too. But none of them get called when I chose the pic from gallery.

None of onActivityResult() get called when startActivityResult() called from:
- child fragment.
- parent fragment. I did this from child frag getParentFragment().startActivityResult() AND also from within the parent fragment itself which is attached to activity directly (not nested).
- called using activity from child fragment with getParentFragment().getActivity().startActivityResult().

None of them lead to call onActivityResult() of, at least, activity.

When I called startActivityResult() from fragment I made sure I called just startActivityResult()..not getActivity().startActivityResult().

I follwed onActivityResult is not being called in Fragment and tried the github lib suggested in one of the answers but seems owner told it is not recommended now. Also it has got compilation errors.

Nay thoughts on it ?

回答1:

In my case i was picking up the mobile number from the contact by using intent in my child fragment class i.e. one of tab of view pager.

calling the parent fragment from MainActivity:

// Home is my parent fragment which contains Tab Layout and View Pager. I am calling Home Fragment by specifying tag, i will use this tag later on.

Fragment fragment = new Home();
fragmentManager.beginTransaction()
               .replace(R.id.main_content, fragment, "MobileTag")
               .addToBackStack(null)
               .commit();

In My child Fragment class:

Intent intent = new Intent(Intent.ACTION_PICK, 
                           ContactsContract.Contacts.CONTENT_URI);
intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE);
startActivityForResult(intent, 1);

Now it will call the onActivityResult method of MainActivity class In Main Activity:

public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
}

By Calling super in onActivityResult of MainActivity will make a call to Parent fragment's i.e. Home Fragment's onActivityResult method.

In Parent Fragment i.e. Home Fragment:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    Fragment fragment = getFragmentManager()
        .findFragmentByTag("MobileTag")
        .getChildFragmentManager()
        .getFragments()
        .get(0);
    fragment.onActivityResult(requestCode, resultCode, data);
}

here I am getting the 0th Child of parent fragment e.g. In View Pager Adapter if Fragment are added like:

@Override
public Fragment getItem(int position) {
    switch (position){
        case 0 :return new ChildFragment0();
        case 1 : return new ChildFragment1();
        case 2 : return new ChildFragment2();
    }
    return null;
}

Then

getFragmentManager()
   .findFragmentByTag("MobileTag")
   .getChildFragmentManager()
   .getFragments()
   .get(0); // will return ChildFragment0

After this Make a call to child fragment's onActivityResult method:

And Finally In Child Fragment:

public void onActivityResult(int reqCode, int resultCode, Intent data) {
    Cursor cursor = null;
    String contactNumber = "";           
    Uri result = data.getData();
    // get the result here
}


回答2:

Currently, it's a known Android bug. Until this is solved a workaround can be used:

public class HackForResultFragment extends Fragment {

    private static Fragment _callingFragment;

    private Intent _intent;
    private int _requestCode;


    public static HackForResultFragment newInstance(int _requestCode, Intent _intent){

        HackForResultFragment fragment = new HackForResultFragment();
        Bundle bundle = new Bundle(2);
        bundle.putInt("_requestCode", _requestCode);
        bundle.putParcelable("_intent", _intent);
        fragment.setArguments(bundle);
        return fragment;
    }

    public HackForResultFragment() {
    }

    public void setCallingFragment(Fragment callingFragment){
        _callingFragment = callingFragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Bundle arguments = getArguments();
        if (arguments == null) {
            //Error handling
            LogUtil.Error("arguments should have been passed to HackForResultFragment");
        }
        else {
            _requestCode = arguments.getInt("_requestCode");
            _intent = arguments.getParcelable("_intent");
        }

        if (savedInstanceState == null) { //first time only
            startActivityForResult(_intent, _requestCode);
        }
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
    }

    @Override
    public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
        if (_requestCode == requestCode) {

            if (_callingFragment != null) {
                _callingFragment.onActivityResult(requestCode, resultCode, data);
                _callingFragment = null;
            }
        }
        getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();

    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        outState.putBoolean("startActivityForResultAlreadyCalled",true);
    }
}

In your calling fragment override startActivityForResult:

@Override
public void startActivityForResult(final Intent _intent, final int _requestCode) {
    FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
    HackForResultFragment f = HackForResultFragment.newInstance(_requestCode,_intent);
    f.setCallingFragment(this);
    fragmentManager.beginTransaction().add(f, null).commit();
}


回答3:

This bug is now resolved in support library version 23.2.0, so the best way to solve this now is to upgrade the support library.

Source: https://code.google.com/p/android/issues/detail?id=40537#c40



回答4:

if FragmentActivity contain fragment1, fragment1 contain fragment2. Android can only handle fragment1.startActivityForResult,fragment2.startActivityForResultwill not working.

For more detail and solution, watch the this answer answer