Podstawowa komunikacja między dwoma fragmentami

Mam jedną aktywność - MainActivity. W ramach tej aktywności mam dwa fragmenty, z których oba utworzyłem deklaratywnie w xml.

Próbuję przekazać String tekstu wprowadzonego przez użytkownika do Fragment A do widoku tekstu w Fragment B. Okazuje się to jednak bardzo trudne. Czy ktoś wie, jak Mogę to osiągnąć?

Zdaję sobie sprawę, że fragment może uzyskać odniesienie do swojej aktywności za pomocą getActivity(). Więc zgaduję, że zacznę od tego?

Author: horcrux, 2012-12-04

10 answers

[[3]}zajrzyj na stronę programistów Androida: http://developer.android.com/training/basics/fragments/communicating.html#DefineInterface

Zasadniczo definiujesz interfejs w swoim fragmencie A i pozwalasz swojej aktywności zaimplementować ten interfejs. Teraz możesz wywołać metodę interfejsu w swoim fragmencie, a Twoja aktywność otrzyma Zdarzenie. Teraz w swojej aktywności możesz wywołać drugi Fragment, aby zaktualizować textview o otrzymaną wartość

Twoja Aktywność implementuje Twój interfejs (Patrz FragmentA poniżej)

public class YourActivity implements FragmentA.TextClicked{
    @Override
    public void sendText(String text){
        // Get Fragment B
        FraB frag = (FragB)
            getSupportFragmentManager().findFragmentById(R.id.fragment_b);
        frag.updateText(text);
    }
}

Fragment A definiuje interfejs i w razie potrzeby wywołuje metodę

public class FragA extends Fragment{

    TextClicked mCallback;

    public interface TextClicked{
        public void sendText(String text);
    }

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

        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            mCallback = (TextClicked) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                + " must implement TextClicked");
        }
    }

    public void someMethod(){
        mCallback.sendText("YOUR TEXT");
    }

    @Override
    public void onDetach() {
        mCallback = null; // => avoid leaking, thanks @Deepscorn
        super.onDetach();
    }
}

Fragment B ma publiczną metodę, aby zrobić coś z tekstem

public class FragB extends Fragment{

    public void updateText(String text){
        // Here you have it
    }
}
 118
Author: Entreco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-29 21:09:37

Niektóre inne przykłady (a nawet dokumentacja w momencie pisania tego tekstu) używają przestarzałych metod onAttach. Oto pełny zaktualizowany przykład.

Tutaj wpisz opis obrazka

Uwagi

  • nie chcesz, aby fragmenty rozmawiały bezpośrednio ze sobą lub z aktywnością. Wiąże je to z konkretną czynnością i utrudnia ponowne użycie.
  • rozwiązaniem jest stworzenie interfejsu słuchacza wywołania zwrotnego, który zostanie zaimplementowany. Gdy Fragment chce wysłać wiadomość do innego fragmentu lub jego macierzystej aktywności, może to zrobić poprzez interfejs.
  • działanie może komunikować się bezpośrednio z publicznymi metodami fragmentu potomka.
  • w ten sposób działanie służy jako kontroler, przekazując wiadomości z jednego fragmentu do kolejny.

Kod

główna aktywność.java

public class MainActivity extends AppCompatActivity implements GreenFragment.OnGreenFragmentListener {

    private static final String BLUE_TAG = "blue";
    private static final String GREEN_TAG = "green";
    BlueFragment mBlueFragment;
    GreenFragment mGreenFragment;

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

        // add fragments
        FragmentManager fragmentManager = getSupportFragmentManager();

        mBlueFragment = (BlueFragment) fragmentManager.findFragmentByTag(BLUE_TAG);
        if (mBlueFragment == null) {
            mBlueFragment = new BlueFragment();
            fragmentManager.beginTransaction().add(R.id.blue_fragment_container, mBlueFragment, BLUE_TAG).commit();
        }

        mGreenFragment = (GreenFragment) fragmentManager.findFragmentByTag(GREEN_TAG);
        if (mGreenFragment == null) {
            mGreenFragment = new GreenFragment();
            fragmentManager.beginTransaction().add(R.id.green_fragment_container, mGreenFragment, GREEN_TAG).commit();
        }
    }

    // The Activity handles receiving a message from one Fragment
    // and passing it on to the other Fragment
    @Override
    public void messageFromGreenFragment(String message) {
        mBlueFragment.youveGotMail(message);
    }
}

GreenFragment.java

public class GreenFragment extends Fragment {

    private OnGreenFragmentListener mCallback;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_green, container, false);

        Button button = v.findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String message = "Hello, Blue! I'm Green.";
                mCallback.messageFromGreenFragment(message);
            }
        });

        return v;
    }

    // This is the interface that the Activity will implement
    // so that this Fragment can communicate with the Activity.
    public interface OnGreenFragmentListener {
        void messageFromGreenFragment(String text);
    }

    // This method insures that the Activity has actually implemented our
    // listener and that it isn't null.
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof OnGreenFragmentListener) {
            mCallback = (OnGreenFragmentListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnGreenFragmentListener");
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mCallback = null;
    }
}

BlueFragment.java

public class BlueFragment extends Fragment {

    private TextView mTextView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_blue, container, false);
        mTextView = v.findViewById(R.id.textview);
        return v;
    }

    // This is a public method that the Activity can use to communicate
    // directly with this Fragment
    public void youveGotMail(String message) {
        mTextView.setText(message);
    }
}

XML

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <!-- Green Fragment container -->
    <FrameLayout
        android:id="@+id/green_fragment_container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:layout_marginBottom="16dp" />

    <!-- Blue Fragment container -->
    <FrameLayout
        android:id="@+id/blue_fragment_container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

</LinearLayout>

fragment_green.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:background="#98e8ba"
              android:padding="8dp"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <Button
        android:id="@+id/button"
        android:text="send message to blue"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

fragment_blue.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:background="#30c9fb"
              android:padding="16dp"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <TextView
        android:id="@+id/textview"
        android:text="TextView"
        android:textSize="24sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>
 31
Author: Suragch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-23 14:48:40

Najładniejszym i zalecanym sposobem jest użycie współdzielonego modelu widoku.

Https://developer.android.com/topic/libraries/architecture/viewmodel#sharing

Z Google doc:

public class SharedViewModel extends ViewModel {
private final MutableLiveData<Item> selected = new MutableLiveData<Item>();

public void select(Item item) {
    selected.setValue(item);
}

public LiveData<Item> getSelected() {
    return selected;
}
}


public class MasterFragment extends Fragment {
private SharedViewModel model;
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
    itemSelector.setOnClickListener(item -> {
        model.select(item);
    });
}
}


public class DetailFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
    model.getSelected().observe(this, { item ->
       // Update the UI.
    });
}
}

Ps : dwa fragmenty nigdy nie komunikują się bezpośrednio

 13
Author: binary,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-05 00:30:37

Rozważmy moje 2 fragmenty A i B, i Załóżmy, że muszę przekazać dane z B do A.

Następnie utwórz interfejs w B i przekaż dane do głównej aktywności. Tam Utwórz inny interfejs i przekaż dane do fragmentu A.

Dzielenie się małym przykładem:

Fragment A wygląda jak

public class FragmentA extends Fragment implements InterfaceDataCommunicatorFromActivity {
public InterfaceDataCommunicatorFromActivity interfaceDataCommunicatorFromActivity;
String data;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    return super.onCreateView(inflater, container, savedInstanceState);
}

@Override
public void updateData(String data) {
    // TODO Auto-generated method stub
    this.data = data;
    //data is updated here which is from fragment B
}

@Override
public void onAttach(Activity activity) {
    // TODO Auto-generated method stub
    super.onAttach(activity);
    try {
        interfaceDataCommunicatorFromActivity = (InterfaceDataCommunicatorFromActivity) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()
                + " must implement TextClicked");
    }

}

}

Fragment wygląda jak

class FragmentB extends Fragment {
public InterfaceDataCommunicator interfaceDataCommunicator;

@Override
public void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);

    // call this inorder to send Data to interface
    interfaceDataCommunicator.updateData("data");
}

public interface InterfaceDataCommunicator {
    public void updateData(String data);
}

@Override
public void onAttach(Activity activity) {
    // TODO Auto-generated method stub
    super.onAttach(activity);
    try {
        interfaceDataCommunicator = (InterfaceDataCommunicator) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()
                + " must implement TextClicked");
    }

}

}

Główna aktywność to

public class MainActivity extends Activity implements InterfaceDataCommunicator {
public InterfaceDataCommunicatorFromActivity interfaceDataCommunicatorFromActivity;

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

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
public void updateData(String data) {
    // TODO Auto-generated method stub
    interfaceDataCommunicatorFromActivity.updateData(data);

}

public interface InterfaceDataCommunicatorFromActivity {
    public void updateData(String data);
}

}
 4
Author: pradeep,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-30 09:59:31
 1
Author: OWADVL,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-23 20:04:58

Istnieje prosty sposób na zaimplementowanie komunikacji między fragmentami czynności za pomocą komponentów architektonicznych. Dane mogą być przekazywane pomiędzy fragmentami aktywności za pomocą ViewModel i LiveData.

Fragmenty zaangażowane w komunikację muszą używać tych samych obiektów modelu widoku, które są powiązane z cyklem życia aktywności. Obiekt modelu widoku zawiera obiekt livedata, do którego dane są przekazywane przez jeden fragment, a drugi fragment nasłuchuje zmian w LiveData i odbiera wysłane dane z fragmentu pierwszego.

Pełny przykład zobacz http://www.zoftino.com/passing-data-between-android-fragments-using-viewmodel

 1
Author: Arnav Rao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-18 15:58:56

Dowiedz się "setTargetFragment ()"

Gdzie "startActivityForResult ()" ustanawia relację między 2 działaniami, "setTargetFragment ()" definiuje relację wywołującą/wywołaną między 2 fragmentami.

 0
Author: Erselan Khan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-20 06:45:32

Daję mojej aktywności interfejs, z którego mogą korzystać wszystkie fragmenty. Jeśli masz wiele fragmentów na tej samej aktywności, oszczędza to dużo ponownego pisania kodu i jest czystszym rozwiązaniem / bardziej modułowym niż tworzenie indywidualnego interfejsu dla każdego fragmentu o podobnych funkcjach. Podoba mi się również to, jak jest modułowy. Minusem jest to, że niektóre fragmenty będą miały dostęp do funkcji, których nie potrzebują.

    public class MyActivity extends AppCompatActivity
    implements MyActivityInterface {

        private List<String> mData; 

        @Override
        public List<String> getData(){return mData;}

        @Override
        public void setData(List<String> data){mData = data;}
    }


    public interface MyActivityInterface {

        List<String> getData(); 
        void setData(List<String> data);
    }

    public class MyFragment extends Fragment {

         private MyActivityInterface mActivity; 
         private List<String> activityData; 

         public void onButtonPress(){
              activityData = mActivity.getData()
         }

        @Override
        public void onAttach(Context context) {
            super.onAttach(context);
            if (context instanceof MyActivityInterface) {
                mActivity = (MyActivityInterface) context;
            } else {
                throw new RuntimeException(context.toString()
                        + " must implement MyActivityInterface");
            }
        }

        @Override
        public void onDetach() {
            super.onDetach();
            mActivity = null;
        }
    } 
 0
Author: David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-08-14 15:33:01

Update

Zignoruj tę odpowiedź. Nie żeby to nie działało. Ale są lepsze metody dostępne. Co więcej, Android zdecydowanie zniechęca do bezpośredniej komunikacji między fragmentami. Zobacz oficjalny dokument . Dzięki użytkownikowi @ Wahib Ul Haq za wskazówkę.

Oryginalna Odpowiedź

Cóż, możesz utworzyć prywatną zmienną i setter w fragmencie B i ustawić wartość z fragmentu A itself,

FragmentB.java

private String inputString;
....
....

public void setInputString(String string){
   inputString = string;
}

FragmentA.java

//go to fragment B

FragmentB frag  = new FragmentB();
frag.setInputString(YOUR_STRING);
//create your fragment transaction object, set animation etc
fragTrans.replace(ITS_ARGUMENTS)

Lub możesz użyć aktywności zgodnie z Twoją sugestią..

 -1
Author: Krishnabhadra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-13 03:31:24

Niedawno stworzyłem bibliotekę, która używa adnotacji do generowania tych typów odlewania kodu kotła dla Ciebie. https://github.com/zeroarst/callbackfragment

Oto przykład. Kliknij TextView na DialogFragment uruchamia wywołanie zwrotne do MainActivity w onTextClicked, a następnie chwyć instancję MyFagment, aby wejść w interakcję.

public class MainActivity extends AppCompatActivity implements MyFragment.FragmentCallback, MyDialogFragment.DialogListener {

private static final String MY_FRAGM = "MY_FRAGMENT";
private static final String MY_DIALOG_FRAGM = "MY_DIALOG_FRAGMENT";

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

    getSupportFragmentManager().beginTransaction()
        .add(R.id.lo_fragm_container, MyFragmentCallbackable.create(), MY_FRAGM)
        .commit();

    findViewById(R.id.bt).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            MyDialogFragmentCallbackable.create().show(getSupportFragmentManager(), MY_DIALOG_FRAGM);
        }
    });
}

Toast mToast;

@Override
public void onClickButton(MyFragment fragment) {
    if (mToast != null)
        mToast.cancel();
    mToast = Toast.makeText(this, "Callback from " + fragment.getTag() + " to " + this.getClass().getSimpleName(), Toast.LENGTH_SHORT);
    mToast.show();
}

@Override
public void onTextClicked(MyDialogFragment fragment) {
    MyFragment myFragm = (MyFragment) getSupportFragmentManager().findFragmentByTag(MY_FRAGM);
    if (myFragm != null) {
        myFragm.updateText("Callback from " + fragment.getTag() + " to " + myFragm.getTag());
    }
}

}

 -1
Author: Arst,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-27 01:30:32