Ank
Ank

Reputation: 31

Passing data between fragment with calling value not reference

I'm trying to pass MyData(Parcelable object including ArrayList) from AFragment to BFragment. Certainly,it works.However, the reference of ArrayList is same.

I've looked at various articles about Parcelable,and finally I found out that Parcelable recreate instance only when two objects is in different task.

How can I pass data with primitive type not reference type?

I wrote codes like below.

MyData:

public class MyData implements Parcelable {

public List<String> mList = new ArrayList<>(0);

@Override
public int describeContents() {
    return 0;
}

@Override
public void writeToParcel(Parcel out, int flags) {
    out.writeStringList(mList);
}

public static final Parcelable.Creator<MyData> CREATOR = new Parcelable.Creator<MyData>() {
    public MyData createFromParcel(Parcel in) {
        return new MyData(in);
    }

    public MyData[] newArray(int size) {
        return new MyData[size];
    }
};

private MyData(Parcel in) {
    in.writeStringList(mList);
}

public MyData() {
}
}

MainActivity:

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    SampleFragment sampleFragment = new SampleFragment();
    replaceFragment(sampleFragment);
}

public void replaceFragment(Fragment fragment) {
    FragmentManager manager = getSupportFragmentManager();

    if (manager.findFragmentByTag(fragment.getClass().getCanonicalName()) != null) {
        return;
    }
    FragmentTransaction transaction = manager.beginTransaction();
    transaction.replace(R.id.container_layout, fragment, fragment.getClass().getCanonicalName());
    transaction.addToBackStack(null);
    transaction.commit();
}
}

AFragment:

public class SampleFragment extends Fragment implements View.OnClickListener {

MainActivity mActivity;

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    mActivity = (MainActivity) context;
}

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

@Nullable
@Override
public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.sample1, container, false);
    view.findViewById(R.id.button).setOnClickListener(this);
    return view;
}

@Override
public void onClick(View v) {
    int id = v.getId();
    if (id == R.id.button) {
        List<String> list = new ArrayList<>(0);
        list.add("sample1");
        list.add("sample2");
        list.add("sample3");
        HogeData data = new HogeData();
        data.mList = list;
        SampleFragment2 sampleFragment2 = new SampleFragment2();
        Bundle bundle = new Bundle();
        bundle.putParcelable(sampleFragment2.getClass().getCanonicalName(), data);
        sampleFragment2.setArguments(bundle);
        mActivity.replaceFragment(sampleFragment2);
    }
}
}

BFragment:

public class SampleFragment2 extends Fragment {

MainActivity mActivity;
HogeData mData;

@Override
public void onAttach(Context context) {
    super.onAttach(context);
    mActivity = (MainActivity) context;
}

@Override
public void onCreate(@Nullable final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Bundle bundle = getArguments();
    mData = bundle.getParcelable(getClass().getCanonicalName());
}

@Nullable
@Override
public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) {
    return inflater.inflate(R.layout.sample2, container, false);
}

The Problem is that when I pass data(MyData) from AFragment to BFragment, the reference of arraylist(mList) is the same. This causes when I change value of mList in BFragment, Value of mList in AFragment changes as well. I have no idea to resolve the problem.

Upvotes: 0

Views: 108

Answers (2)

Ailton Ramos
Ailton Ramos

Reputation: 106

From Google Developers website:

Often you will want one Fragment to communicate with another, for example to change the content based on a user event. All Fragment-to-Fragment communication is done through the associated Activity. Two Fragments should never communicate directly.

A good practice is send data to an Activity through a interface. The Activity will receive data and should be able to send data to the second fragment through a method.

Please read this and this.

Upvotes: 2

GreenROBO
GreenROBO

Reputation: 4910

Fragment fragmentGet1 = new FragmentGet1();
Fragment fragmentGet2 = new FragmentGet2();
Fragment fragmentGet2 = new FragmentGet3();

fragmentGet1.setArguments(bundle);
fragmentGet2.setArguments(bundle);
fragmentGet3.setArguments(bundle);

You can create instances of all the 3 fragments, but then only using the instance of FragmentGet1. The other ones are not used. Later, when you create another instance of any of those Fragments, it will not have the args because it is a totally separate object.

That you need is to pass the bundle forward each time you create a new Fragment. If you want to create it from within an already-created fragment, it will look somewhat like this:

public void showNextFragment() {

    FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

    Fragment fragmentGet2 = new FragmentGet2();

    if(this.getArguments() != null)
        fragmentGet2.setArguments(this.getArguments());

    fragmentTransaction.replace(R.id.frame_container, fragmentGet2);
    fragmentTransaction.addToBackStack(null);
    fragmentTransaction.commit();

}

Example

To pass the Student object to an Activity, just do something like this:

Student s = //get it here
Bundle b = new Bundle();
b.putParcelable("student", s);

Intent i = new Intent(getActivity(), ThatOtherActivity.class);
i.putExtra("extraWithStudent", b);
startActivity(i);

And then to read the data in the Activity:

Intent incomingIntent = getIntent();
Bundle b = incomingIntent.getBundleExtra("extraWithStudent");
Student s = (Student) b.getParcelable("student");
s

Upvotes: 0

Related Questions