Actualmente tengo un fragmento en una superposición. Esto es para iniciar sesión en el servicio. En la aplicación del teléfono, cada uno de los pasos que quiero mostrar en la superposición son sus propias pantallas y actividades. Hay tres partes del proceso de inicio de sesión y cada una tenía su propia actividad a la que se llamaba con startActivityForResult ().
Ahora quiero hacer lo mismo usando fragmentos y una superposición. La superposición mostrará un fragmento correspondiente a cada actividad. El problema es que estos fragmentos están alojados en una actividad de la API Honeycomb. Puedo hacer que el primer fragmento funcione, pero luego necesito startActivityForResult (), lo cual no es posible. ¿Hay algo en la línea de startFragmentForResult () donde pueda iniciar un nuevo fragmento y cuando haya terminado, devolver un resultado al fragmento anterior?
fuente
onActivityResult
método del fragmento principal si así lo desea.Si lo desea, existen algunos métodos de comunicación entre Fragmentos,
setTargetFragment(Fragment fragment, int requestCode) getTargetFragment() getTargetRequestCode()
Puede devolver la llamada utilizando estos.
Fragment invoker = getTargetFragment(); if(invoker != null) { invoker.callPublicMethod(); }
fuente
setTargetFragment()
.setTargetFragment
actualmente está desaprobado. VeasetResultListener
en stackoverflow.com/a/61881149/2914140 aquí.Simplemente podemos compartir el mismo ViewModel entre fragmentos
SharedViewModel
import android.arch.lifecycle.MutableLiveData import android.arch.lifecycle.ViewModel class SharedViewModel : ViewModel() { val stringData: MutableLiveData<String> by lazy { MutableLiveData<String>() } }
FirstFragment
import android.arch.lifecycle.Observer import android.os.Bundle import android.arch.lifecycle.ViewModelProviders import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup class FirstFragment : Fragment() { private lateinit var sharedViewModel: SharedViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) activity?.run { sharedViewModel = ViewModelProviders.of(activity).get(SharedViewModel::class.java) } } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_first, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) sharedViewModel.stringData.observe(this, Observer { dateString -> // get the changed String }) } }
SecondFragment
import android.arch.lifecycle.ViewModelProviders import android.os.Bundle import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGrou class SecondFragment : Fragment() { private lateinit var sharedViewModel: SharedViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) activity?.run { sharedViewModel = ViewModelProviders.of(activity).get(SharedViewModel::class.java) } } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_first, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) changeString() } private fun changeString() { sharedViewModel.stringData.value = "Test" } }
fuente
Recientemente, Google acaba de agregar una nueva capacidad
FragmentManager
que hizoFragmentManager
que pueda actuar como un almacén central para los resultados de los fragmentos. Podemos pasar los datos de un fragmento a otro fácilmente.Fragmento inicial.
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Use the Kotlin extension in the fragment-ktx artifact setResultListener("requestKey") { key, bundle -> // We use a String here, but any type that can be put in a Bundle is supported val result = bundle.getString("bundleKey") // Do something with the result... } }
Un fragmento de que queremos el resultado de vuelta.
button.setOnClickListener { val result = "result" // Use the Kotlin extension in the fragment-ktx artifact setResult("requestKey", bundleOf("bundleKey" to result)) }
El fragmento se tomó de los documentos oficiales de Google. https://developer.android.com/training/basics/fragments/pass-data-between#kotlin
A la fecha de redacción de esta respuesta, esta característica aún se encuentra en
alpha
estado. Puedes probarlo usando esta dependencia.androidx.fragment:fragment:1.3.0-alpha05
fuente
Mis 2 centavos.
Cambio entre fragmentos intercambiando un fragmento antiguo por uno nuevo usando ocultar y mostrar / agregar (existente / nuevo). Entonces, esta respuesta es para desarrolladores que usan fragmentos como yo.
Entonces uso el
onHiddenChanged
método para saber que el fragmento antiguo se cambió del nuevo. Consulte el código a continuación.Antes de dejar el nuevo fragmento, establezco un resultado en un parámetro global para ser consultado por el fragmento antiguo. Esta es una solución muy ingenua.
@Override public void onHiddenChanged(boolean hidden) { super.onHiddenChanged(hidden); if (hidden) return; Result result = Result.getAndReset(); if (result == Result.Refresh) { refresh(); } } public enum Result { Refresh; private static Result RESULT; public static void set(Result result) { if (RESULT == Refresh) { // Refresh already requested - no point in setting anything else; return; } RESULT = result; } public static Result getAndReset() { Result result = RESULT; RESULT = null; return result; } }
fuente
getAndReset()
método?onResume()
llama también al primer fragmento cuando se descarta el segundo?En su fragmento puede llamar a getActivity (). Esto le dará acceso a la actividad que creó el fragmento. Desde allí, puede llamar a su método de personalización para establecer los valores o pasar los valores.
fuente
Hay una biblioteca de Android, FlowR, que le permite iniciar fragmentos para obtener resultados.
Comenzar un fragmento para obtener un resultado.
Flowr.open(RequestFragment.class) .displayFragmentForResults(getFragmentId(), REQUEST_CODE);
El manejo da como resultado el fragmento de llamada.
@Override protected void onFragmentResults(int requestCode, int resultCode, Bundle data) { super.onFragmentResults(requestCode, resultCode, data); if (requestCode == REQUEST_CODE) { if (resultCode == Activity.RESULT_OK) { demoTextView.setText("Result OK"); } else { demoTextView.setText("Result CANCELED"); } } }
Estableciendo el resultado en el Fragmento.
Flowr.closeWithResults(getResultsResponse(resultCode, resultData));
fuente
Una solución que utiliza interfaces (y Kotlin). La idea central es definir una interfaz de devolución de llamada, implementarla en su actividad y luego llamarla desde su fragmento.
Primero, crea una interfaz
ActionHandler
:interface ActionHandler { fun handleAction(actionCode: String, result: Int) }
A continuación, llame a esto de su hijo (en este caso, su fragmento):
companion object { const val FRAGMENT_A_CLOSED = "com.example.fragment_a_closed" } fun closeFragment() { try { (activity as ActionHandler).handleAction(FRAGMENT_A_CLOSED, 1234) } catch (e: ClassCastException) { Timber.e("Calling activity can't get callback!") } dismiss() }
Finalmente, implemente esto en su padre para recibir la devolución de llamada (en este caso, su Actividad):
class MainActivity: ActionHandler { override fun handleAction(actionCode: String, result: Int) { when { actionCode == FragmentA.FRAGMENT_A_CLOSED -> { doSomething(result) } actionCode == FragmentB.FRAGMENT_B_CLOSED -> { doSomethingElse(result) } actionCode == FragmentC.FRAGMENT_C_CLOSED -> { doAnotherThing(result) } } }
fuente
La forma más fácil de devolver datos es mediante setArgument (). Por ejemplo, tiene fragment1 que llama a fragment2 que llama a fragment3, fragment1 -> framgnet2 -> fargment3
En fragment1
public void navigateToFragment2() { if (fragmentManager == null) return; Fragment2 fragment = Fragment2.newInstance(); String tag = "Fragment 2 here"; fragmentManager.beginTransaction() .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) .add(R.id.flContent, fragment, tag) .addToBackStack(null) .commitAllowingStateLoss(); }
En fragment2 llamamos fragment3 como de costumbre
private void navigateToFragment3() { if (fragmentManager == null) return; Fragment3 fragment = new Fragment3(); fragmentManager.beginTransaction() .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) .replace(R.id.flContent, fragment, tag) .addToBackStack(null) .commit(); }
Cuando terminamos nuestra tarea en fragment3 ahora llamamos así:
FragmentManager fragmentManager = getActivity().getSupportFragmentManager(); if (fragmentManager == null) return; fragmentManager.popBackStack(); Bundle bundle = new Bundle(); bundle.putString("bundle_filter", "data"); fragmentManager.findFragmentByTag("Fragment 2 here").setArguments(bundle);
Ahora en el fragment2 podemos llamar fácilmente a los argumentos
@Override public void onResume() { super.onResume(); Bundle rgs = getArguments(); if (args != null) String data = rgs.getString("bundle_filter"); }
fuente
Otra cosa que podría hacer dependiendo de su arquitectura es usar un ViewModel compartido entre los fragmentos. Entonces, en mi caso, FragmentA es un formulario, y FragmentB es una vista de selección de elementos donde el usuario puede buscar y seleccionar un elemento, almacenándolo en ViewModel. Luego, cuando regrese a FragmentA, ¡la información ya está almacenada!
fuente