web-dev-qa-db-de.com

Gibt es eine Methode, die wie das Start-Fragment für das Ergebnis funktioniert?

Ich habe derzeit ein Fragment in einer Überlagerung. Dies ist für die Anmeldung beim Dienst. In der Telefon-App sind alle Schritte, die ich in der Überlagerung anzeigen möchte, ihre eigenen Bildschirme und Aktivitäten. Es gibt drei Teile des Anmeldeprozesses und jeder hatte seine eigene Aktivität, die mit startActivityForResult () aufgerufen wurde. 

Jetzt möchte ich dasselbe mit Fragmenten und einer Überlagerung tun. Die Überlagerung zeigt ein Fragment, das jeder Aktivität entspricht. Das Problem ist, dass diese Fragmente in einer Aktivität in der Honeycomb-API gehostet werden. Ich kann das erste Fragment zum Laufen bringen, aber dann muss ichActivityForResult () starten, was nicht möglich ist. Gibt es etwas in der Richtung von startFragmentForResult (), bei dem ich ein neues Fragment starten kann und wenn es fertig ist, ein Ergebnis zum vorherigen Fragment zurückgeben?

70
CACuzcatlan

Alle Fragmente leben in Aktivitäten. Das Starten eines Fragments für ein Ergebnis ist nicht sehr sinnvoll, da die Aktivität, in der es untergebracht ist, immer Zugriff darauf hat und umgekehrt. Wenn das Fragment ein Ergebnis weitergeben muss, kann es auf seine Aktivität zugreifen, das Ergebnis festlegen und es beenden. Im Falle des Austauschs von Fragmenten in einer einzelnen Aktivität ist die Aktivität auch für beide Fragmente zugänglich, und alle Nachrichten, die Sie weitergeben, können einfach durch die Aktivität gehen.

Denken Sie daran, dass Sie immer zwischen einem Fragment und seiner Aktivität kommunizieren. Beginnen und beenden Sie mit einem Ergebnis den Mechanismus für die Kommunikation zwischen Aktivitäten. Die Aktivitäten können dann alle erforderlichen Informationen an ihre Fragmente delegieren.

45
LeffelMania

Wenn Sie möchten, gibt es einige Methoden zur Kommunikation zwischen Fragmenten.

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

Sie können mit diesen Rückrufen. 

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

Meine 2 Cent.

Ich wechsle zwischen Fragmenten, indem ich ein altes Fragment durch Verstecken und Anzeigen/Hinzufügen (Vorhanden/Neu) austauschen. Diese Antwort ist also für Entwickler gedacht, die Fragmente wie ich verwenden.

Dann verwende ich die onHiddenChanged-Methode, um zu wissen, dass das alte Fragment von dem neuen umgestellt wurde. Siehe Code unten.

Vor dem Verlassen des neuen Fragments habe ich ein Ergebnis in einem globalen Parameter festgelegt, der vom alten Fragment abgefragt werden soll. Dies ist eine sehr naive Lösung.

@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

In Ihrem Fragment können Sie getActivity () aufrufen. Dadurch erhalten Sie Zugriff auf die Aktivität, mit der das Fragment erstellt wurde. Von dort aus können Sie Ihre eigene Methode aufrufen, um die Werte festzulegen oder die Werte zu übergeben.

1
Summved Jain

Sie können EventBus verwenden. Es vereinfacht die Kommunikation zwischen Aktivitäten, Fragmenten, Threads, Diensten usw. Weniger Code, bessere Qualität.

0

Wir können einfach dasselbe ViewModel zwischen Fragmenten teilen 

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

Die einfachste Möglichkeit, Daten zurückzuleiten, ist setArgument (). Beispielsweise haben Sie fragment1, das fragment2 aufruft und fragment3, fragment1 -> framgnet2 -> fargement3

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

In fragment2 nennen wir wie gewohnt fragment3

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

Wenn wir unsere Aufgabe in fragment3 beendet haben, rufen wir jetzt so auf:

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

In fragment2 können wir leicht Argumente aufrufen

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

Es gibt eine Android-Bibliothek - FlowR , mit der Sie Fragmente für Ergebnisse starten können.

Ein Fragment für das Ergebnis starten.

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

Ergebnisse im aufrufenden Fragment behandeln.

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

Festlegen des Ergebnisses im Fragment.

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

Abhängig von Ihrer Architektur können Sie auch ein gemeinsames ViewModel zwischen den Fragmenten verwenden. In meinem Fall ist FragmentA ein Formular, und FragmentB ist eine Elementauswahlansicht, in der der Benutzer ein Element suchen und auswählen und im ViewModel speichern kann. Wenn ich dann zu FragmentA zurückkomme, sind die Informationen bereits gespeichert! 

0
Arjun

Eine Lösung mit Schnittstellen (und Kotlin). Die Grundidee besteht darin, eine Rückmeldeschnittstelle zu definieren, in Ihre Aktivität zu implementieren und sie dann von Ihrem Fragment aus aufzurufen.

Erstellen Sie zuerst eine Schnittstelle ActionHandler:

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

Rufen Sie als Nächstes dies von Ihrem Kind (in diesem Fall Ihr Fragment) auf:

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

Implementieren Sie dies schließlich in Ihrem übergeordneten Element, um den Rückruf (in diesem Fall Ihre Aktivität) zu erhalten:

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