Evan Bain
Evan Bain

Reputation: 59

Change activity's button state from fragment

Here I have code from both my activity and my fragment:

Activity:

class Activity0: AppCompatActivity() {
   private lateinit var binding: Activity0Binding
   override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)                                    
      binding = Activity0Binding.inflate(layoutInflater)
      setContentView(binding.root)

      binding.popUpButton.setOnClickListener {
        supportFragmentManager.commit {
            replace(R.id.quiz_fragment_container, Activity0FragmentNull())
        }
        binding.popUpButton.isEnabled = false
      }
   }
}

Fragment:

class Activity0FragmentNull : Fragment() {
   ...
   override fun onCreateView(
     inflater: LayoutInflater, container: ViewGroup?,
     savedInstanceState: Bundle?
   ): View? {
       Activity0().popUpButton.isEnabled = true
       return inflater.inflate(R.layout.activity0_null, container, false)
   }
   ...
}

Here I am trying to change the state of my button to be enabled whenever the fragment is launched. However, whenever my fragment is run the app crashes and returns to the main activity (start of the app). How come trying to reach a button in my activity from my fragment is causing the app to crash. Thank you for your time and any help is appreciated.

Upvotes: 2

Views: 850

Answers (2)

D. Kupra
D. Kupra

Reputation: 373

I think mightyWoz's approach is sufficient for your purposes.

But in my experience, this sort of thing comes up a lot and it helps to have a way to deal with them on the fly.

My usual workflow for giving a child like an alertdialog or fragment access to their parent activity goes like this.

  1. Inside the child, declare a callback and then invoke it somewhere that you know will run. It looks like this:
class Activity0FragmentNull : Fragment() {

var controllParentCallback:(()->Unit)?=null
   ...

   override fun onCreateView(
     inflater: LayoutInflater, container: ViewGroup?,
     savedInstanceState: Bundle?
   ): View? {
       controllParentCallback?.invoke()

       return inflater.inflate(R.layout.activity0_null, container, false)
   }
   ...

Now inside the parent activity, give the child a name and then give value to its callback. It looks like this:

class Activity0: AppCompatActivity() {
   private lateinit var binding: Activity0Binding
   override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)                                    
      binding = Activity0Binding.inflate(layoutInflater)
      setContentView(binding.root)
      val childFragment=Activity0FragmentNull()
      childFragment.controllParentCallback={
binding.popUpButton.isEnabled = true
}

      binding.popUpButton.setOnClickListener {
        supportFragmentManager.commit {
            replace(R.id.quiz_fragment_container, Activity0FragmentNull())
        }
        binding.popUpButton.isEnabled = false
      }
   }
}

So even though creating an interface is great and very Kotlinic, a little callback like this really speeds up development time in situations where you create children without knowing you need to access the parent later.

Upvotes: 1

mightyWOZ
mightyWOZ

Reputation: 8355

You never create Activity objects, that is the responsibility of the operating system. so never do Activity0(). in a fragment you can access the associated Activity by using the activity property.

As of your problem it can be solved as

Define an interface

interface ButtonStateManager{
    fun setEnabled(enabled: Boolean)
}

Make your Activity implement this interface

class Activity0: AppCompatActivity(), ButtonStateManager {
    
    ...

    override fun setEnabled(enabled: Boolean) {
         binding.popUpButton.isEnabled = enabled
    }
}

Now you can enable/disable the button from Fragment as

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
     super.onViewCreated(view, savedInstanceState)
     /* cast the activity to ButtonStateManager and then call the function */
     (activity as? ButtonStateManager)?.setEnabled(true)  
}

Upvotes: 3

Related Questions