Übergeben von Daten zwischen einem Fragment und seiner Containeraktivität

176

Wie kann ich Daten zwischen einem Fragment und seiner Containeraktivität übergeben? Gibt es etwas Ähnliches wie das Übertragen von Daten zwischen Aktivitäten durch Absichten?

Ich habe das gelesen, aber es hat nicht viel geholfen:
http://developer.android.com/guide/topics/fundamentals/fragments.html#CommunicatingWithActivity

tyb
quelle
Ist das nicht ausreichend? Sie können alles senden, was Sie wollen, vielleicht können Sie mehr erklären, was möchten Sie erreichen?
Marcin Milejski
Aus dem Dokument habe ich nicht verstanden, wie ich zum Beispiel einen Wert oder eine Zeichenfolge aus der Aktivität an das Fragment übergeben würde oder umgekehrt. Danke
tyb
2
Der beste Weg, um asynchrone Aufrufe von Fragmenten zu verarbeiten und diese Daten zurückzugeben, besteht darin, BroadcastReceivers auf beiden Seiten zu implementieren. Sie sollten es trotzdem asynchron machen, wenn Sie mit einer unspezifischen Anzahl von Fragmenten arbeiten.
Marek Sebera
@ Punisher_malade Nein, funktioniert für mich
Vadim Kotov

Antworten:

210

In Ihrem Fragment können Sie anrufen getActivity().

Dadurch erhalten Sie Zugriff auf die Aktivität, mit der das Fragment erstellt wurde. Von dort aus können Sie natürlich jede Art von Zugriffsmethode aufrufen, die sich in der Aktivität befindet.

zB für eine Methode, die getResult()für Ihre Aktivität aufgerufen wird :

((MyActivity) getActivity()).getResult();
Nick
quelle
85
Da Sie auf eine Funktion innerhalb IHRER Aktivität zugreifen (und nicht auf die übergeordnete Android-Aktivität), müssen Sie Ihren Aufruf getActivity () umwandeln: ((MyActivity) getActivity ()). GetResult ();
Nick
3
Wie wird möglicherweise die Rückmethode sein, vom Fragment zur Aktivität?
Vasil Valchev
6
@VasilValchev, Sie können eine Schnittstelle erstellen und die Implementierung der Aktivität erzwingen und dann eine Methode aus Ihrem Fragment aufrufen, um die Daten zu übergeben. Verwenden Sie die onAttach-Methode, um zu überprüfen, ob die Aktivität die Schnittstelle implementiert.
Ivan Nikolov
3
Hervorragende Antwort von @IvanNikolov. Eine ausführliche Erklärung finden Sie unter Fragmente Training Link
Bogdan
8
Dies ist weder eine gute Praxis noch ein Muster. Die Antwort mit Schnittstellen ist die richtige.
Moictab
303

Versuchen Sie es mit Schnittstellen.

Jedes Fragment, das Daten an seine enthaltende Aktivität zurückgeben soll, sollte eine Schnittstelle deklarieren, die die Daten verarbeitet und weitergibt. Stellen Sie dann sicher, dass Ihre enthaltende Aktivität diese Schnittstellen implementiert. Beispielsweise:

JAVA

Deklarieren Sie in Ihrem Fragment die Schnittstelle ...

public interface OnDataPass {
    public void onDataPass(String data);
}

Verbinden Sie dann die Implementierung der Schnittstelle der enthaltenden Klasse mit dem Fragment in der onAttach-Methode wie folgt:

OnDataPass dataPasser;

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    dataPasser = (OnDataPass) context;
}

Wenn Sie in Ihrem Fragment die Datenübergabe verarbeiten müssen, rufen Sie sie einfach im dataPasser-Objekt auf:

public void passData(String data) {
    dataPasser.onDataPass(data);
}

Schließlich in Ihrer enthaltenen Aktivität, die OnDataPass ...

@Override
public void onDataPass(String data) {
    Log.d("LOG","hello " + data);
}

KOTLIN

Schritt 1. Schnittstelle erstellen

interface OnDataPass {
    fun onDataPass(data: String)
}

Schritt 2. Verbinden Sie dann die Implementierung der Schnittstelle der enthaltenden Klasse mit dem Fragment in der onAttach-Methode (YourFragment) wie folgt:

lateinit var dataPasser: OnDataPass

override fun onAttach(context: Context) {
    super.onAttach(context)
    dataPasser = context as OnDataPass
}

Schritt 3. Wenn Sie in Ihrem Fragment die Datenübergabe verarbeiten müssen, rufen Sie sie einfach im dataPasser-Objekt auf:

fun passData(data: String){
    dataPasser.onDataPass(data)
}

Schritt 4. Schließlich implementiert OnDataPass in Ihrer Aktivität

class MyActivity : AppCompatActivity(), OnDataPass {}

override fun onDataPass(data: String) {
    Log.d("LOG","hello " + data)
}
Harlo Holmes
quelle
1
Vielen Dank gute Antwort auf den Punkt. Dies ist auch sehr schön erklärt hier . Was mir nicht klar war, ist, dass Sie mehrere Schnittstellen implementieren können. Ich habe bereits eine implementiert ActionBar.TabListenerund musste eine zusätzliche Schnittstelle hinzufügen.
Eugene van der Merwe
5
Dies ist definitiv der richtige Weg und meiner Meinung nach der EINZIGE Weg. Und bietet eine wechselseitige Interaktion zwischen der Aktivität und dem Fragment. Ermöglicht auch die Kommunikation zwischen Fragmenten, wenn Sie mehrere Fragmente in einer Aktivität haben, sei es über Registerkarten oder über das Layout mehrerer Fragmente.
Christopher
1
Ich frage mich etwas ... Dies ist die offizielle Antwort, und auf der offiziellen Entwicklerseite heißt es, dies sei der richtige Weg, um frag-act-frag zu kommunizieren, aber warum ist es überhaupt möglich, dies über das Casting von getActivity ( )?
Unmultimedio
3
Warum braucht jemand dafür eine zusätzliche Schnittstelle? Warum halten Sie die folgende Lösung für schlecht oder Ihre Lösung für besser? ((MyActivity) getActivity) .myMethod (...)
spacifici
3
onAttach (Aktivitätsaktivität) ist veraltet. Verwenden Sie stattdessen onAttach (Kontextkontext).
Chris.C
23

Einfachster Ansatz, aber nicht empfohlen

Sie können über das Fragment auf Aktivitätsdaten zugreifen:

Aktivität:

public class MyActivity extends Activity {

    private String myString = "hello";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        ...
    }

    public String getMyData() {
        return myString;
    }
}

Fragment:

public class MyFragment extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        MyActivity activity = (MyActivity) getActivity();
        String myDataFromActivity = activity.getMyData();
        return view;
    }
}
Zar E Ahmer
quelle
5
Dies fügt Ihrem Code eine hohe Kopplung hinzu und ist eine schlechte Praxis. Jetzt können Sie das Fragment in keiner anderen Aktivität alsMyActivity
AmeyaB
Warum wird dieser Weg als schlechte Praxis angesehen und ist die Schnittstelle nur eine Lösung dieser Frage?
androidXP
AmeyaB, wenn sich alle Aktivitäten von einer BaseActivity aus erstrecken oder und wir sie wie BaseActivity activity = (BaseActivity) getActivity () umwandeln; dann wird es bei allen Aktivitäten funktionieren
Zar E Ahmer
21
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    Bundle b = getActivity().getIntent().getExtras();
            wid = b.getString("wid");
            rid = b.getString("rid");
            View view = inflater.inflate(R.layout.categoryfragment, container, false);
    return view;
 }
Jeetu
quelle
14
So erhalten Sie es in das Fragment, aber wie legen Sie es in der Klasse fest, die das Fragment aufruft, wenn Sie Ihr Fragment in einer XML-Layoutdatei haben.
Zapnologica
17

Übergeben von Daten zwischen einem Fragment und seiner Containeraktivität

Aktivität:

        Bundle bundle = new Bundle();
        bundle.putString("message", "Alo Elena!");
        FragmentClass fragInfo = new FragmentClass();
        fragInfo.setArguments(bundle);
        transaction.replace(R.id.fragment_single, fragInfo);
        transaction.commit();

Fragment:

Lesen des Wertes im Fragment

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        String myValue = this.getArguments().getString("message");
        ...
        ...
        ...
        }
Jorgesys
quelle
Hallo @Elenasys. Wie kann ich Bundle-Daten von Aktivitäten an Fragmente zurücksenden? Ich bin von Fragment zu Aktivität übergegangen und muss zu dem bereits erstellten Fragment zurückkehren (ruft nur onStart, onResume, ... auf) und benötige die Daten, die ich in Aktivität erhalten konnte. Gibt es eine Möglichkeit, wie es geht, oder mache ich etwas falsch?
Michal Moravik
7

Ich weiß nicht, ob dies der beste Weg ist oder nicht. Ich habe schon eine ganze Weile bei Google gesucht, um herauszufinden, wie ich ein Bundle von einem Fragment an seine Containeraktivität übergeben kann, aber ich habe stattdessen nur Daten von Aktivität zu Fragment gesendet (was für mich etwas verwirrend war, da ich ein Neuling bin).

später versuchte ich etwas Eigenes, das genau für mich funktionierte, wie ich wollte. Also werde ich es hier posten, falls jemand wie ich das Gleiche sucht.

// Daten aus Fragment übergeben.

Bundle gameData = new Bundle();
        gameData.putStringArrayList(Constant.KEY_PLAYERS_ARR,players);
        gameData.putString(Constant.KEY_TEAM_NAME,custom_team_name);
        gameData.putInt(Constant.KEY_REQUESTED_OVER,requestedOver);

        Intent intent = getActivity().getIntent();
        intent.putExtras(gameData);

// Abrufen von Daten aus dem Bundle aus der Containeraktivität.

Bundle gameData = getIntent().getExtras();
        if (gameData != null)
        {
            int over = gameData.getInt(Constant.KEY_REQUESTED_OVER);
            ArrayList<String> players = gameData.getStringArrayList(Constant.KEY_PLAYERS_ARR);
            String team = gameData.getString(Constant.KEY_TEAM_NAME);

        }
        else if (gameData == null)
        {
            Toast.makeText(this, "Bundle is null", Toast.LENGTH_SHORT).show();
        }
Gefrorenes Tagebuch
quelle
6

Schnittstelle ist eine der besten Lösungen:

Kleberschnittstelle:

public interface DataProviderFromActivity {

    public String getName();
    public String getId);

}  

Meine Aktivität:

public class MyActivity implements DataProviderFromActivity{

    String name = "Makarov";
    String id = "sys533";

    ... ... ... ... ... .... .... 
    ... ... ... ... ... .... .... 

    public String getName(){
        return name;
    };
    public String getId(){
        return id;
    };
}

MyFragment:

public class MyFragment extends Fragment{

    String fragName = "";
    String fragId = "";

    ... ... ... ... ... .... .... 
    ... ... ... ... ... .... .... 

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        DataProviderFromActivity myActivity= (DataProviderFromActivity) getActivity();
        fragName = myActivity.getName();
        fragId = myActivity.getId();

        ... ... ... ... ... .... .... 
        ... ... ... ... ... .... .... 

        updateFragmentView();
    }
}
Hassan Tareq
quelle
Hallo @HassanMakarov Ich mag deine Oberfläche, einfach und sauber. Ich habe jedoch ein Problem. Ich weiß nicht, ob es spezifisch für meinen Viewpager ist, aber ich bekomme die Daten nur in höchstens 2 Fragmenten gleichzeitig? Die Zeichenfolgen "Makarov" und "sys533" werden in Fragmenten 1 und 2 angezeigt, wenn die Aktivität erstellt wird. Die Zeichenfolgen werden jedoch erst in Fragment 3 angezeigt, wenn Fragment 2 oder 3 ausgewählt ist. Irgendwelche Ideen?
JC23
@ JC23 Ich denke, das Problem hängt mit der Fragmenttransaktion zusammen. Welches Fragment wird beim Start von MainActivity festgelegt?
Hassan Tareq
@ JC23 Was ich mache: Anstelle von Tab / ViewPager verwende ich Toolbar & NavigationView. In onNavigationItemSelected () führe ich Fragmenttransaktionen durch, um Fragmente entsprechend festzulegen.
Hassan Tareq
2

Ich habe eine AppCompatActivity verwendet, die Datumslistener implementiert. Fragmente waren eine Notwendigkeit, da ich einen Datumsbereichsselektor codieren musste. Außerdem brauchte ich den Container, um die ausgewählten Daten zu erhalten und sie an die übergeordnete Aktivität zurückzugeben.

Für die Containeraktivität ist dies die Klassendeklaration:

public class AppCompatDateRange extends AppCompatActivity implements
    DateIniRangeFragment.OnDateIniSelectedListener, DateFimRangeFragment.OnDateFimSelectedListener

Und die Schnittstellen für die Rückrufe:

@Override
public void onDateIniSelected(String dataIni) {
    Log.i("data inicial:", dataIni);
}

@Override
public void onDateFimSelected(String dataFim) {
    Log.i("data final:", dataFim);
}

Die Rückrufe sind Zeichenfolgen, da Datumsangaben Parameter in einer Abfrageauswahl sind.

Der Code für die Fragmente (basierend auf dem ursprünglichen Datumsfragment):

public class DateIniRangeFragment extends Fragment {
OnDateIniSelectedListener callbackIni;

private DatePicker startDatePicker;

public DateIniRangeFragment() {
    ///required empty constructor
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
}

///through this interface the fragment sends data to the container activity
public interface OnDateIniSelectedListener {
    void onDateIniSelected(String dataIni);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    ///layout for the fragment
    View v = inflater.inflate(R.layout.date_ini_fragment, container, false);

    ///initial date for the picker, in this case, current date
    startDatePicker = (DatePicker) v.findViewById(R.id.start_date_picker_appcompat);
    Calendar c = Calendar.getInstance();
    int ano = c.get(Calendar.YEAR);
    int mes = c.get(Calendar.MONTH);
    int dia = c.get(Calendar.DAY_OF_MONTH);
    startDatePicker.setSpinnersShown(false);
    startDatePicker.init(ano, mes, dia, dateSetListener);

    return v;
}

///listener that receives the selected date
private DatePicker.OnDateChangedListener dateSetListener = new DatePicker.OnDateChangedListener() {
    public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
        if (view.isShown()) { ///if the datepicker is on the screen
            String sDataIni = year + "-" + (monthOfYear + 1) + "-" + dayOfMonth;
            callbackIni.onDateIniSelected(sDataIni); //apply date to callback, string format
        }
    }
};

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);

    /*
    * this function guarantees that the container activity implemented the callback interface
    * */
    try {
        callbackIni = (OnDateIniSelectedListener) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString() + " deve implementar OnDateIniSelectedListener");
    }
}

}}

Zum Erstellen des Containers + der Fragmente habe ich einen ViewPager (AppCompat) mit einer benutzerdefinierten Klasse verwendet, die FragmentPagerAdapter erweitert. Keine Dialoge.

Pablo
quelle
2

Sie können EventBus einfach verwenden, es ist einfach und funktioniert hervorragend

EventBus in 3 Schritten

  1. Ereignisse definieren:

    public static class MessageEvent { /* Additional fields if needed */ }

  2. Abonnenten vorbereiten: Deklarieren und kommentieren Sie Ihre Abonnementmethode, und geben Sie optional einen Thread-Modus an:

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(MessageEvent event) {/* Do something */};

Registrieren Sie Ihren Abonnenten und heben Sie die Registrierung auf. Beispielsweise sollten sich Aktivitäten und Fragmente unter Android normalerweise entsprechend ihrem Lebenszyklus registrieren:

 @Override
 public void onStart() {
     super.onStart();
     EventBus.getDefault().register(this);
 }

 @Override
 public void onStop() {
     super.onStop();
     EventBus.getDefault().unregister(this);
 }
  1. Ereignisse veröffentlichen:

    EventBus.getDefault().post(new MessageEvent());

Sattar
quelle
1

Ich weiß, dass dies zu spät sein könnte. Aber ich war auch immer in dieser Frage verloren. Ich teile diesen Link ... weil dies möglicherweise die beste Erklärung ist, die ich jemals im Internet dafür gefunden habe. Dies löst Fragment zu Aktivität und Fragment zu Fragment !

Sehr gut gelöst und erklärt

Yo Apps
quelle
0

Das funktioniert bei mir ..

Fügen Sie in Aktivität diese Methode hinzu

    public void GetData(String data)
     {
        // do something with your data        
     }

und in Fragment diese Zeile hinzufügen

((YourActivity)getContext).GetData("your data here");
Basant
quelle
0
public class Fragmentdemo extends Fragment {

  public interface onDemoEventListener {
    public void demoEvent(String s);
  }

  onDemoEventListener demoEventListener;

  @Override
  public void onAttach(Activity activity) {
    super.onAttach(activity);
        try {
          demoEventListener = (onDemoEventListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement onDemoEventListener");
        }
  }

  final String LOG_TAG = "TAG";

  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragmentdemo, null);

    Button button = (Button) v.findViewById(R.id.button);
    button.setOnClickListener(new OnClickListener() {
      public void onClick(View v) {
        demoEventListener.someEvent("Test text to Fragment1");
      }
    });
    enter code here
    return v;
  }
}
Shweta Chandarana
quelle
-12

Eine andere einfache Möglichkeit, Daten, die von einer anderen Aktivität übergeben wurden, in einem Fragment in einer Containeraktivität abzurufen: Beispiel:

Activity_A => Activity_B (Fragment)

In Ihrer Aktivität_A erstellen Sie eine Absicht, als würden Sie Daten (Zeichenfolge hier) an eine andere Aktivität senden:

Intent intent = new Intent(getBaseContext(),Activity_B.class);
intent.putExtra("NAME", "Value");
startActivity(intent);

in Ihrem Fragment, enthalten in Ihrer Activity_B:

String data = getActivity().getIntent().getExtras();
SuperZouzou
quelle
getBaseContext()gibt mir den folgenden Fehler:The method getBaseContext() is undefined for the type new View.OnClickListener(){}
Si8