onActivityResult no se llama en Fragment

La actividad que aloja este fragmento tiene su onActivityResult llamado cuando la actividad de la cámara retorna.

Mi fragmento inicia una actividad para obtener un resultado con el bash enviado para que la cámara tome una fotografía. La aplicación de imagen se carga bien, toma una foto y regresa. onActivityResult embargo, el onActivityResult nunca se golpea. Establecí puntos de interrupción, pero no se activó nada. ¿Puede un fragmento tener onActivityResult ? Creo que sí, ya que es una función provista. ¿Por qué no se activa esto?

 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); } } 

La actividad de alojamiento anula onActivityResult() , pero no realizó una llamada a super.onActivityResult() para códigos de resultado no controlados. Aparentemente, aunque el fragmento es el que hace la llamada a startActivityForResult() , la actividad tiene la primera oportunidad de manejar el resultado. Esto tiene sentido cuando se considera la modularidad de los fragmentos. Una vez que implementé super.onActivityResult() para todos los resultados no controlados, el fragmento tuvo la oportunidad de manejar el resultado.

Y también de la respuesta @siqing:

Para obtener el resultado en su fragmento, asegúrese de llamar a startActivityForResult(intent,111); en lugar de getActivity().startActivityForResult(intent,111); dentro de tu fragmento

Creo que getActivity().startActivityForResult(intent,111); . Debería llamar a startActivityForResult(intent,111); .

Opción 1:

Si está llamando a startActivityForResult() desde el fragmento, debe llamar a startActivityForResult() , no getActivity().startActivityForResult() , ya que dará como resultado el fragmento onActivityResult ().

Si no está seguro de dónde está llamando en startActivityForResult() y cómo va a llamar a los métodos.

Opcion 2:

Dado que Activity obtiene el resultado de onActivityResult() , deberá anular la actividad en onActivityResult() y llamar a super.onActivityResult() para propagar al fragmento respectivo para códigos de resultados no controlados o para todos.

Si las dos opciones anteriores no funcionan, consulte la opción 3, ya que definitivamente funcionará.

Opción 3:

Una llamada explícita desde el fragmento a la función onActivityResult es la siguiente.

En la clase de actividad principal, anule el método onActivityResult () e incluso anule el mismo en la clase Fragment y llame como el siguiente código.

En la clase de padres:

 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.dualPane); fragment.onActivityResult(requestCode, resultCode, data); } 

En la clase de niños:

 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // In fragment class callback } 

Estoy teniendo el mismo problema con ChildFragmentManager . El administrador no pasará el resultado al fragmento nested, tienes que hacerlo manualmente en tu fragmento 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); } } 

En caso de que no conozca fragmentos en su actividad, solo enumere todos y envíe los argumentos del resultado de la actividad:

 // 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); } } 

Publicación original.

FragmentActivity reemplaza requestCode por uno modificado. Después de eso, cuando se onActivityResult() , FragmentActivity analiza los 16 bits más altos y restaura el índice del Fragment original. Mira este esquema:

Ingrese la descripción de la imagen aquí

Si tiene algunos fragmentos en el nivel raíz, no hay problemas. Pero si tiene fragmentos nesteds , por ejemplo, Fragment con algunas tabs dentro de ViewPager , tiene garantizado que se encontrará con un problema (o ya lo enfrentó).

Porque solo un índice está almacenado dentro de requestCode . Ese es el índice de Fragment dentro de su FragmentManager . Cuando estamos utilizando fragmentos nesteds, hay Child FragmentManager s, que tienen su propia lista de Fragmentos. Por lo tanto, es necesario guardar toda la cadena de índices, comenzando desde root FragmentManager .

Ingrese la descripción de la imagen aquí

¿Cómo resolvemos este problema? Hay una solución de solución común en esta publicación .

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

Este es uno de los problemas más populares. Podemos encontrar muchos hilos con respecto a este tema. Pero ninguno de ellos es útil para MÍ.

Así que he resuelto este problema usando esta solución.

Primero, comprendamos por qué sucede esto.

Podemos llamar a startActivityForResult directamente desde Fragment, pero en realidad todos los mecánicos están manejados por Activity.

Una vez que llame a startActivityForResult desde un Fragment, requestCode se cambiará para adjuntar la identidad de Fragment al código. Eso permitirá que Activity pueda rastrear quién envía esta solicitud una vez que se recibe el resultado.

Una vez que se haya navegado hacia atrás la actividad, el resultado se enviará a ActivityActivityResult con el requestCode modificado que se decodificará a la identidad de requestCode + Fragment original. Después de eso, Activity enviará el Resultado de la actividad a ese Fragmento a través de ActivityResult. Y todo está hecho.

El problema es:

La actividad podría enviar el resultado solo al Fragmento que se ha adjuntado directamente a la Actividad pero no al nested. Esa es la razón por la cual onActivityResult del fragmento nested nunca se habría llamado sin importar qué.

Solución:

1) Comience con intención en su Fragmento por el siguiente código:

  /** Pass your fragment reference **/ frag.startActivityForResult(intent, REQUEST_CODE); // REQUEST_CODE = 12345 

2) Ahora en su anulación de actividad principal ** onActivityResult() : **

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

Tienes que llamar esto a la actividad de los padres para que funcione.

3) En tu llamada de fragmento:

 @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == Activity.RESULT_OK) { } } 

Eso es. Con esta solución, podría aplicarse a cualquier fragmento individual, ya sea nested o no. Y sí, ¡también cubre todo el caso! Además, los códigos también son agradables y limpios.

PARA MUCHOS FRAGMENTOS NESTADOS (por ejemplo, cuando se usa un ViewPager en un fragmento)

En tu actividad principal :

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

En tu fragmento:

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

En tu fragmento nested

Actividad de llamada

 getParentFragment().startActivityForResult(intent, uniqueInstanceInt); 

uniqueInstanceInt : reemplácelo con un int que sea único entre los fragmentos nesteds para evitar que otro fragmento trate la respuesta.

Recibir respuesta

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

Atención

Se debe usar un número entre 0 y 65536 en uniqueInstanceInt para evitar el error “Solo se pueden usar 16 bits inferiores para requestCode”.

Puedo agregar dos consejos si alguien todavía no puede hacerlo. En el archivo Manifest.xml, asegúrese de que la actividad de alojamiento no finalizó cuando la callback y la actividad que se inicia tienen el modo de inicio de serie. Ver detalles de la siguiente manera:

Para la actividad de Hosting, establezca la propiedad sin historial como falsa si tiene

 android:noHistory="false" 

Para que la actividad se inicie, configure el modo de lanzamiento como estándar si tiene

 android:launchMode="standard" 

También conocí este problema en un Fragmento. Y llamé a startActivityForResult en un DialogFragment .

Pero ahora este problema se ha resuelto:
FragmentClassname.this.startActivityForResult .

Solución 1:

Llame a startActivityForResult(intent, REQUEST_CODE); en lugar de getActivity().startActivityForResult(intent, REQUEST_CODE); .

Solución 2:

Cuando startActivityForResult(intent, REQUEST_CODE); se llama activityActivityResult onActivityResult(requestCode,resultcode,intent) se invoca, y luego puede invocar fragments onActivityResult() desde aquí, pasando requestCode, resultCode and intent .

También estaba enfrentando el mismo problema una vez que cambié este bloque de código fuera de un Fragmento a una Clase de Utilidad , con parentActivity pasado como argumento ,

 Intent intent = new Intent(parentActivity, CameraCaptureActivity.class); parentActivity.startActivityForResult(intent,requestCode); 

Entonces no estaba obteniendo ningún valor en el método onActivityResult de ese Fragment . Luego, cambié el argumento a Fragment , por lo que la definición revisada del método parecía,

 Intent intent = new Intent(fragment.getContext(), CameraCaptureActivity.class); fragment.startActivityForResult(intent,requestCode); 

Después de eso, pude obtener valor en onActivityResult on the Fragment

Dentro de tu fragmento, llama

 this.startActivityForResult(intent, REQUEST_CODE); 

donde this se refiere al fragmento. De lo contrario, haz lo que dijo @Clevester:

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

También tuve que llamar

 super.onActivityResult(requestCode, resultCode, data); 

en la actividad de padre onActivityResult para que funcione.

(He adaptado esta respuesta de la respuesta de @ Clevester).

En mi caso, fue un error de Android ( http://technet.weblineindia.com/mobile/onactivityresult-not-getting-called-innes-fragments-android/ ), si usas FragmentActivity compatible, debes usar getSupportFragmentManager en getSupportFragmentManager lugar de getChildFragmentManager :

 List fragments = getSupportFragmentManager().getFragments(); if (fragments != null) { for (Fragment fragment : fragments) { if(fragment instanceof UserProfileFragment) { fragment.onActivityResult(requestCode, resultCode, data); } } } 

En breve,

En fragmento, declara Fragment fragment = this ;

después de eso use fragment.startActivityForResult .

El resultado volverá en activityResult.

PARA FRAGMENTOS ANIDOS (por ejemplo, cuando se usa un ViewPager)

En tu actividad principal:

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

En su fragmento principal de nivel superior (fragmento de 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); } 

En YourFragment (fragmento nested):

 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 adapter = new ArrayAdapter(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); } } 
  1. Simplemente puede anular BaseActivity onActivityResult en el fragmento baseActivity.startActivityForResult .

  2. En BaseActivity, agregue la interfaz y anule 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); } 
  3. On Fragment implementa 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(); } } 

Esta solución alternativa hará el truco.

Si el problema anterior se enfrenta al inicio de sesión de Facebook, entonces puede usar el siguiente código en una actividad principal de su fragmento como:

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

O:

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

Y agrega la siguiente llamada en tu fragmento …

 callbackManager.onActivityResult(requestCode, resultCode, data); 

La mayoría de estas respuestas siguen diciendo que tienes que llamar a super.onActivityResult(...) en tu Activity host para tu Fragment . Pero eso no pareció funcionar para mí.

Por lo tanto, en su Activity host debería llamar a sus Fragments onActivityResult(...) lugar. Aquí hay un ejemplo.

 public class HostActivity extends Activity { private MyFragment myFragment; protected void onActivityResult(...) { super.onActivityResult(...); this.myFragment.onActivityResult(...); } } 

En algún momento de su HostActivity tendrá que asignarle esto. this.myFragment the Fragment que está usando. O bien, use FragmentManager para obtener el Fragment lugar de mantener una referencia en su HostActivity . Además, verifique null antes de intentar llamar a this.myFragment.onActivityResult(...); .

Una de las formas más simples es comenzar una actividad desde tu fragmento.

 startActivity(ActivityName); 

Luego, agregue que llame a startActivityForResult(intent,"1"); de tu Actividad y agrega el onActivityResult de actividad en tu actividad

 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. } 

Como lo mencionó Ollie C, hay un error activo para la biblioteca de soporte que usa los valores devueltos en onActivityResult cuando usa fragmentos nesteds. Acabo de golpearlo :-(.

Ver Fragment.onActivityResult no llamado when requestCode! = 0 .

Tengo una fuerte sospecha de que todas las respuestas aquí no son más que hacks. Los probé a todos y a muchos otros, pero sin una conclusión confiable, ya que siempre hay algún tipo de problema estúpido. Yo, por mi parte, no puedo confiar en resultados inconsistentes. Si observa la documentación oficial de la API de Android para Fragmentos, verá que Google establece claramente lo siguiente:

Llame a startActivityForResult (Intent, int) desde la actividad que contiene el fragmento.

Ver: Android Fragment API

Por lo tanto, parecería que el enfoque más correcto y confiable sería llamar a startActivityForResult () desde la actividad de alojamiento y también manejar el ResultActivityResult resultante () desde allí.

Tu código tiene un fragmento nested. Llamar a super.onActivityForResult no funciona

No desea modificar todas las actividades de las que se puede invocar el fragmento y hacer un repaso para llamar a cada fragmento de la cadena de fragmentos.

Aquí hay una de muchas soluciones de trabajo. cree un fragmento sobre la marcha y conéctelo directamente a la actividad con el administrador de fragmentos de soporte. Luego, llame a startActivityForResult desde el fragmento recién creado.

 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(); } 

Mi problema fue con la actividad de Host. Lo encontré con un conjunto de android:launchMode="standard" Lo android:launchMode="standard" temporalmente y funciona.

Acabo de hacer un método de solución:

 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); } 

En tu Fragmento, antes de startActivityResult, establece

 MainActivity._tempFragment = this; 

Después de onActivityResult <- in Fragment

 @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // Do your job { } MainActivity._tempFragment = null; } 

Simplemente use el siguiente código para el fragmento.

 @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 llamará sin llamar a su padre.

Un punto que nadie mention para asegurarse de que el modo de inicio de su actividad de host no debe establecerse en singleInstance o singleTask .

onActivityResult no funcionará si su modo de inicio está configurado en SingleInstance o SingleTask. o llamas a tu actividad usando estos IntentFilters

standard modo de inicio standard o singleTop funcionará bien.

Si hay problemas con el método en onActivityResult que está dentro de la clase de fragmento, y desea actualizar algo que también está dentro de la clase de fragmento, use:

 @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 paird devices. this.arrayDevice = new ArrayAdapter(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); } 

Simplemente agregue la this.variable como se muestra en el código anterior. De lo contrario, se llamará al método dentro de la actividad primaria y la variable no se actualizará de la instancia actual.

También lo probé colocando este bloque de código en MainActivity , reemplazándolo con la clase HomeFragment y teniendo las variables estáticas. Obtuve resultados como esperaba.

Por lo tanto, si desea que la clase de fragmento tenga su propia implementación de onActivityResult , el ejemplo de código anterior es la respuesta.

Si está utilizando fragmentos nesteds, esto también funciona:

 getParentFragment().startActivityForResult(intent, RequestCode); 

Además de esto, debe llamar a super.onActivityResult de la actividad principal y completar el método onActivityResult del fragmento.