如何在fragment_terminal中监听fragment_blank_fragment2的Test2按钮?
Hey there! The short answer is yes, you absolutely can listen to the Test2 button in BlankFragment2 from TerminalFragment—but your current approach isn’t working for a key reason. Let’s break down why, then walk through the proper ways to make this work.
The issue here is that you’re inflating fragment_blank_fragment2’s layout directly inside TerminalFragment, but this inflated view never gets attached to the app’s visible view hierarchy. The actual Test2 button users interact with belongs to a separate instance of BlankFragment2 that’s added to your activity (or parent fragment)—not the "ghost" view you created locally. So your click listener is attached to a view that’s never rendered, hence no response when you click the real button.
1. Use a Shared ViewModel (Google’s Preferred Method)
This keeps your fragments decoupled, as they communicate through a ViewModel scoped to their parent component (activity or parent fragment).
Step 1: Create the Shared ViewModel
import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel class SharedButtonViewModel : ViewModel() { private val _buttonClickEvent = MutableLiveData<String>() val buttonClickEvent: LiveData<String> = _buttonClickEvent fun triggerButtonClick(message: String) { _buttonClickEvent.value = message } }
Step 2: Update BlankFragment2 to Send Events
In BlankFragment2’s onViewCreated:
import androidx.fragment.app.viewModels class BlankFragment2 : Fragment() { // Get the ViewModel scoped to the parent activity private val sharedViewModel: SharedButtonViewModel by viewModels({ requireActivity() }) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) view.findViewById<Button>(R.id.test2).setOnClickListener { sharedViewModel.triggerButtonClick("Test2") } } }
Step 3: Observe Events in TerminalFragment
In TerminalFragment’s onViewCreated:
import androidx.fragment.app.viewModels import androidx.lifecycle.Observer class TerminalFragment : Fragment() { private val sharedViewModel: SharedButtonViewModel by viewModels({ requireActivity() }) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // Listen for button clicks from BlankFragment2 sharedViewModel.buttonClickEvent.observe(viewLifecycleOwner) { message -> send(message) } // Your existing Test button listener view.findViewById<Button>(R.id.test).setOnClickListener { send("Test") } } private fun send(message: String) { // Your send logic here } }
2. Use an Interface (Traditional Communication)
If you prefer a more explicit interface-based approach:
Step 1: Define a Listener Interface
interface ButtonClickListener { fun onButtonClicked(message: String) }
Step 2: Implement the Interface in the Parent Activity
class MainActivity : AppCompatActivity(), ButtonClickListener { override fun onButtonClicked(message: String) { // Pass the event to TerminalFragment val terminalFragment = supportFragmentManager.findFragmentById(R.id.terminal_fragment_container) as? TerminalFragment terminalFragment?.send(message) } }
Step 3: Trigger Events in BlankFragment2
class BlankFragment2 : Fragment() { private var listener: ButtonClickListener? = null override fun onAttach(context: Context) { super.onAttach(context) listener = context as? ButtonClickListener requireNotNull(listener) { "Parent activity must implement ButtonClickListener" } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) view.findViewById<Button>(R.id.test2).setOnClickListener { listener?.onButtonClicked("Test2") } } override fun onDetach() { super.onDetach() listener = null } }
Step 4: Update TerminalFragment
Ensure your TerminalFragment has the send function accessible:
class TerminalFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_terminal, container, false) view.findViewById<Button>(R.id.test).setOnClickListener { send("Test") } return view } fun send(message: String) { // Your send logic here } }
3. Direct Fragment Reference (Not Recommended)
While you can find BlankFragment2 via FragmentManager, this creates tight coupling between fragments and is fragile (depends on the fragment being already attached):
// In TerminalFragment's onViewCreated val blankFragment2 = parentFragmentManager.findFragmentById(R.id.blank_fragment2_container) as? BlankFragment2 blankFragment2?.view?.findViewById<Button>(R.id.test2)?.setOnClickListener { send("Test2") }
Stick to the ViewModel or interface methods for better maintainability.
内容的提问来源于stack exchange,提问作者Ari Gusti Satria

