एंड्रॉइड में फ्रैगमेंट-टू-फ्रैगमेंट संचार
फ्रैगमेंट्स को एक-दूसरे से सीधे बात नहीं करनी चाहिए। अनुशंसित पैटर्न: **शेयर्ड ViewModel** (आर्किटेक्चर कंपोनेंट्स) या **इंटरफेस कॉलबैक** होस्ट गतिविधि के माध्यम से। दोनों दृष्टिकोण यहां दिखाए गए हैं।
दृष्टिकोण 1 - शेयर्ड ViewModel (पसंदीदा, जीवनचक्र-जागरूक)
ViewModel
public class SharedViewModel extends ViewModel {
private final MutableLiveData message = new MutableLiveData<>();
public void sendMessage(String msg) { message.setValue(msg); }
public LiveData getMessage() { return message; }
}
फ्रैगमेंट A (प्रेषक)
public class SenderFragment extends Fragment {
private SharedViewModel vm;
private EditText etInput;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saved) {
View v = inflater.inflate(R.layout.fragment_sender, container, false);
etInput = v.findViewById(R.id.etInput);
v.findViewById(R.id.btnSend).setOnClickListener(view -> {
String txt = etInput.getText().toString();
if (!txt.isEmpty()) vm.sendMessage(txt);
});
return v;
}
@Override
public void onViewCreated(@NonNull View view, Bundle saved) {
super.onViewCreated(view, saved);
vm = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
}
}
फ्रैगमेंट B (प्राप्तकर्ता)
public class ReceiverFragment extends Fragment {
private TextView tvMessage;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saved) {
return inflater.inflate(R.layout.fragment_receiver, container, false);
}
@Override
public void onViewCreated(@NonNull View view, Bundle saved) {
super.onViewCreated(view, saved);
tvMessage = view.findViewById(R.id.tvMessage);
SharedViewModel vm = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
vm.getMessage().observe(getViewLifecycleOwner(), msg -> tvMessage.setText("प्राप्त: " + msg));
}
}
दृष्टिकोण 2 - इंटरफेस कॉलबैक (लीगेसी/सरल मामले)
इंटरफेस
public interface OnFragmentMessageListener {
void onMessageReceived(String message);
}
फ्रैगमेंट A
public class SenderFragment extends Fragment {
private OnFragmentMessageListener listener;
private EditText etInput;
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
if (context instanceof OnFragmentMessageListener) {
listener = (OnFragmentMessageListener) context;
} else {
throw new ClassCastException("होस्ट को OnFragmentMessageListener लागू करना होगा");
}
}
@Override
public void onDetach() {
super.onDetach();
listener = null;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saved) {
View v = inflater.inflate(R.layout.fragment_sender, container, false);
etInput = v.findViewById(R.id.etInput);
v.findViewById(R.id.btnSend).setOnClickListener(view -> {
if (listener != null) listener.onMessageReceived(etInput.getText().toString());
});
return v;
}
}
गतिविधि (मध्यस्थ)
public class MainActivity extends AppCompatActivity implements OnFragmentMessageListener {
@Override
protected void onCreate(Bundle saved) {
super.onCreate(saved);
setContentView(R.layout.activity_main); // दोनों फ्रैगमेंट्स वाला लेआउट
}
@Override
public void onMessageReceived(String message) {
ReceiverFragment receiver = (ReceiverFragment) getSupportFragmentManager()
.findFragmentById(R.id.receiverFragment);
if (receiver != null) receiver.updateMessage(message);
}
}
फ्रैगमेंट B
public class ReceiverFragment extends Fragment {
private TextView tvMessage;
@Override public View onCreateView(LayoutInflater inf, ViewGroup c, Bundle s) {
return inf.inflate(R.layout.fragment_receiver, c, false);
}
@Override public void onViewCreated(View v, Bundle s) {
tvMessage = v.findViewById(R.id.tvMessage);
}
public void updateMessage(String msg) { tvMessage.setText("प्राप्त: " + msg); }
}
तुलना
| पहलू | शेयर्ड ViewModel | इंटरफेस कॉलबैक |
|---|---|---|
| डिकॉउपलिंग | उच्च (फ्रैगमेंट्स एक-दूसरे को नहीं जानते) | मध्यम (गतिविधि मध्यस्थ है) |
| कॉन्फिग परिवर्तन पर जीवित रहता है | हां | नहीं (मैन्युअल हैंडलिंग आवश्यक) |
| बैक स्टैक सुरक्षित | हां | नाजुक (फ्रैगमेंट नष्ट हो सकता है) |
| बॉयलरप्लेट | कम | मध्यम |
लेआउट (गतिविधि)
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<fragment
android:id="@+id/senderFragment"
android:name="com.example.SenderFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<fragment
android:id="@+id/receiverFragment"
android:name="com.example.ReceiverFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
</LinearLayout>
सर्वोत्तम अभ्यास
- नए ऐप्स के लिए **शेयर्ड ViewModel** का उपयोग करें — यह जीवनचक्र, बैक स्टैक और प्रक्रिया पुनर्निर्माण को संभालता है।
- सरल, अल्पकालिक इवेंट्स के लिए जहां ViewModel ओवरकिल है, **इंटरफेस** का उपयोग करें।
- कभी भी
getFragmentManager().findFragmentById()पर भरोसा न करें और सीधे दूसरे फ्रैगमेंट पर विधियों को कॉल न करें — यह टाइट कपलिंग और क्रैश का कारण बनता है। - नेविगेशन कंपोनेंट का उपयोग कर रहे हैं?
NavController+getBackStackEntry()के माध्यम से शेयर्ड ViewModel को स्कोप करें।
मूल उदाहरण की समीक्षा
मूल कोड गतिविधि में एक इंटरफेस का उपयोग करता था लेकिन onAttach में कास्टिंग, नल-सुरक्षा की कमी, और प्राप्तकर्ता फ्रैगमेंट पर एक सार्वजनिक विधि onFragmentInteraction थी। ऊपर दिए गए ViewModel दृष्टिकोण को प्राथमिकता दें।