Jak przekazywać wartości między fragmentami

109

Jestem całkiem nowy w używaniu Fragmentów.

Po prostu próbuję zbudować prostą przykładową aplikację, która używa fragmentów. Mój scenariusz jest taki, że mam dwie czynności z jednym fragmentem w każdej czynności. Pierwszy fragment ma edittext i przycisk. Drugi fragment zawiera widok tekstu. Po wpisaniu nazwy w edytorze i kliknięciu przycisku, w widoku tekstu w drugim fragmencie powinna wyświetlić się nazwa wpisana w edytorze pierwszego fragmentu.

Mogłem przesłać wartość z pierwszego fragmentu do jego aktywności, a następnie z tej czynności do drugiej. Teraz, jak użyć tej wartości w drugim fragmencie.

Oto kod Java :::

package com.example.fragmentexample;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class Fragment_1 extends Fragment{

    OnFragmentChangedListener mCallback;

    // Container Activity must implement this interface
    public interface OnFragmentChangedListener {
        public void onButtonClicked(String name);
    }

    @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 = (OnFragmentChangedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnHeadlineSelectedListener");
        }
    }


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

        View view = inflater.inflate(R.layout.fragment_fragment_1, container, false);

        final EditText edtxtPersonName_Fragment = (EditText) view.findViewById(R.id.edtxtPersonName);
        Button btnSayHi_Fragment = (Button) view.findViewById(R.id.btnSayHi);

        btnSayHi_Fragment.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub

                String name = edtxtPersonName_Fragment.getText().toString();

                FragmentManager fm = getFragmentManager();
                Fragment_2 f2 = (Fragment_2) fm.findFragmentById(R.id.fragment_content_2);

                Activity activity = getActivity();

                if(activity != null)
                {
                    Toast.makeText(activity, "Say&ing Hi in Progress...", Toast.LENGTH_LONG).show();
                }


                if(f2 != null && f2.isInLayout())
                {
                    f2.setName(name);
                }
                else
                {
                    mCallback.onButtonClicked(name);
                }
            }
        });

        return view;


    }

}

MainActivity.Java

package com.example.fragmentexample;

import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;

import android.view.Choreographer.FrameCallback;
import android.view.Menu;

public class MainActivity extends Activity implements Fragment_1.OnFragmentChangedListener {

    @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.activity_main, menu);
        return true;
    }

    @Override
    public void onButtonClicked(String name) {
        // TODO Auto-generated method stub

        Intent i = new Intent(this, SecondActivity.class);
        i.putExtra("", name);
        startActivity(i);
    }

}

SecondActivity.Java

package com.example.fragmentexample;

import android.app.Activity;
import android.os.Bundle;

public class SecondActivity extends Activity{

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

        setContentView(R.layout.activity_second);

        Bundle b = getIntent().getExtras();

        Fragment_2 f2 = new Fragment_2();
        f2.setArguments(b);
    }
}

Fragment_2.Java

package com.example.fragmentexample;

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class Fragment_2 extends Fragment{

    View view;
    TextView txtName;


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

        view = inflater.inflate(R.layout.fragment_fragment_2, container, false);

            // Exception at this line
        String name = getArguments().getString("message");
        txtName = (TextView) view.findViewById(R.id.txtViewResult);
        txtName.setText(name);

        return view;
    }

    @Override
    public void onAttach(Activity activity) {
        // TODO Auto-generated method stub
        super.onAttach(activity);       
    }

    public void setName(String name)
    {   
        txtName.setText("Hi " + name);
    }

}

Otrzymuję następujący wyjątek :::

04-16 18:10:24.573: E/AndroidRuntime(713): FATAL EXCEPTION: main
04-16 18:10:24.573: E/AndroidRuntime(713): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.fragmentexample/com.example.fragmentexample.SecondActivity}: android.view.InflateException: Binary XML file line #8: Error inflating class fragment
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1815)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1831)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.ActivityThread.access$500(ActivityThread.java:122)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1024)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.os.Handler.dispatchMessage(Handler.java:99)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.os.Looper.loop(Looper.java:132)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.ActivityThread.main(ActivityThread.java:4123)
04-16 18:10:24.573: E/AndroidRuntime(713):  at java.lang.reflect.Method.invokeNative(Native Method)
04-16 18:10:24.573: E/AndroidRuntime(713):  at java.lang.reflect.Method.invoke(Method.java:491)
04-16 18:10:24.573: E/AndroidRuntime(713):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
04-16 18:10:24.573: E/AndroidRuntime(713):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
04-16 18:10:24.573: E/AndroidRuntime(713):  at dalvik.system.NativeStart.main(Native Method)
04-16 18:10:24.573: E/AndroidRuntime(713): Caused by: android.view.InflateException: Binary XML file line #8: Error inflating class fragment
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:688)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.view.LayoutInflater.rInflate(LayoutInflater.java:724)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.view.LayoutInflater.inflate(LayoutInflater.java:479)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.view.LayoutInflater.inflate(LayoutInflater.java:391)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.view.LayoutInflater.inflate(LayoutInflater.java:347)
04-16 18:10:24.573: E/AndroidRuntime(713):  at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:223)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.Activity.setContentView(Activity.java:1786)
04-16 18:10:24.573: E/AndroidRuntime(713):  at com.example.fragmentexample.SecondActivity.onCreate(SecondActivity.java:13)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.Activity.performCreate(Activity.java:4397)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1048)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1779)
04-16 18:10:24.573: E/AndroidRuntime(713):  ... 11 more
04-16 18:10:24.573: E/AndroidRuntime(713): Caused by: java.lang.NullPointerException
04-16 18:10:24.573: E/AndroidRuntime(713):  at com.example.fragmentexample.Fragment_2.onCreateView(Fragment_2.java:24)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:754)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:956)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.FragmentManagerImpl.addFragment(FragmentManager.java:1035)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.app.Activity.onCreateView(Activity.java:4177)
04-16 18:10:24.573: E/AndroidRuntime(713):  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:664)
04-16 18:10:24.573: E/AndroidRuntime(713):  ... 21 more

Jak uzyskać wartość z pakietu w SecondActivity.java do Fragment_2.Java?

Vamsi Challa
źródło
Proszę zaznaczyć fragment, w którym ru pojawia się problem
Nikhil Agrawal
rozwiązanie robocze w łatwy sposób: stackoverflow.com/a/59332751/10201722
Adil Siddiqui,

Odpowiedzi:

203

krok 1. przesłanie danych z fragmentu do działania

Intent intent = new Intent(getActivity().getBaseContext(),
                        TargetActivity.class);
                intent.putExtra("message", message);
                getActivity().startActivity(intent);

krok 2. aby otrzymać te dane w Aktywności:

Intent intent = getIntent();
String message = intent.getStringExtra("message");

krok 3 . aby przesłać dane z działania do innego działania, należy postępować zgodnie z normalnym podejściem

Intent intent = new Intent(MainActivity.this,
                        TargetActivity.class);
                intent.putExtra("message", message);
                startActivity(intent);

krok 4, aby otrzymać te dane w działaniu

     Intent intent = getIntent();
  String message = intent.getStringExtra("message");

Krok 5. Z Activity możesz wysłać dane do Fragmentu z zamiarem:

Bundle bundle=new Bundle();
bundle.putString("message", "From Activity");
  //set Fragmentclass Arguments
Fragmentclass fragobj=new Fragmentclass();
fragobj.setArguments(bundle);

i odebrać fragmentem w metodzie Fragment onCreateView:

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
          String strtext=getArguments().getString("message");

    return inflater.inflate(R.layout.fragment, container, false);
    }
Shiv
źródło
2
Wypróbowałem krok 5, że wywołuję listactivity z fragmentu i po wybraniu elementu z tego działania chcę wrócić we fragmencie z wybraną nazwą pliku. Ale to nie działa, daje mi wyjątek Nullpointer w onCreateView. Jakieś rozwiązanie w tej sprawie? To jest moje pytanie stackoverflow.com/questions/18208771/ ...
OnkarDhane
jak umieścić tutaj POJO? bundle.putString("message", "From Activity");
jeet.chanchawat
31
Czy ktoś jest zniesmaczony tym, jak zawiłe jest robienie czegoś takiego
Ed Lee,
1
Dokładnie Eddie, to nie jest właściwy sposób. Powinni używać interfejsów do komunikacji między fragmentami za pośrednictwem działania kontenera.
Kaveesh Kanwal
Odnośnie używania interfejsów do komunikacji między fragmentami: developer.android.com/training/basics/fragments/ ...
Andre L Torres
49

Jak wspomniano na stronie programisty

Często będziesz chciał, aby jeden fragment komunikował się z innym, na przykład aby zmienić zawartość na podstawie zdarzenia użytkownika. Cała komunikacja między fragmentami odbywa się za pośrednictwem skojarzonego działania. Dwa fragmenty nigdy nie powinny komunikować się bezpośrednio.

komunikacja między fragmentami powinna odbywać się poprzez powiązane działanie.

Miejmy następujące elementy:

Działanie zawiera fragmenty i umożliwia komunikację fragmentów

Fragment Pierwszy fragment, który wyśle ​​dane

FragmentB drugi fragment, który otrzyma dane z FragmentA

Implementacja FragmentA to:

public class FragmentA extends Fragment 
{
    DataPassListener mCallback;
    
    public interface DataPassListener{
        public void passData(String data);
    }

    @Override
    public void onAttach(Context context) 
    {
        super.onAttach(context);
        // This makes sure that the host activity has implemented the callback interface
        // If not, it throws an exception
        try 
        {
            mCallback = (OnImageClickListener) context;
        }
        catch (ClassCastException e) 
        {
            throw new ClassCastException(context.toString()+ " must implement OnImageClickListener");
        }
    }
    
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) 
    {
        // Suppose that when a button clicked second FragmentB will be inflated
        // some data on FragmentA will pass FragmentB
        // Button passDataButton = (Button).........
        
        passDataButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (view.getId() == R.id.passDataButton) {
                    mCallback.passData("Text to pass FragmentB");
                }
            }
        });
    }
}

Implementacja MainActivity to:

public class MainActivity extends ActionBarActivity implements DataPassListener{
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        if (findViewById(R.id.container) != null) {
            if (savedInstanceState != null) {
                return;
            }
            getFragmentManager().beginTransaction()
                    .add(R.id.container, new FragmentA()).commit();
        }
    }
    
    @Override
    public void passData(String data) {
        FragmentB fragmentB = new FragmentB ();
        Bundle args = new Bundle();
        args.putString(FragmentB.DATA_RECEIVE, data);
        fragmentB .setArguments(args);
        getFragmentManager().beginTransaction()
            .replace(R.id.container, fragmentB )
            .commit();
    }
}

Implementacja FragmentB to:

public class FragmentB extends Fragment{
    final static String DATA_RECEIVE = "data_receive";
    TextView showReceivedData;
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_B, container, false);
        showReceivedData = (TextView) view.findViewById(R.id.showReceivedData);
    }
    
    @Override
    public void onStart() {
        super.onStart();
        Bundle args = getArguments();
        if (args != null) {
            showReceivedData.setText(args.getString(DATA_RECEIVE));
        }
    }
}

Mam nadzieję, że to pomoże..

ozhanli
źródło
4
Co to jest tutaj OnImageClickListener? i jak jest rzutowany na zmienną DataPassListener?
Harsha
Okazało się, że to „DataPassListener”. Mam to do pracy, ale tylko po to, aby znaleźć, ponieważ za każdym kliknięciem przycisku dane są wysyłane. Po wysłaniu zastępuje fragment. Co oznacza, że ​​lista jest odnawiana za każdym razem. Dlatego nie trzymanie listy pozycji w pamięci.
wesley franks
44

// We Fragment_1.java

Bundle bundle = new Bundle();
bundle.putString("key","abc"); // Put anything what you want

Fragment_2 fragment2 = new Fragment_2();
fragment2.setArguments(bundle);

getFragmentManager()
      .beginTransaction()
      .replace(R.id.content, fragment2)
      .commit();

// We Fragment_2.java

Bundle bundle = this.getArguments();

if(bundle != null){
     // handle your code here.
}

Mam nadzieję, że to ci pomoże.

nguyencse
źródło
1
Czysta odpowiedź, aby pokazać główny punkt. za pomocą putString(lub putInt) jest odpowiedzią!
Mehdi Dehghani
22

Ze strony dla programistów :

Często będziesz chciał, aby jeden fragment komunikował się z innym, na przykład aby zmienić zawartość na podstawie zdarzenia użytkownika. Cała komunikacja między fragmentami odbywa się za pośrednictwem skojarzonego działania. Dwa fragmenty nigdy nie powinny komunikować się bezpośrednio.

Możesz porozumiewać się między fragmentami za pomocą jego Aktywności. Za pomocą tego podejścia możesz komunikować się między działaniami i fragmentami .

Sprawdź również ten link.

Jainendra
źródło
Drugi link, który podałeś, pokazuje, jak komunikować się między fragmentami, gdy są w tej samej aktywności. Jak mam się komunikować, gdy oboje wykonują różne czynności?
Vamsi Challa,
5

Po pierwsze wszystkie odpowiedzi są prawidłowe, możesz przekazać dane z wyjątkiem obiektów niestandardowych za pomocą Intent. Jeśli chcesz przekazać niestandardowe obiekty, musisz zaimplementować Serialazablelub Parcelabledo niestandardowej klasy obiektów. Myślałem, że to zbyt skomplikowane ...

Więc jeśli twój projekt jest prosty, spróbuj użyć DataCache. Zapewnia to bardzo prosty sposób przekazywania danych. Ref: Projekt Github CachePot

1- Ustaw to na Widok lub Aktywność lub Fragment, który wyśle ​​dane

DataCache.getInstance().push(obj);

2- Uzyskaj dane w dowolnym miejscu, jak poniżej

public class MainFragment extends Fragment
{
    private YourObject obj;

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

        obj = DataCache.getInstance().pop(YourObject.class);

    }//end onCreate()
}//end class MainFragment
kimkevin
źródło
Czy nie byłoby łatwiej użyć dodatkowej klasy ze statycznymi wartościami wewnątrz? Dostęp do tych wartości można następnie uzyskać za pomocą obu fragmentów, więc nie ma potrzeby używania dodatkowej biblioteki do buforowania niestandardowych obiektów.
Neph
4

Najnowsze rozwiązanie do przekazywania danych między fragmentami można zaimplementować przy użyciu komponentów architektonicznych Androida, takich jak ViewModel i LiveData. Dzięki temu rozwiązaniu nie musisz definiować interfejsu do komunikacji i możesz czerpać korzyści z używania ViewModel, takie jak przetrwanie danych ze względu na zmiany konfiguracji.

W tym rozwiązaniu fragmenty zaangażowane w komunikację mają ten sam obiekt viewmodel, który jest powiązany z cyklem życia ich działania. Obiekt modelu widoku zawiera obiekt Liveata. Jeden fragment ustawia dane do przekazania do obiektu Liveata, a obserwatorzy drugiego fragmentu zmieniają dane i otrzymują dane.

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

Arnav Rao
źródło
3

Przekazywanie argumentów między fragmentami. To dość późna odpowiedź na to pytanie, ale może to komuś pomóc! Fragment_1.java

Bundle i = new Bundle(); 
            i.putString("name", "Emmanuel");

            Fragment_1 frag = new Fragment_1();
            frag.setArguments(i);
            FragmentManager fragmentManager = getFragmentManager();
            fragmentManager.beginTransaction()
                    .replace(R.id.content_frame
                            , new Fragment_2())
                    .commit();

Wtedy w twoim Fragment_2.javamożesz normalnie uzyskać parametry w twoim onActivityCreated np

 Intent intent = getActivity().getIntent();
    if (intent.getExtras() != null) {
        String name =intent.getStringExtra("name");
    }
Emmanuel R.
źródło
3

Myślę, że dobrym sposobem rozwiązania tego problemu jest użycie niestandardowego interfejsu.

Załóżmy, że masz dwa fragmenty (A i B), które znajdują się w ramach tego samego działania i chcesz wysłać dane z punktu A do B.

Interfejs:

public interface OnDataSentListener{
    void onDataSent(Object data);
}

Czynność:

    public class MyActivity extends AppCompatActivity{

            private OnDataSentListener onDataSentListener;

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

                FragmentTransaction trans = getFragmentManager().beginTransaction();

                FragmentA fa = new FragmentA();
                FragmentB fb = new FragmentB();

               fa.setOnDataSentListener(new Listeners.OnDataSentListener() {
                    @Override
                    public void onDataSent(Object data) {
                         if(onDataSentListener != null)  onDataSentListener.onDataSent(data);
                    }
               });

                transaction.add(R.id.frame_a, fa);
                transaction.add(R.id.frame_b, fb);

                transaction.commit();
            }

            public void setOnDataSentListener(OnDataSentListener listener){
                this.onDataSentListener = listener;
            }
        }

Fragment A:

public class FragmentA extends Fragment{

    private OnDataSentListener onDataSentListener;

    private void sendDataToFragmentB(Object data){
        if(onDataSentListener != null) onDataSentListener.onDataSent(data);
    }

    public void setOnDataSentListener(OnDataSentListener listener){
        this.onDataSentListener = listener;
    }
}

Fragment B:

public class FragmentB extends Fragment{

    private void initReceiver(){
        ((MyActivity) getActivity()).setOnDataSentListener(new OnDataSentListener() {
            @Override
            public void onDataSent(Object data) {
                //Here you receive the data from fragment A
            }
        });
    }
}
simpleApps
źródło
2

Komunikacja między fragmentami jest dość skomplikowana (uważam, że koncepcja słuchaczy jest trochę trudna do wdrożenia).

Do wyodrębnienia tych komunikatów często używa się „szyny zdarzeń”. Jest to biblioteka strony trzeciej, która zajmuje się tą komunikacją za Ciebie.

Często do tego używa się „Otto” i warto zajrzeć na stronę: http://square.github.io/otto/

Booger
źródło
2

Przekazywanie danych z fragmentu do innego fragmentu

  • Od pierwszego fragmentu

    // Set data to pass
    MyFragment fragment = new MyFragment(); //Your Fragment
    Bundle bundle = new Bundle();
    bundle.putInt("year", 2017)  // Key, value
    fragment.setArguments(bundle); 
    // Pass data to other Fragment
    getFragmentManager()
     .beginTransaction()
     .replace(R.id.content, fragment)
     .commit(); 
  • Na drugim fragmencie

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
    
         Bundle bundle = this.getArguments();
         if (bundle != null) {
             Int receivedYear = bundle.getInt("year", ""); // Key, default value
         } 
    }
Duch Rozwiązań
źródło
1

Ta prosta implementacja pomaga w prostym przekazywaniu danych między fragmentami. Myślisz, że chcesz przekazać dane z „Frgement1” do „Fragment2”

We fragmencie 1 (ustaw dane do wysłania)

 Bundle bundle = new Bundle();
 bundle.putString("key","Jhon Doe"); // set your parameteres

 Fragment2 nextFragment = new Fragment2();
 nextFragment.setArguments(bundle);

 FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
 fragmentManager.beginTransaction().replace(R.id.content_drawer, nextFragment).commit();

W metodzie Fragment2 onCreateView (Pobierz parametry)

String value = this.getArguments().getString("key");//get your parameters
Toast.makeText(getActivity(), value+" ", Toast.LENGTH_LONG).show();//show data in tost
Janaka
źródło
W mojej aplikacji próbuję to uruchomić, ale jakoś wartość jest przekazywana, ale nie jest wyświetlana na fragmencie2, myślę, że popełniam błąd w ustawianiu R.id.content_drawer. Czy ktoś może mi pomóc, jaki może być właściwy identyfikator dla R.id.content_drawer z przykładem .xml.
falcon
1

Droga Kotlina

Skorzystaj z SharedViewModelpropozycji w oficjalnej dokumentacji ViewModel

Bardzo często dwa lub więcej fragmentów działania musi się ze sobą komunikować. Wyobraź sobie typowy przypadek fragmentów master-detail, w którym masz fragment, w którym użytkownik wybiera element z listy i inny fragment, który wyświetla zawartość wybranego elementu. Ten przypadek nigdy nie jest trywialny, ponieważ oba fragmenty muszą definiować jakiś opis interfejsu, a aktywność właściciela musi powiązać je ze sobą. Ponadto oba fragmenty muszą obsługiwać scenariusz, w którym drugi fragment nie jest jeszcze utworzony lub widoczny.

Ten typowy problem można rozwiązać za pomocą obiektów ViewModel. Te fragmenty mogą współużytkować ViewModel przy użyciu zakresu działania do obsługi tej komunikacji

Najpierw zaimplementuj fragment-ktx, aby łatwiej utworzyć instancję modelu widoku

dependencies {
    implementation "androidx.fragment:fragment-ktx:1.2.2"
} 

Następnie wystarczy umieścić w modelu widoku dane, które będziesz udostępniać drugiemu fragmentowi

class SharedViewModel : ViewModel() {
    val selected = MutableLiveData<Item>()

    fun select(item: Item) {
        selected.value = item
    }
}

Następnie, aby zakończyć, po prostu utwórz wystąpienie viewModel w każdym fragmencie i ustaw wartość selected z fragmentu, dla którego chcesz ustawić dane

Fragment A

class MasterFragment : Fragment() {

    private val model: SharedViewModel by activityViewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        itemSelector.setOnClickListener { item ->
        model.select(item)
      }

    }
}

A potem po prostu nasłuchuj tej wartości w miejscu docelowym fragmentu

Fragment B.

 class DetailFragment : Fragment() {

        private val model: SharedViewModel by activityViewModels()

        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            model.selected.observe(viewLifecycleOwner, Observer<Item> { item ->
                // Update the UI
            })
        }
    }

Możesz też zrobić to w odwrotny sposób

Gastón Saillén
źródło
0

W 100% działające rozwiązanie: (jeśli ci pomożesz, nie zapomnij uderzyć w górę)

W swoim pierwszym fragmencie umieść ten fragment kodu:

    editprofile.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {

                    Fragment_editprofile Fragment = new Fragment_editprofile();
.
.
.
.
.


                Fragment.getintentdetails(tv_name.getText().toString(),
                            tv_mob.getText().toString(), tv_email.getText().toString(), tv_dob.getText().toString(),
                            tv_gender.getText().toString(), photointent);

                }
            });

W drugim fragmencie utwórz metodę jak poniżej:

public void getintentdetails(String name, String mobile, String email, String dob, String gender,
                                 String photointent) {

        this.name_str= name;
        this.mob_str= mobile;
        this.email_str= email;
        this.dob_str= dob;
        this.gender_str= gender;
        this.photo_str= photointent;

    }

następnie zdefiniuj zmienną na poziomie klasy:

String name_str, mob_str, dob_str, photo_str, email_str, gender_str;

następnie utwórz inną metodę w drugim fragmencie, aby ustawić wartość:

  setexistingdetails();


private void setexistingdetails() {

        if(!name_str.equalsIgnoreCase(""))
            (et_name).setText(name_str);
        if(!mob_str.equalsIgnoreCase(""))
            et_mobile.setText(mob_str);
        if(!email_str.equalsIgnoreCase(""))
            email_et.setText(email_str);
        if(!dob_str.equalsIgnoreCase(""))
            dob_et.setText(dob_str);
        if(!gender_str.equalsIgnoreCase("")){
            if (gender_str.equalsIgnoreCase("m")){
                male_radio.setChecked(true);
            }else {
                female_radio.setChecked(true);
            }
        }
        if(!photo_str.equalsIgnoreCase("")){
            try {
                Picasso.get().load(Const.BASE_PATH+"include/sub-domain/GENIUS/"+photo_str).into(adminpropic_edit);
            } catch (Exception e) {            }
        }
    }
Adil Siddiqui
źródło
0

Możesz osiągnąć swój cel za pomocą ViewModel i Live Data, które są usuwane przez Arnav Rao . Teraz podam przykład, aby wyjaśnić to dokładniej.

Najpierw zakładane ViewModeljest nazwane SharedViewModel.java.

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

Wtedy fragment źródłowy to ten, MasterFragment.javaz którego chcemy wysłać dane.

public class MasterFragment extends Fragment {
    private SharedViewModel model;

    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
        itemSelector.setOnClickListener(item -> {

            // Data is sent

            model.select(item);
        });
    }
}

I wreszcie fragment docelowy to miejsce, DetailFragment.javado którego chcemy odebrać dane.

public class DetailFragment extends Fragment {

    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        SharedViewModel model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
        model.getSelected().observe(getViewLifecycleOwner(), { item ->

           // Data is received 

        });
    }
}
Gk Mohammad Emon
źródło
0

OK, po tylu kopaniu tutaj znalazłem proste rozwiązanie, właściwie nigdy nie powinieneś przekazywać danych z fragmentu na fragment, to zawsze zły pomysł, możesz przekazać dane z fragmentu A do aktywności i pobrać dane z aktywności we fragmencie B.

For Example
//fragment A
//your method that will be called in Main Activity for getting data from this fragment
public List<customDataModel> getlist(){
return mlist; //your custom list 
}
buttonopen.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //before calling  your new fragment, send a Broadcast signal to your main activity
 mContext.sendBroadcast(new Intent("call.myfragment.action"));
//here you are now changing the fragment
Fragment fragment1 = new VolunteerListDetailsFragment();

            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            ft.replace(R.id.content_frame, fragment1);
            ft.commit();
        }
    });

// w głównym działaniu

this.registerReceiver(mBroadcastReceiver, new IntentFilter("call.myfragment.action"));//this line should be in your onCreate method
   BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {
//init the fragment A
FragmenA fragment =
                (FragmentA) getSupportFragmentManager().findFragmentById(R.id.content_frame);
        mlistdetails = fragment.getlist();//this is my method in fragmentA which is retuning me a custom list, init this list type in top of on create fragment


    }
};
//here you are creating method that is returning the list that you just recieved From fragmentA
public List<customDataModel> getcustomlist(){
return mlistdetails; //you are returning the same list that you recived from fragmentA
}

// teraz w FragmentB

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

    View rootView = (View) inflater.inflate(R.layout.vol_listdetails, container, false);

    mlistdetails=((MainActivity)getActivity()).getcustomlist();//here you are calling the method that you have created in Main Activity

    Toast.makeText(getActivity().getApplicationContext(), mlistdetails.get(0).getItemqty(), Toast.LENGTH_SHORT).show();
    return rootView;

}
Mubashir Murtaza
źródło
-2

stworzyłem coś naprawdę łatwego dla początkujących takich jak ja. utworzyłem przegląd tekstowy w moim pliku activity_main.xml i umieściłem

id=index
visibility=invisible

wtedy otrzymuję ten widok tekstu z pierwszego fragmentu

index= (Textview) getActivity().findviewbyid(R.id.index)
index.setText("fill me with the value")

a następnie w drugim fragmencie otrzymuję wartość

index= (Textview) getActivity().findviewbyid(R.id.index)
String get_the_value= index.getText().toString();

mam nadzieję, że to pomoże!

user7933515
źródło
Odpowiedź nie jest związana z zadanym pytaniem
Kanagalingam