0

How do you pass data between Fragments.

I've created a InstructionActivity, InstructionsFragment, StepsFragment and SharedViewModel. I'm trying to pass String from InstructionsFragment to the StepsFragment

this the result in my logCat:

D/StepsFragment:THIS com.shawn.nichol.bakingapp.Fragments.SharedViewModel@23e39c0

I have also put the whole code up on GitHub.

SharedViewModel:

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

public void setStepPosition(String position) {
    stepPosition.setValue(position);
}

public MutableLiveData getStepPosition() {
    return stepPosition;
}
}

InstructionsFragment:

public class InstructionsFragment extends Fragment {
private static final String LOGTAG = "InstructionsFragment";

private RecyclerView mRecyclerView;
private InstructionsAdapter mAdapter;

private String mAllIngredients;

private SharedViewModel model;

// Empty constructor
public InstructionsFragment() {
}



public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle onSavedInstanceState) {

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

    model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);

    mRecyclerView = (RecyclerView) view.findViewById(R.id.ingredients_instructions_rv_fragments);

    mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

    mRecyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity().getApplicationContext(),
            mRecyclerView, new RecyclerTouchListener.ClickListener() {

        @Override
        public void onClick(View view, int position) {
            Log.d(LOGTAG, "Step " + (position + 1) + " " +
                    InstructionsExtractSteps.stepsShortDescriptionList.get(position));

            model.setStepPosition("HELP");




            FragmentManager mFragmentManager = getFragmentManager();

            StepsFragment mStepsFragment = new StepsFragment();

            FragmentTransaction mFragmentTransaction = mFragmentManager.beginTransaction();
            mFragmentTransaction
                    .replace(R.id.instructions_place_holder, mStepsFragment)
                    // Puts InstructionsFragment on back stack, when back button is press it will
                    // reload that fragment instead of going back to the RecipeActivity.
                    .addToBackStack(null)
                    .commit();
        }

        @Override
        public void onLongClick(View view, int position) {

        }
    }));

    mAdapter = new InstructionsAdapter();
    mRecyclerView.setAdapter(mAdapter);

    return view;
}

/**
 * onViewCreated: I found this to be the only way to update the TextView in fragment_instructions.xml
 *
 * @param view
 * @param savedInstanceState
 */
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState){
    TextView mLoadIngredients = (TextView)getView().findViewById(R.id.ingredients_tv_fragment);

    // Set ingredients to screen
    for(int i = 0; i < InstructionsExtractIngredients.ingredientList.size(); i++) {
        if(i == 0) {
            mAllIngredients = "- " + InstructionsExtractIngredients.ingredientList.get(i);
        } else {
            mAllIngredients = mAllIngredients + "\n - " + InstructionsExtractIngredients.ingredientList.get(i);
        }
    }
    Log.d(LOGTAG, mAllIngredients);
    mLoadIngredients.setText(mAllIngredients);
}
}

StepsFragment:

public class StepsFragment extends Fragment {
private static final String LOGTAG = "StepsFragment";

// Requires an empty constructor
public StepsFragment() {
}


public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_step, container, false);

    final SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);

    model.getStepPosition();

    Log.d(LOGTAG, "THIS " + model);

    return view;
}
}
Milad Bahmanabadi
  • 946
  • 11
  • 27
Shawn
  • 1,222
  • 1
  • 18
  • 41
  • There are multiple, different solutions in the answers on that question. Which one are you saying is deprecated? The interface solution certainly is not deprecated. – Mike M. Dec 16 '18 at 22:27
  • Now I'm confused, I could have sworn I read that in comments for the correct answer on that question. I guess I've just been at this problem for so long that I'm confusing different answers. – Shawn Dec 16 '18 at 22:30
  • 1
    Well, if you're having trouble implementing the solution outlined in those developer pages linked in the accepted answer, you should edit your question to provide the details for that, rather than have someone reiterate the generic solution here. – Mike M. Dec 16 '18 at 22:33
  • That's a good point, I'll update my question to reflect the problem that I'm having with the code. – Shawn Dec 16 '18 at 22:36
  • What is the actual question? You seem to have everything in place to share the data. The answer is "with a shared ViewModel" but you are already using it. – Richard Le Mesurier Dec 17 '18 at 05:35
  • How do I pass data from the InstructionFragment to the stepsFragment, The view modes is passing the following ** com.shawn.nichol.bakingapp.Fragments.SharedViewModel@23e39c0** instead of a String – Shawn Dec 17 '18 at 05:55

2 Answers2

2

you can use interfaces to allow communications between two fragment and its not deprecated

however a better alternative option is to use Architecture Components

just add the following libraries to your app gradle file

implementation 'android.arch.lifecycle:extensions:1.1.1'
implementation 'android.arch.lifecycle:runtime:1.1.1'

and then create the following class as shown below

import android.arch.lifecycle.ViewModel;
import android.support.annotation.NonNull;

public class TestViewModel extends ViewModel {

private MutableLiveData<String> fragmentAClicked;

public LiveData<String> getFragmentAClicked() {
       if (fragmentAClicked == null) {
              fragmentAClicked = new MutableLiveData<String>(); 
       }
                return fragmentAClicked;
}

public void fragmentAIsClicked(){
           fragmentAClicked.setValue("I am clicked")
}

}

in your activity class add the following code

public class MyActivity extends AppCompatActivity {
     TestViewModel model;
     public void onCreate(Bundle savedInstanceState) {

        model = ViewModelProviders.of(this).get(TestViewModel.class);

     }
    }

suppose you have two fragments A and B

public class FragmentB extends Fragment {
    private TestViewModel model;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        model =ViewModelProviders.of(getActivity()).get(TestViewModel.class);

        //communicating with fragment  
        model.fragmentAIsClicked();
    }
}

public class FragmentA extends Fragment {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TestViewModel model = ViewModelProviders.of(getActivity()).get(TestViewModel.class);
        model.getFragmentAClicked().observe(this, { msg ->
           Log.d("test","message from fragmentA is " + msg)
        });
    }
}

so basically the idea is that you a viewmodel class based on mvvm design pattern which handles all communication between activities ,fragments using events

for more info check this viewmodel

has19
  • 1,307
  • 16
  • 31
  • In FragmentA Log.d("test","message from fragmentA is " + item), I get error from item, should it be Item (With a caps)? – Shawn Dec 17 '18 at 00:30
  • in FragmentA there is an item in Log.d("test","message from fragmentA is " + item), I get a cannot resolve symbol what em I suppose to do with it. – Shawn Dec 17 '18 at 00:32
0

I don't know what is your purpose but you can use a POJO class to pass between fragment.

public class Test {
    public static class FragmentScanIDGInfo {
        public String getLastName() { return lastName; }
        public void setLastName(String lastName) { this.lastName = lastName; }

        public String getFirstName() { return firstName; }
        public void setFirstName(String firstName) { this.firstName = firstName; }

        String lastName = "";
        String firstName = "";

        public static FragmentScanIDGInfo shared;
        public static FragmentScanIDGInfo sharedSingleton() {
            if (shared == null) {
                shared = new FragmentScanIDGInfo();
            }
            return shared;
        }

        FragmentScanIDGInfo() {
            this.setLastName("");
            this.setFirstName("");
        }
    }
}

And you can set and get in your own purpose like :

Test.FragmentScanIDGInfo scanDataFragment = Test.FragmentScanIDGInfo.sharedSingleton();
scanDataFragment.setFirstName(""); /* set data first name */
scanDataFragment.getFirstName();   /* get data first name */
MrX
  • 953
  • 2
  • 16
  • 42