You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跨Fragment传递数据:从FragmentA向FragmentB的RecyclerView传对象

解决Fragment切换时传递数据到新建Fragment的问题

Hey, I get exactly what's going on here! You're right to suspect the root cause is the fact that every BottomNavigation switch creates a brand new instance of FragmentA and FragmentB. When you tried using an interface, the FragmentB reference you had in FragmentA was already the old, destroyed one—so the data never made it to the currently displayed FragmentB.

Let's fix this with two solid approaches, depending on your project's needs:


Approach 1: Use MainActivity as a Middleman (Quick & Simple)

This is the most straightforward fix for your current setup. We'll have MainActivity temporarily hold the data, then pass it to the new FragmentB instance when switching.

Step 1: Update MainActivity

Modify your navigation logic to store the pending object and pass it via a Bundle when creating FragmentB:

// Temporarily store the object we need to pass to FragmentB
private CustomObject pendingCustomObject;

private BottomNavigationView.OnNavigationItemSelectedListener navListener = new BottomNavigationView.OnNavigationItemSelectedListener() {
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
        Fragment selectedFragment = null;
        switch (menuItem.getItemId()) {
            case R.id.nav_a:
                selectedFragment = new FragmentA();
                break;
            case R.id.nav_b:
                selectedFragment = new FragmentB();
                // If we have a pending object, pass it via Bundle
                if (pendingCustomObject != null) {
                    Bundle bundle = new Bundle();
                    // Important: CustomObject MUST implement Serializable or Parcelable!
                    bundle.putSerializable("selected_item", pendingCustomObject);
                    selectedFragment.setArguments(bundle);
                    // Clear the pending object so we don't re-add it later
                    pendingCustomObject = null;
                }
                break;
        }
        getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, selectedFragment).commit();
        return true;
    }
};

// Method for FragmentA to call when it wants to pass data
public void setPendingCustomObject(CustomObject obj) {
    this.pendingCustomObject = obj;
    // Automatically switch to FragmentB so the user sees the update immediately
    bottomNavigationView.setSelectedItemId(R.id.nav_b);
}

Step 2: Update FragmentA's Click Listener

Call MainActivity's method to pass the selected object:

adapter.setOnItemClickListener(new RewardItemAdapter.OnItemClickListener() {
    @Override
    public void onItemClick(int position) {
        CustomObject theItem = items.get(position);
        // Make sure we're attached to MainActivity before calling the method
        if (getActivity() instanceof MainActivity) {
            ((MainActivity) getActivity()).setPendingCustomObject(theItem);
        }
    }
});

Step 3: Update FragmentB to Receive Data

Modify onCreateView to check for the passed Bundle and update the list:

public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_b, container, false);
    itemsList = new ArrayList<>();

    // Check if we received a passed object
    Bundle bundle = getArguments();
    if (bundle != null) {
        CustomObject selectedItem = (CustomObject) bundle.getSerializable("selected_item");
        if (selectedItem != null) {
            itemsList.add(selectedItem);
        }
    }

    // Add default data only if the list is empty
    if (itemsList.isEmpty()) {
        itemsList.add(new CustomObject(R.drawable.picture, "Text", "More text.", 200));
    }

    // Set up RecyclerView as before
    recyclerView = v.findViewById(R.id.fragmentBRecyclerView);
    recyclerView.setHasFixedSize(true);
    layoutManager = new LinearLayoutManager(getContext());
    adapter = new FragmentBItemAdapter(itemsList);
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setAdapter(adapter);
    return v;
}

Important Note:

Your CustomObject class needs to implement Serializable (easy for simple objects) or Parcelable (better for performance with complex objects). Here's how to add Serializable:

public class CustomObject implements Serializable {
    // Your existing fields, constructors, getters, and setters go here
}

If you're using Android Jetpack, a ViewModel is the cleanest way to share data between fragments—it survives configuration changes and fragment recreation.

Step 1: Create a Shared ViewModel

import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

public class SharedViewModel extends ViewModel {
    // LiveData holds the selected object and notifies observers when it changes
    private MutableLiveData<CustomObject> selectedItem = new MutableLiveData<>();

    public void selectItem(CustomObject item) {
        selectedItem.setValue(item);
    }

    public MutableLiveData<CustomObject> getSelectedItem() {
        return selectedItem;
    }
}

Step 2: Update FragmentA's Click Listener

Get the ViewModel and set the selected item, then switch to FragmentB:

adapter.setOnItemClickListener(new RewardItemAdapter.OnItemClickListener() {
    @Override
    public void onItemClick(int position) {
        CustomObject theItem = items.get(position);
        // Get the shared ViewModel using the activity scope
        SharedViewModel viewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
        viewModel.selectItem(theItem);
        // Trigger the switch to FragmentB
        requireActivity().findViewById(R.id.nav_b).performClick();
    }
});

Step 3: Update FragmentB to Observe Data

Watch the ViewModel for changes and update the RecyclerView when new data comes in:

public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_b, container, false);
    itemsList = new ArrayList<>();
    itemsList.add(new CustomObject(R.drawable.picture, "Text", "More text.", 200));

    // Set up RecyclerView
    recyclerView = v.findViewById(R.id.fragmentBRecyclerView);
    recyclerView.setHasFixedSize(true);
    layoutManager = new LinearLayoutManager(getContext());
    adapter = new FragmentBItemAdapter(itemsList);
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setAdapter(adapter);

    // Observe the shared ViewModel for new items
    SharedViewModel viewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
    viewModel.getSelectedItem().observe(getViewLifecycleOwner(), customObject -> {
        if (customObject != null) {
            itemsList.add(customObject);
            adapter.notifyItemInserted(itemsList.size() - 1);
            // Clear the value to avoid re-adding the same item if FragmentB is recreated
            viewModel.selectItem(null);
        }
    });

    return v;
}

Which Approach Should You Choose?

  • Approach 1 is perfect for small, simple projects where you don't want to add extra dependencies or complexity.
  • Approach 2 follows Android's recommended architecture practices, avoids lifecycle headaches, and scales better if your app grows more complex.

内容的提问来源于stack exchange,提问作者Mark Denom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 03:51:03