tutorial studio navegar fragments example entre diferencia desde activity abrir android android-fragments android-activity

studio - fragments android tutorial



onActivityResult no se llama en Fragmento (30)

Un punto que nadie ha mention que asegúrese de que el modo de inicio de la Actividad del Host no se debe configurar en singleInstance o singleTask .

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

standard modo de lanzamiento standard o singleTop funcionará bien.

La actividad que alberga este fragmento tiene su onActivityResult cuando la actividad de la cámara regresa.

Mi fragmento inicia una actividad para obtener un resultado con la intención enviada para que la cámara tome una fotografía. La aplicación de imagen se carga bien, toma una imagen y regresa. El onActivityResult sin embargo nunca se golpea. He establecido puntos de interrupción, pero nada se activa. ¿Puede un fragmento tener onActivityResult ? Yo creo que sí, ya que es una función proporcionada. ¿Por qué no se está activando 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); } }


PARA FRAGMENTOS ANULADOS (por ejemplo, cuando se utiliza 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 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 anidado):

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


  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 hará el truco.


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 <- en Fragmento

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


Como mencionó Ollie C, hay un error activo para la biblioteca de soporte que usa valores devueltos para onActivityResult cuando está usando fragmentos anidados. Acabo de golpearlo :-(.

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


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


Dentro de tu fragmento, llama

this.startActivityForResult(intent, REQUEST_CODE);

Cuando 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 los padres, onActivityResult para que funcione.

(Adapté esta respuesta de la respuesta de @Clevester).


En breve,

En fragmento, declare Fragment fragment = this ;

después de eso use fragment.startActivityForResult .

El resultado volverá en activityResult.


En caso de que no sepa fragmentos en su actividad, simplemente enumérelos todos y envíe los argumentos de los resultados 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); } }


En mi caso, se trata de un error de Android ( http://technet.weblineindia.com/mobile/onactivityresult-not-getting-called-in-nested-fragments-android/ ), si utiliza FragmentActivity compatible, debe usar getSupportFragmentManager en getSupportFragmentManager lugar. de getChildFragmentManager :

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


Este es uno de los temas más populares. Podemos encontrar un montón de hilo con respecto a este problema. Pero ninguno de ellos es útil para MÍ.

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

Primero entendamos por qué esto está sucediendo.

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

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

Una vez que se haya vuelto a navegar la actividad, el resultado se enviará a Activity''s OnActivityResult con el requestCode modificado que se descodificará a requestCode original + identidad del fragmento. Después de eso, la Actividad enviará el Resultado de la Actividad a ese Fragmento a través de onActivityResult. 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 anidado. Esa es la razón por la cual onActivityResult de fragmento anidado nunca se llamaría sin importar qué.

Solución:

1) Inicia la Intención en tu Fragmento por el siguiente código:

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

2) Ahora en su actividad de padres anular ** onActivityResult() : **

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

Tienes que llamar a esto en 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 que esté anidado o no. Y sí, también cubre todo el caso! Además, los códigos también son bonitos y limpios.


Estoy teniendo este mismo problema con ChildFragmentManager . El administrador no pasará el resultado al fragmento anidado, debe hacerlo manualmente en su 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); } }


La actividad de alojamiento anula onActivityResult() , pero no realizó una llamada a super.onActivityResult() para los códigos de resultados no super.onActivityResult() . Aparentemente, aunque el fragmento es el que realiza la llamada startActivityForResult() , la actividad obtiene 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 super.onActivityResult() , el fragmento tuvo una 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.


La mayoría de estas respuestas siguen diciendo que debe llamar a super.onActivityResult(...) en su Activity host para su Fragment . Pero eso no parecía estar funcionando para mí.

Por lo tanto, en su Activity host, debe llamar a su 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 , deberá asignar a this.myFragment el Fragment que está utilizando. O use FragmentManager para obtener el Fragment lugar de mantener una referencia a él en su HostActivity . Además, compruebe si hay un null antes de intentar llamar a this.myFragment.onActivityResult(...); .


Mi problema fue con la actividad del host. Lo encontré con un conjunto de android:launchMode="standard" Lo android:launchMode="standard" temporalmente y funcionó!


PARA MUCHOS FRAGMENTOS ANULADOS (por ejemplo, cuando se utiliza 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 anidado

Actividad de llamada

getParentFragment().startActivityForResult(intent, uniqueInstanceInt);

uniqueInstanceInt : reemplácelo con un int que sea único entre los fragmentos anidados 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

Es necesario utilizar un número entre 0 y 65536 en uniqueInstanceInt para evitar el error "Solo se pueden usar 16 bits más bajos 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 hospedaje no haya finalizado cuando se devuelva la llamada y que la actividad a comenzar tenga el modo de inicio como estándar. Vea los detalles a continuación:

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

android:noHistory="false"

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

android:launchMode="standard"


Si el problema anterior se enfrenta al inicio de sesión de Facebook , puede usar el código siguiente 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 añada la siguiente llamada en su fragmento ...

callbackManager.onActivityResult(requestCode, resultCode, data);


Si está utilizando fragmentos anidados, 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.


Si hay problemas con el método 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 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); }

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

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

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


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.


Solución 1:

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

Solución 2:

When startActivityForResult(intent, REQUEST_CODE); se llama onActivityResult(requestCode,resultcode,intent) la actividad onActivityResult(requestCode,resultcode,intent) se invoca, y luego se pueden llamar fragments onActivityResult() desde aquí, pasando el requestCode, resultCode and intent .


También enfrenté 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 Fragmento . Después, cambié el argumento a Fragmento , por lo que la definición revisada de 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 en el Fragmento


También me encontré con este problema en un fragmento. Y llamé a startActivityForResult en un DialogFragment .

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


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

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

Ver: API de fragmento de Android

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


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

startActivity(ActivityName);

Luego, agregue lo que llama startActivityForResult(intent,"1"); de su actividad y agregue onActivityResult en su 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. }


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 Fragmento original. Mira este esquema:

Si tiene algunos fragmentos en el nivel raíz, no hay problemas. Pero si tiene fragmentos anidados , por ejemplo Fragment con algunas pestañas dentro de ViewPager , garantiza que se enfrentará a un problema (o ya lo enfrentó).

Porque solo un índice se almacena dentro de requestCode . Ese es el índice de Fragment dentro de su FragmentManager . Cuando estamos utilizando fragmentos anidados, hay FragmentManager secundarios, que tienen su propia lista de Fragmentos. Por lo tanto, es necesario guardar toda la cadena de índices, a partir de FragmentManager raíz.

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

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


Opción 1:

Si llama a startActivityForResult() desde el fragmento, debería llamar a startActivityForResult() , no a getActivity().startActivityForResult() , ya que dará como resultado el fragmento onActivityResult ().

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

Opcion 2:

Dado que la Actividad obtiene el resultado de onActivityResult() , deberá anular el onActivityResult() la actividad y llamar a super.onActivityResult() para propagarse al fragmento respectivo para los códigos de resultados no super.onActivityResult() 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 al siguiente código.

En la clase padre:

@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 infantil:

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


Su código tiene un fragmento anidado. Llamar a super.onActivityForResult no funciona

No desea modificar todas las actividades desde las que se puede llamar a su fragmento ni hacer una solución para llamar a cada fragmento en la cadena de fragmentos.

Aquí está una de las 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(); }


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