How to send data from one Fragment to another Fragment?

1

I have created an application where I create 3 Fragments which I visualize with tabs and I want to send information from one fragment to another .. but I do not know what I'm wrong with as it does not mark a code error, but when I click on it button to send the application stops.

  • PrimerFragment
    • displays only a few CardView,
  • secondFragment
    • 2 EditText and a send button to send to TercerFragment
  • ThirdFragmetn
    • ListView to receive data from the secondFragment
  • SegundoBlankFragment Class

    @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            View view = inflater.inflate(R.layout.fragment_segundo_blank, container, false);
    
            editText1 = view.findViewById(R.id.editTex1);
            editText2 = view.findViewById(R.id.editTex2);
            btn1 = view.findViewById(R.id.btnGuardar);
    
            btn1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    createNewPerson();
                }
            });
            return view;
        }
    
    private void createNewPerson() {
            if (!editText1.getText().toString().isEmpty()) {
                Temp person = new Temp(editText1.getText().toString(), editText2.getText().toString() );
                Tem2.createPerson(person);
            }
        }
    

    Interface class Tem2 which only refers to the class Temp 2 that only has 2 String text1 and text2 with its respective constructor, gets and sets

    public interface Tem2 {
        void createPerson(Temp person);
    }
    

    TercerFragment class where you are supposed to display a list of items sent from the ThirdFragment

    private List<Temp> persons;
    private ListView listView;
    private adapterTemp adapter;
    
     @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            View view =inflater.inflate(R.layout.fragment_tercer_blank, container, false);
            persons = new ArrayList<Temp>();
            listView = (ListView) view.findViewById(R.id.listViewPerson);
            adapter = new adapterTemp(getContext(),R.layout.list_view_temp, persons);
            listView.setAdapter(adapter);
            return view;
        }
    
    public void addPerson(Temp person) {
            this.persons.add(person);
            adapter.notifyDataSetChanged();
        }
    

    logcat

    java.lang.ClassCastException: com.yordy.richard.calculadora.SegundoBlankFragment cannot be cast to com.yordy.richard.calculadora.TercerBlankFragment
    
    at com.yordy.richard.calculadora.MainActivity.createPerson(MainActivity.java:111)
            at com.yordy.richard.calculadora.SegundoBlankFragment.createNewPerson(SegundoBlankFragment.java:59)
            at com.yordy.richard.calculadora.SegundoBlankFragment.access$000(SegundoBlankFragment.java:19)
            at com.yordy.richard.calculadora.SegundoBlankFragment$1.onClick(SegundoBlankFragment.java:46)
    

    On line 111 of the MainActivity it follows it

    TercerBlankFragment fragment = (TercerBlankFragment) getSupportFragmentManager().getFragments().get(PERSON_LIST_FRAGMENT);
    

    what is inside the get is

    public static final int PERSON_LIST_FRAGMENT = 1;
    

    Class Pageadapter

    private int numberOfTabs;
    
        public PageAdapter(FragmentManager fm, int numberOfTabs) {
            super(fm);
            this.numberOfTabs = numberOfTabs;
        }
    
        @Override
        public Fragment getItem(int i) {
            switch (i){
                case 0:
                    return new PrimerBlankFragment();
                case 1:
                    return new SegundoBlankFragment();
                case 2:
                    return new TercerBlankFragment();
                    default:
                        return null;
            }
        }
    
        @Override
        public int getCount() {
            return numberOfTabs;
        }
    }
    
        
    asked by Richard Yordy 14.10.2018 в 19:53
    source

    1 answer

    4

    The communication between Fragments that depend on a Activity must be done through Activity and not directly.

    For communication between Fragment and Activity , although it can be done through casting getActivity() in Fragment to the class of Activity (for example MainActivity ) the recommended form of doing so is through interfaces , which use Fragments to make callbacks to Activity , and in turn, Activity implements them to respond to Fragments .

    This would cover the basics of communication, down a little more on the subject.

    Then we have that the app uses ViewPager to show the different Fragments of the app. ViewPager has two things to keep in mind:

    1) Manage the life cycle of the Fragments . That is to say that based on the% or% of% that we spent when we initialized it, it stays with the class, and then it kills, it creates, and it replaces instances as it suits it. This brings a complexity if we want at some point to be able to invoke something about the Fragments given that if we keep an instance for later, it may not be the same one that is shown on the screen in a while.

    2) The Fragment prepares the ViewPager in advance before the Views is visible, so if we depend on for example Fragment to show some updated data, that onResume() can be called when maybe they are not even given the conditions to be able to calculate the update of the screen.

    To solve point 1, instead of trying to keep an instance of the onResume() when creating them for the first time, in the adapter, we make a Fragments of the method override , which is called when the instantiateItem creates a new instance of our ViewPager , and taking the new instance we replace the previous one in our reference.

    The second point is solved using Fragment which is a Fragment method and is called by the setUserVisibleHint(boolean) with ViewPager when it will be displayed on the screen. So we take advantage of this call back to do the last minute updates before Fragment is shown. (Supposedly this method is called correctly, in previous varsiones it could be called with the activity in null and it was necessary to do some extra checks).

    Returning to the topic of communication between Activity and Fragment. When it is the true that sends something to Fragment of the user, and assuming that it is interactively with the screen, there are no major problems because the Activity is working and the Activity as well. When it is the Fragment that would have to send something to Activity the problem arises that the Fragment may not be ready when the Fragment wants to send a message. So the way I solve it is to make the Activity request the data to Fragment when the Activity is ready to receive it (and in any case you can also verify that the Activity tabmién is ready to send it).

    Below is an example of all this:

    Layouts:

    Fragment One

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <TextView
            android:id="@+id/tvTitle"
            android:layout_alignParentTop="true"
            android:layout_alignParentStart="true"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Soy Fragment 1"/>
        <Button
            android:id="@+id/btnEnviar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/tvTitle"
            android:text="Enviar Fecha a Fragment 2"/>
    
    </RelativeLayout>
    

    Fragment Two

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <TextView
            android:id="@+id/tvTitle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_alignParentLeft="true"
            android:text="Soy Fragment 2"/>
        <TextView
            android:id="@+id/tvHoraActual"
            android:layout_below="@id/tvTitle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
    </RelativeLayout>
    

    Main Activity

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
        <android.support.design.widget.TabLayout
            android:id="@+id/tabs"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_width="match_parent"
            android:layout_height="25dp">
        </android.support.design.widget.TabLayout>
        <android.support.v4.view.ViewPager
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            app:layout_constraintTop_toBottomOf="@id/tabs"
            app:layout_constraintBottom_toBottomOf="parent"
            >
        </android.support.v4.view.ViewPager>
    </android.support.constraint.ConstraintLayout>
    

    Java

    Main Activity

    import android.support.design.widget.TabLayout;
    import android.support.v4.app.Fragment;
    import android.support.v4.view.ViewPager;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    
    public class MainActivity extends AppCompatActivity
        implements FragmentUno.FragmentUnoListener, FragmentDos.FragmentDosListener {
    
        private String laFechaActualSegunFragment1;
        private ViewPager viewPager;
        private MyViewPagerAdapter viewPagerAdapter;
        private TabLayout tabs;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
    
    
            viewPagerAdapter = new MyViewPagerAdapter(getSupportFragmentManager());
    
            Fragment fragmentUno = new FragmentUno();
            viewPagerAdapter.addFragment(fragmentUno,"Frag Uno");
            Fragment fragmentDos = new FragmentDos();
            viewPagerAdapter.addFragment(fragmentDos,"Frag Dos");
    
            tabs = findViewById(R.id.tabs);
            tabs.addTab(tabs.newTab().setText(viewPagerAdapter.getPageTitle(0)),0);
            tabs.addTab(tabs.newTab().setText(viewPagerAdapter.getPageTitle(1)),1);
    
    
            tabs.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
               @Override
               public void onTabSelected(TabLayout.Tab tab) {
                   viewPager.setCurrentItem(tab.getPosition());
               }
               @Override
               public void onTabUnselected(TabLayout.Tab tab) {}
    
               @Override
               public void onTabReselected(TabLayout.Tab tab) {}
           });
    
            viewPager = findViewById(R.id.viewPager);
            viewPager.setAdapter(viewPagerAdapter);
            viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabs));
        }
    
        @Override
        public void onFechaActualIngresada(String horaActual) {
            this.laFechaActualSegunFragment1 = horaActual;
            viewPager.setCurrentItem(1,true);
        }
    
        @Override
        public String getHoraActual() {
            return this.laFechaActualSegunFragment1;
        }
    }
    

    ViewPager Adapter

    import android.support.v4.app.Fragment;
    import android.support.v4.app.FragmentManager;
    import android.support.v4.app.FragmentStatePagerAdapter;
    import android.view.ViewGroup;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    
    public class MyViewPagerAdapter extends FragmentStatePagerAdapter {
    
        protected final List<Fragment> fragmentList = new ArrayList<>();
        protected final List<String> fragmentTitleList = new ArrayList<>();
        protected final HashMap<Integer,Fragment> currentInstances = new HashMap<>();
        protected FragmentManager fm;
    
        public MyViewPagerAdapter(FragmentManager manager) {
            super(manager);
            this.fm = manager;
        }
    
        @Override
        public Fragment getItem(int position) {
            return fragmentList.get(position);
        }
    
        @Override
        public int getCount() {
            return fragmentList.size();
        }
    
        public void addFragment(Fragment fragment, String title) {
            fragmentList.add(fragment);
            fragmentTitleList.add(title);
        }
    
        @Override
        public int getItemPosition(Object object) {
            return POSITION_NONE;
        }
    
        @Override
        public CharSequence getPageTitle(int position) {
            return fragmentTitleList.get(position);
        }
    
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
            currentInstances.put(position, createdFragment);
            return createdFragment;
        }
    
        public Fragment getCurrentIntance(int position){
            return currentInstances.get(position);
        }
    }
    

    Fragment One (The one that sends a data to Fragment Two)

    import android.content.Context;
    import android.os.Bundle;
    import android.support.annotation.NonNull;
    import android.support.annotation.Nullable;
    import android.support.v4.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.Button;
    
    import java.util.Date;
    
    public class FragmentUno extends Fragment {
    
        private Button btnEnviar;
        private FragmentUnoListener listener;
    
        @Override
        public void onAttach(Context context) {
            super.onAttach(context);
            if(context instanceof FragmentUnoListener){
                this.listener = (FragmentUnoListener) context;
            }
        }
    
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
        }
    
        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            View viewRoot = inflater.inflate(R.layout.demo_fragment1_layout,null);
            btnEnviar = viewRoot.findViewById(R.id.btnEnviar);
            btnEnviar.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    String fechaActual = new Date(System.currentTimeMillis()).toString();
                    listener.onFechaActualIngresada(fechaActual);
                }
            });
            return viewRoot;
        }
    
        public static interface FragmentUnoListener{
            public void onFechaActualIngresada(String horaActual);
        }
    }
    

    Fragment Two (The one that receives a data entered from Fragment One)

    import android.content.Context;
    import android.os.Bundle;
    import android.support.annotation.NonNull;
    import android.support.annotation.Nullable;
    import android.support.v4.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.TextView;
    
    public class FragmentDos extends Fragment {
    
        private FragmentDosListener listener;
    
        TextView tvHoraActual;
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
        }
    
        @Override
        public void onAttach(Context context) {
            super.onAttach(context);
            if(context instanceof  FragmentDosListener){
                this.listener = (FragmentDosListener) context;
            }
        }
    
        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            View viewRoot = inflater.inflate(R.layout.demo_fragment2_layout,null);
    
            tvHoraActual = viewRoot.findViewById(R.id.tvHoraActual);
    
            return viewRoot;
        }
    
        @Override
        public void setUserVisibleHint(boolean isVisibleToUser) {
            super.setUserVisibleHint(isVisibleToUser);
            if(isVisibleToUser){
                String horaActual = listener.getHoraActual();
                tvHoraActual.setText(horaActual);
            }
        }
    
        public static interface FragmentDosListener{
            public String getHoraActual();
        }
    }
    
        
    answered by 15.10.2018 / 03:48
    source