[android] onActivityResult n'est pas appelé dans Fragment


Answers

Je pense que vous avez appelé getActivity().startActivityForResult(intent,111); . Vous devriez appeler startActivityForResult(intent,111); .

Question

L'activité hébergeant ce fragment a son onActivityResult appelé lorsque l'activité de la caméra revient.

Mon fragment commence une activité pour un résultat avec l'intention envoyée à la caméra de prendre une photo. L'application d'image se charge bien, prend une photo et revient. Le onActivityResult n'est cependant jamais atteint. J'ai défini des points d'arrêt, mais rien n'est déclenché. Un fragment peut-il avoir onActivityResult ? Je le pense car c'est une fonction fournie. Pourquoi cela n'est-il pas déclenché?

ImageView myImage = (ImageView)inflatedView.findViewById(R.id.image);
myImage.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View view) {
        Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
        startActivityForResult(cameraIntent, 1888);
    }
});

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if( requestCode == 1888 ) {
        Bitmap photo = (Bitmap) data.getExtras().get("data");
        ((ImageView)inflatedView.findViewById(R.id.image)).setImageBitmap(photo);
    }
}



Un point que personne n'a mention qui s'assure que votre mode de lancement de l' activité hôte ne doit pas être défini sur singleInstance ou sur singleTask .

OnActivityResult ne fonctionnera pas si votre mode de lancement est défini sur SingleInstance ou SingleTask. ou vous appelez votre activité en utilisant ces IntentFilters

standard mode de lancement standard ou singleTop .




J'ai ce même problème avec le ChildFragmentManager . Le gestionnaire ne transmettra pas le résultat au fragment imbriqué, vous devez le faire manuellement dans votre fragment de base.

public void onActivityResult(int requestCode, int resultCode, Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);
    Fragment fragment = (Fragment) getChildFragmentManager().findFragmentByTag(childTag);
    if (fragment != null) {
        fragment.onActivityResult(requestCode, resultCode, intent);
    }
}



Message original.

FragmentActivity remplace requestCode par un modifié. Après cela, lorsque onActivityResult() sera onActivityResult() , FragmentActivity analyse les 16 bits supérieurs et restaure l'index du fragment d'origine. Regardez ce schéma:

Si vous avez quelques fragments au niveau de la racine, il n'y a pas de problèmes. Mais si vous avez des fragments imbriqués , par exemple Fragment avec quelques onglets à l'intérieur de ViewPager , vous êtes assuré de faire face à un problème (ou déjà confronté).

Parce qu'un seul index est stocké dans requestCode . C'est l'index de Fragment dans son FragmentManager . Lorsque nous utilisons des fragments imbriqués, il existe des FragmentManager enfants, qui ont leur propre liste de Fragments. Il est donc nécessaire de sauvegarder toute la chaîne d'indices, à partir de la racine FragmentManager .

Comment pouvons-nous résoudre ce problème? Il existe une solution de contournement commune dans ce post .

GitHub: https://github.com/shamanland/nested-fragment-issue




À l'intérieur de votre fragment, appelez

this.startActivityForResult(intent, REQUEST_CODE);

this se réfère au fragment. Sinon, faites comme @Clevester a déclaré:

Fragment fragment = this;
....
fragment.startActivityForResult(intent, REQUEST_CODE);

J'ai aussi dû appeler

super.onActivityResult(requestCode, resultCode, data);

dans la onActivityResult l'activité parent pour le faire fonctionner.

(J'ai adapté cette réponse de la réponse de @ Clevester.)




J'ai également rencontré ce problème dans un fragment. Et j'ai appelé startActivityForResult dans un DialogFragment .

Mais maintenant ce problème a été résolu:
FragmentClassname.this.startActivityForResult .




Comme Ollie C l'a mentionné, il existe un bogue actif pour la bibliothèque de support qui utilise les valeurs renvoyées à onActivityResult lorsque vous utilisez des fragments imbriqués. Je viens de frapper :-(.

Voir code.google.com/p/android/issues/detail?id=15394 .




Si le problème ci-dessus est rencontré lors de la connexion Facebook, vous pouvez utiliser le code ci-dessous dans une activité parente de votre fragment comme:

Fragment fragment = getFragmentManager().findFragmentById(android.R.id.tabcontent);
fragment.onActivityResult(requestCode, resultCode, data);

Ou:

Fragment fragment = getFragmentManager().findFragmentById("fragment id here");
fragment.onActivityResult(requestCode, resultCode, data);

Et ajoutez l'appel ci-dessous dans votre fragment ...

callbackManager.onActivityResult(requestCode, resultCode, data);



Si vous utilisez des fragments imbriqués, cela fonctionne également:

getParentFragment().startActivityForResult(intent, RequestCode);

En plus de cela, vous devez appeler super.onActivityResult partir de l'activité parente et remplir la méthode onActivityResult du fragment.




Je viens de faire une méthode de contournement:

public static Fragment _tempFragment = null;
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(_tempFragment != null)
        _tempFragment.onActivityResult(requestCode, resultCode, data);
}

Dans votre fragment, avant startActivityResult, définissez

MainActivity._tempFragment = this;

Après onActivityResult <- in Fragment

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

     // Do your job
     {

     }
     MainActivity._tempFragment = null;
}



La plupart de ces réponses n'arrêtent pas de dire que vous devez appeler super.onActivityResult(...) dans votre Activity hôte pour votre Fragment . Mais cela ne semblait pas fonctionner pour moi.

Ainsi, dans votre Activity hôte, vous devriez appeler vos Fragments onActivityResult(...) place. Voici un exemple.

public class HostActivity extends Activity {

    private MyFragment myFragment;

    protected void onActivityResult(...) {
        super.onActivityResult(...);
        this.myFragment.onActivityResult(...);
    }
}

À un certain moment dans votre HostActivity vous devrez assigner this.myFragment au Fragment vous utilisez. Ou, utilisez FragmentManager pour obtenir le Fragment au lieu de conserver une référence à celui-ci dans votre HostActivity . Vérifiez également null avant d'essayer d'appeler le this.myFragment.onActivityResult(...); .




public class takeimage extends Fragment {

    private Uri mImageCaptureUri;
    private static final int PICK_FROM_CAMERA = 1;
    private static final int PICK_FROM_FILE = 2;
    private String mPath;
    private ImageView mImageView;
    Bitmap bitmap = null;
    View view;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.activity_send_image, container, false);
        final String[] items = new String[] { "From Camera", "From SD Card" };
        mImageView = (ImageView)view.findViewById(R.id.iv_pic);
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.select_dialog_item, items);
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setTitle("Select Image");

        builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int item) {
                if (item == 0) {
                    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                    File file = new File(Environment.getExternalStorageDirectory(), "tmp_avatar_"
                        + String.valueOf(System.currentTimeMillis())
                        + ".jpg");
                    mImageCaptureUri = Uri.fromFile(file);

                    try {
                        intent.putExtra(
                            android.provider.MediaStore.EXTRA_OUTPUT,
                            mImageCaptureUri);
                        intent.putExtra("return-data", true);

                        getActivity().startActivityForResult(intent,
                            PICK_FROM_CAMERA);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    dialog.cancel();
                } else {
                    Intent intent = new Intent();

                    intent.setType("image/*");
                    intent.setAction(Intent.ACTION_GET_CONTENT);

                    getActivity().startActivityForResult(
                        Intent.createChooser(intent,
                            "Complete action using"), PICK_FROM_FILE);
                }
            }
        });
        final AlertDialog dialog = builder.create();

        Button show = (Button) view.findViewById(R.id.btn_choose);
        show.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // Switch the tab content to display the list view.
                dialog.show();
            }
        });

    return view;
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {

        if (resultCode != Activity.RESULT_OK)
            return;

        if (requestCode == PICK_FROM_FILE) {
            mImageCaptureUri = data.getData();
            // mPath = getRealPathFromURI(mImageCaptureUri); //from Gallery

            if (mPath == null)
                mPath = mImageCaptureUri.getPath(); // from File Manager

            if (mPath != null)
                bitmap = BitmapFactory.decodeFile(mPath);
        } else {
            mPath = mImageCaptureUri.getPath();
            bitmap = BitmapFactory.decodeFile(mPath);
        }
        mImageView.setImageBitmap(bitmap);  
    }

    public String getRealPathFromURI(Uri contentUri) {
        String [] proj = {MediaStore.Images.Media.DATA};
        Cursor cursor = managedQuery(contentUri, proj, null, null,null);

        if (cursor == null) return null;

        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        cursor.moveToFirst();
        return cursor.getString(column_index);
    }
} 



Votre code a un fragment imbriqué. L'appel de super.onActivityForResult ne fonctionne pas

Vous ne voulez pas modifier toutes les activités à partir desquelles votre fragment peut être appelé et / ou contourner chaque fragment de la chaîne de fragments.

Voici l'une des nombreuses solutions de travail. créez un fragment à la volée et reliez-le directement à l'activité avec le gestionnaire de fragment de support. Appelez ensuite startActivityForResult à partir du fragment nouvellement créé.

private void get_UserEmail() {

    if (view == null) {
        return;
    }
    ((TextView) view.findViewById(R.id.tvApplicationUserName))
            .setText("Searching device for user accounts...");

    final FragmentManager fragManager = getActivity().getSupportFragmentManager();

    Fragment f = new Fragment() {
        @Override
        public void onAttach(Activity activity) {
            super.onAttach(activity);
            startActivityForResult(AccountPicker.newChooseAccountIntent(null, null,
                    new String[]{"com.google"}, false, null, null, null, null), REQUEST_CODE_PICK_ACCOUNT);
        }

        @Override
        public void onActivityResult(int requestCode, int resultCode,
                                     Intent data) {
            if (requestCode == REQUEST_CODE_PICK_ACCOUNT) {
                String mEmail = "";
                if (resultCode == Activity.RESULT_OK) {
                    if (data.hasExtra(AccountManager.KEY_ACCOUNT_NAME)) {
                        mEmail = data
                                .getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
                    }
                }
                if (mActivity != null) {
                    GoPreferences.putString(mActivity, SettingApplication.USER_EMAIL, mEmail);
                }
                doUser();
            }
            super.onActivityResult(requestCode, resultCode, data);
            fragManager.beginTransaction().remove(this).commit();
        }
    };
    FragmentTransaction fragmentTransaction = fragManager
            .beginTransaction();
    fragmentTransaction.add(f, "xx" + REQUEST_CODE_PICK_ACCOUNT);
    fragmentTransaction.commit();
}



POUR LES FRAGMENTS NESTED (par exemple, lors de l'utilisation d'un ViewPager)

Dans votre activité principale:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
}

Dans votre fragment principal de niveau supérieur (fragment ViewPager):

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    YourFragment frag = (YourFragment) getChildFragmentManager().getFragments().get(viewPager.getCurrentItem());
    frag.yourMethod(data);  // Method for callback in YourFragment
    super.onActivityResult(requestCode, resultCode, data);
}

Dans YourFragment (fragment imbriqué):

public void yourMethod(Intent data){
    // Do whatever you want with your data
}



POUR DE NOMBREUX FRAGMENTS (par exemple, lors de l'utilisation d'un ViewPager dans un fragment)

Dans votre activité principale :

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
}

Dans votre fragment:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    for (Fragment fragment : getChildFragmentManager().getFragments()) {
        fragment.onActivityResult(requestCode, resultCode, data);
    }
}

Dans votre fragment imbriqué

Appelez l'activité

getParentFragment().startActivityForResult(intent, uniqueInstanceInt);

uniqueInstanceInt - remplacez-le par un int unique parmi les fragments imbriqués pour éviter qu'un autre fragment traite la réponse.

Recevoir une réponse

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == uniqueInstanceInt ) {
        // TODO your code
    }
}

Attention

Un nombre entre 0 et 65536 doit être utilisé dans uniqueInstanceInt pour l'erreur éviter "Ne peut utiliser que 16 bits inférieurs pour requestCode".




Related