web-dev-qa-db-fra.com

Existe-t-il une méthode qui fonctionne comme start fragment pour result?

J'ai actuellement un fragment dans une superposition. Ceci est pour vous connecter au service. Dans l'application téléphonique, chacune des étapes que je souhaite afficher dans la superposition correspond à ses propres écrans et activités. Il existe 3 parties du processus de connexion et chacune a sa propre activité appelée startActivityForResult (). 

Maintenant, je veux faire la même chose en utilisant des fragments et une superposition. La superposition montrera un fragment correspondant à chaque activité. Le problème est que ces fragments sont hébergés dans une activité de l'API Honeycomb. Je peux faire fonctionner le premier fragment, mais il me faut ensuite démarrerActivityForResult (), ce qui n'est pas possible. Existe-t-il quelque chose dans le genre de startFragmentForResult () où je puisse lancer un nouveau fragment et le renvoyer ensuite au résultat précédent?

70
CACuzcatlan

Tous les fragments vivent dans les activités. Commencer un fragment pour un résultat n'a pas beaucoup de sens, car l'activité qui le héberge a toujours accès, et inversement. Si le fragment doit transmettre un résultat, il peut accéder à son activité, définir son résultat et le terminer. Dans le cas de permutation de fragments en une seule activité, l’activité est toujours accessible par les deux fragments et tous vos messages transmis peuvent simplement passer à travers l’activité.

Rappelez-vous simplement que vous avez toujours une communication entre un fragment et son activité. Le mécanisme de communication entre les activités commence et se termine avec un résultat. Les activités peuvent ensuite déléguer les informations nécessaires à leurs fragments.

45
LeffelMania

Si vous le souhaitez, il existe des méthodes de communication entre les fragments,

setTargetFragment(Fragment fragment, int requestCode)
getTargetFragment()
getTargetRequestCode()

Vous pouvez rappeler en utilisant ceux-ci. 

Fragment invoker = getTargetFragment();
if(invoker != null) {
    invoker.callPublicMethod();
}
53
nagoya0

Mes 2 centimes.

Je permute entre les fragments en échangeant un ancien fragment avec un nouveau en utilisant les fonctions masquer et afficher/ajouter (existant/nouveau). Donc, cette réponse est pour les développeurs qui utilisent des fragments comme moi.

Ensuite, j'utilise la méthode onHiddenChanged pour savoir que l'ancien fragment a été remplacé par le nouveau. Voir le code ci-dessous.

Avant de quitter le nouveau fragment, j'ai défini un résultat dans un paramètre global à interroger par l'ancien fragment. C'est une solution très naïve.

@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;
    }
}
4
AlikElzin-kilaka

Dans votre fragment, vous pouvez appeler getActivity (). Cela vous donnera accès à l'activité qui a créé le fragment. À partir de là, vous pouvez appeler votre méthode de personnalisation pour définir les valeurs ou pour les transmettre.

1
Summved Jain

Vous pouvez utiliser EventBus . Cela simplifie la communication entre activités, fragments, threads, services, etc. Moins de code, meilleure qualité.

0
KishanSolanki124

Nous pouvons simplement partager le même ViewModel entre fragments 

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(this).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(this).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"
    }

}
0
Levon Petrosyan

Le moyen le plus simple de renvoyer des données consiste à définir setArgument (). Par exemple, vous avez fragment1 qui appelle fragment2 qui appelle fragment3, fragment1 -> framgnet2 -> fargment3

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

Dans fragment2, nous appelons fragment3 comme d'habitude

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

Lorsque nous avons terminé notre tâche dans fragment3, nous appelons maintenant ceci:

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

Maintenant, dans fragment2, nous pouvons facilement appeler des arguments

@Override
public void onResume() {
    super.onResume();
    Bundle rgs = getArguments();
    if (args != null) 
        String data = rgs.getString("bundle_filter");
}
0
Kirk_hehe

Il existe une bibliothèque Android - FlowR qui vous permet de démarrer des fragments pour obtenir des résultats.

Commencer un fragment pour un résultat.

Flowr.open(RequestFragment.class)
    .displayFragmentForResults(getFragmentId(), REQUEST_CODE);

La gestion des résultats dans le fragment appelant.

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

Définition du résultat dans le fragment.

Flowr.closeWithResults(getResultsResponse(resultCode, resultData));
0
Ragunath Jawahar

En fonction de votre architecture, vous pouvez également utiliser un ViewModel partagé entre les fragments. Donc, dans mon cas, FragmentA est un formulaire et FragmentB est une vue de sélection d’éléments dans laquelle l’utilisateur peut rechercher et sélectionner un élément, en le stockant dans le ViewModel. Ensuite, lorsque je reviens sur FragmentA, les informations sont déjà stockées! 

0
Arjun

Une solution utilisant des interfaces (et Kotlin). L'idée principale est de définir une interface de rappel, de l'implémenter dans votre activité, puis de l'appeler à partir de votre fragment.

Commencez par créer une interface ActionHandler:

interface ActionHandler {
    fun handleAction(actionCode: String, result: Int)
}

Ensuite, appelez ceci de votre enfant (dans ce cas, votre fragment):

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

Enfin, implémentez ceci dans votre parent pour recevoir le rappel (dans ce cas, votre activité):

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)
            }
        }
    }
0
JakeSteam