onActivityResult n'est pas appelé dans Fragment
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 de l'image charge bien, prend une image, et retourne. Le onActivityResult
n'est cependant jamais touché. J'ai mis des points d'arrêt, mais rien n'est déclenchée. Un fragment peut-il avoir onActivityResult
? Je pense donc, puisque c'est une fonction fournie. Pourquoi n'est-ce pas être déclenchée?
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);
}
}
30 réponses
l'activité d'hébergement l'emporte sur onActivityResult()
, mais elle n'a pas appelé super.onActivityResult()
pour les codes de résultat non contrôlés. Apparemment, même si le fragment est celui qui fait l'appel startActivityForResult()
, l'activité obtient le premier coup à manipuler le résultat. Cela a du sens quand on considère la modularité des fragments. Une fois que j'ai implémenté super.onActivityResult()
pour tous les résultats non contrôlés, le fragment a eu une chance de gérer le résultat.
et aussi de la réponse de @siqing:
pour obtenir le résultat dans votre fragment, n'oubliez pas d'appeler startActivityForResult(intent,111);
au lieu de getActivity().startActivityForResult(intent,111);
à l'intérieur de votre fragment.
je pense que vous avez appelé getActivity().startActivityForResult(intent,111);
. Vous devriez appeler startActivityForResult(intent,111);
.
Option 1:
si vous appelez startActivityForResult()
à partir du fragment , vous devez appeler startActivityForResult()
, et non getActivity().startActivityForResult()
, car il en résultera un fragment onActivityResult().
si vous ne savez pas où vous appelez startActivityForResult()
et comment vous appellerez les méthodes.
Option 2:
depuis que L'activité le résultat de onActivityResult()
, vous aurez besoin de surcharger l'activité onActivityResult()
et appeler super.onActivityResult()
pour se propager au fragment respectif pour les codes de résultats non manipulés ou pour tous.
si deux options ci-dessus ne fonctionnent pas, référez-vous alors à l'option 3 car elle fonctionnera certainement.
Option 3:
un appel explicite de fragment à la fonction onActivityResult est comme suivre.
dans la classe d'activité parent, outrepasser la méthode onActivityResult() et même outrepasser la même chose dans la classe Fragment et appeler comme le code suivant.
dans la classe mère:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.dualPane);
fragment.onActivityResult(requestCode, resultCode, data);
}
dans la classe des enfants:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// In fragment class callback
}
j'ai le même problème avec le ChildFragmentManager
. Le gestionnaire ne passera 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);
}
}
dans le cas où vous ne connaissez pas les fragments dans votre activité, énumérez-les tous et envoyez les arguments de résultat de l'activité:
// In your activity
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
for (Fragment fragment : getSupportFragmentManager().getFragments()) {
fragment.onActivityResult(requestCode, resultCode, data);
}
}
FragmentActivity
remplace requestCode
par une version modifiée. Après cela, quand onActivityResult()
sera invoqué, FragmentActivity
analyse les 16 bits supérieurs et restaure l'index du Fragment original. Regardez ce schéma:
si vous avez quelques fragments au niveau de la racine, il n'y a aucun problème. Mais si vous avez imbriqué fragments , par exemple Fragment
avec quelques onglets à l'intérieur ViewPager
, vous garanti fera face à un problème (ou l'a déjà fait face).
parce que un seul index est stocké à l'intérieur de requestCode
. C'est l'index de Fragment
à l'intérieur de son FragmentManager
. Lorsque nous utilisons des fragments imbriqués, il y a des enfants FragmentManager
s, qui ont leur propre liste de Fragments. Donc, il est nécessaire de sauver l'ensemble chaîne d'indices, à partir de la racine FragmentManager
.
comment résoudre ce problème? il y a une solution de contournement commune dans cet article .
C'est l'un des sujets les plus populaires. Nous pouvons trouver beaucoup de fil concernant cette question. Mais aucun d'eux n'est utile pour MOI.
Donc, j'ai résolu ce problème en utilisant cette solution.
commençons par comprendre pourquoi cela se produit.
nous pouvons appeler startActivityForResult
directement à partir de Fragment mais en fait mécanique derrière sont tous manipulés par activité.
une fois que vous appelez startActivityForResult
à partir d'un Fragment, requestCode sera changé pour attacher l'identité du Fragment au code. Cela permettra à Activity de retracer l'expéditeur de cette demande une fois le résultat reçu.
une fois L'activité repérée, le résultat sera envoyé à onActivityResult de L'activité avec le requestCode modifié qui sera décodé à l'identité originale du requestCode + Fragment. Après cela, L'activité enverra le résultat de l'activité à ce Fragment par l'intermédiaire d'onActivityResult. Et tout est fait.
le problème est:
L'activiténe peut envoyer le résultat qu'au Fragment qui a été attaché directement à l'activité mais pas au Fragment imbriqué. C'est la raison pour laquelle onActivityResult du fragment imbriqué n'a jamais été appelé quoi qu'il arrive.
Solution:
1) Démarrez L'intention dans votre Fragment par le code ci-dessous:
/** Pass your fragment reference **/
frag.startActivityForResult(intent, REQUEST_CODE); // REQUEST_CODE = 12345
2) maintenant dans votre activité Parent outrepasser ** onActivityResult()
:**
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
Vous devez appeler cette activité parent pour le faire fonctionner.
3) dans votre appel de fragment:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
}
}
C'est ça. Avec cette solution, il pourrait être appliqué pour n'importe quel fragment simple qu'il soit emboîté ou non. Et oui, il couvre tous les cas! De plus, les codes sont également agréables et propres.
pour de nombreux FRAGMENTS imbriqués (par exemple, en utilisant 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é
activité D'appel
getParentFragment().startActivityForResult(intent, uniqueInstanceInt);
uniqueInstanceInt - le remplacer par un int qui est unique parmi les fragments imbriqués pour empêcher un autre fragment traiter la réponse.
Recevoir de 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 for error avoid"ne peut utiliser que 16 bits inférieurs pour requestCode".
je peux ajouter deux conseils si quelqu'un ne peut toujours pas le faire. Dans Le Manifeste.fichier xml, assurez-vous que l'activité d'hébergement ne s'est pas terminée lors du rappel et que l'activité à commencer a le mode de lancement standard. Voir les détails ci-dessous:
Pour l'Hébergement de l'activité, de définir le pas de l'histoire de la propriété false si ont
android:noHistory="false"
pour que L'activité soit lancée, définissez le mode de lancement standard si vous avez
android:launchMode="standard"
j'ai aussi 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
.
j'ai également été confronté au même problème une fois que j'ai déplacé ce bloc de code à l'extérieur d'un Fragment à une Classe D'utilité , avec parentActivity
passé comme argument ,
Intent intent = new Intent(parentActivity, CameraCaptureActivity.class);
parentActivity.startActivityForResult(intent,requestCode);
alors je n'obtenais aucune valeur dans onActivityResult
méthode de ce Fragment ,
Par la suite , j'ai changé le argument en Fragment , de sorte que le révision de la définition de la méthode ressemblait,
Intent intent = new Intent(fragment.getContext(), CameraCaptureActivity.class);
fragment.startActivityForResult(intent,requestCode);
après cela, j'ai pu obtenir la valeur dans onActivityResult
sur le Fragment
Solution 1:
appeler startActivityForResult(intent, REQUEST_CODE);
au lieu de getActivity().startActivityForResult(intent, REQUEST_CODE);
.
Solution 2:
quand startActivityForResult(intent, REQUEST_CODE);
est appelé onActivityResult(requestCode,resultcode,intent)
de l'activité est invoquée, et alors vous pouvez appeler fragments onActivityResult()
d'ici, en passant le requestCode, resultCode and intent
.
dans votre fragment, appelez
this.startActivityForResult(intent, REQUEST_CODE);
où this
se réfère au fragment. Sinon faites comme @Clevester a dit:
Fragment fragment = this;
....
fragment.startActivityForResult(intent, REQUEST_CODE);
j'ai aussi dû appeler
super.onActivityResult(requestCode, resultCode, data);
dans l'activité mère onActivityResult
pour la faire fonctionner.
(j'ai adapté cette réponse de la réponse de @Clevester.)
dans mon cas c'était un bug Android ( http://technet.weblineindia.com/mobile/onactivityresult-not-getting-called-in-nested-fragments-android / ), si vous utilisez FragmentActivity
vous devez utiliser getSupportFragmentManager
au lieu de getChildFragmentManager
:
List<Fragment> fragments = getSupportFragmentManager().getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
if(fragment instanceof UserProfileFragment) {
fragment.onActivityResult(requestCode, resultCode, data);
}
}
}
en bref,
en fragment, déclarer Fragment fragment = this
;
après fragment.startActivityForResult
.
le résultat reviendra en activityResult.
pour les FRAGMENTS imbriqués (par exemple, lorsqu'on utilise 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);
}
In YourFragment (nested fragment):
public void yourMethod(Intent data){
// Do whatever you want with your data
}
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);
}
}
-
vous pouvez simplement surcharger BaseActivity
onActivityResult
sur fragmentbaseActivity.startActivityForResult
. -
Sur BaseActivity l'interface d'ajout et de remplacer onActivityResult.
private OnBaseActivityResult baseActivityResult; public static final int BASE_RESULT_RCODE = 111; public interface OnBaseActivityResult{ void onBaseActivityResult(int requestCode, int resultCode, Intent data); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(getBaseActivityResult() !=null && requestCode == BASE_RESULT_RCODE){ getBaseActivityResult().onBaseActivityResult(requestCode, resultCode, data); setBaseActivityResult(null); }
-
Sur Fragment met en œuvre
OnBaseActivityResult
@Override public void onBaseActivityResult(int requestCode, int resultCode, Intent data) { Log.d("RQ","OnBaseActivityResult"); if (data != null) { Log.d("RQ","OnBaseActivityResult + Data"); Bundle arguments = data.getExtras(); } }
Cette solution fera l'affaire.
si le problème ci-dessus est confronté à Facebook login alors vous pouvez utiliser le code ci-dessous dans une activité parent 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);
la plupart de ces réponses disent que vous devez appeler super.onActivityResult(...)
dans votre hôte Activity
pour votre Fragment
. Mais ça ne semble pas fonctionner pour moi.
donc, dans votre hôte Activity
vous devriez appeler votre Fragments
onActivityResult(...)
à la place. Ici est un exemple.
public class HostActivity extends Activity {
private MyFragment myFragment;
protected void onActivityResult(...) {
super.onActivityResult(...);
this.myFragment.onActivityResult(...);
}
}
à un moment donné dans votre HostActivity
vous devrez assigner this.myFragment
le Fragment
que vous utilisez. Ou, utilisez le FragmentManager
obtenir le Fragment
au lieu de garder une référence dans votre HostActivity
. En outre, vérifiez null
avant d'essayer d'appeler le this.myFragment.onActivityResult(...);
.
comme Ollie C l'a mentionné, il y a un bug actif pour la bibliothèque de support en utilisant les valeurs retournées à onActivityResult lorsque vous utilisez des fragments imbriqués. Je viens de le frapper :-(.
Voir Fragment.onActivityResult pas appelé quand requestCode != 0 .
je soupçonne fortement que toutes les réponses ici ne sont rien d'autre que des piratages. Je les ai tous essayés et beaucoup d'autres, mais sans aucune conclusion fiable car il y a toujours une sorte de problème stupide. Pour ma part, je ne peut pas compter sur des résultats incohérents. Si vous regardez la documentation officielle de L'API Android pour les Fragments, vous verrez que Google indique clairement ce qui suit:
Appel startActivityForResult(Intent, int) à partir du fragment contenant Activité.
voir: Android Fragment API
ainsi, il semblerait que l'approche la plus correcte et fiable serait effectivement d'appeler startActivityForResult () de l'activité d'hébergement et aussi gérer le résultat onActivityResult () de là.
votre code a un fragment imbriqué. Un appel à super.onActivityForResult ne fonctionne pas
vous ne voulez pas modifier chaque activité à partir de laquelle votre fragment peut être appelé et / ou faire un travail autour de l'appel de chaque fragment dans la chaîne de fragment.
Voici une des nombreuses solutions de travail. créer un fragment à la volée et de fil directement à l'activité avec le soutien fragment de manager. Puis appeler startActivityForResult de la nouvellement créée fragment.
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();
}
mon problème était avec l'activité hôte je l'ai trouvé avec un ensemble android:launchMode="standard"
Je l'ai enlevé temporaire et travail informatique !
un des moyens les plus simples est de démarrer une activité à partir de votre fragment.
startActivity(ActivityName);
Ensuite, ajoutez startActivityForResult(intent,"1");
de votre activité et ajoutez onActivityResult
de votre activité
startActivityForResult(intent,"1");
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.dualPane);
fragment.onActivityResult(requestCode, resultCode, data);
// perform other activity result like fetching from Uris or handling cursors
finish(); // finish the activity will get to back to your fragment.
}
je viens de faire un contournement de la méthode:
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 de commencer activityresult, mettez
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;
}
utilisez Simplement le code ci-dessous pour le fragment.
@Override
public void onOtherButtonClick(ActionSheet actionSheet, int index) {
if (index == 1)
{
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.setType("image/*");
startActivityForResult(Intent.createChooser(intent,
"Select Picture"), 1);
}
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == 1) {
if (requestCode == 1) {
Uri selectedImageUri = data.getData();
//selectedImagePath = getPath(selectedImageUri);
}
}
}
onActivityResult appellera sans appeler son parent.
Un point que personne n'a
mention
assurez-vous que votre Hôte Activité mode de lancement ne doit pas être réglé sursingleInstance
ousingleTask
.
onActivityResult ne fonctionnera pas si votre mode de lancement est configuré pour SingleInstance ou SingleTask. ou vous appelez votre activité en utilisant ces filtres Intent
Le mode de lancement standard
ou singleTop
fonctionnera très bien.
S'il y a un problème avec la méthode onActivityResult
qui est à l'intérieur de la classe fragment, et que vous voulez mettre à jour quelque chose qui est aussi à l'intérieur de la classe fragment, utilisez:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(resultCode == Activity.RESULT_OK)
{
// If the user had agreed to enabling Bluetooth,
// populate the ListView with all the paired devices.
this.arrayDevice = new ArrayAdapter<String>(this.getContext(), R.layout.device_item);
for(BluetoothDevice bd : this.btService.btAdapater.getBondedDevices())
{
this.arrayDevice.add(bd.getAddress());
this.btDeviceList.setAdapter(this.arrayDevice);
}
}
super.onActivityResult(requestCode, resultCode, data);
}
il suffit d'ajouter le this.variable
comme indiqué dans le code ci-dessus. Sinon, la méthode sera appelée dans l'activité mère et la variable ne sera pas mise à jour de l'instance courante.
je l'ai testé aussi en mettant ce bloc de code dans le MainActivity
, remplacer this
par HomeFragment
et avoir les variables statiques. J'ai eu des résultats comme je m'y attendais.
donc si vous voulez que la classe de fragments ait sa propre implémentation de onActivityResult
, l'exemple de code ci-dessus est la réponse.
si vous utilisez des fragments imbriqués, cela fonctionne aussi:
getParentFragment().startActivityForResult(intent, RequestCode);
en plus de cela, vous devez appeler super.onActivityResult
de l'activité parent et remplir la méthode onActivityResult
du fragment.