I'm building a Resume Builder App. For that I have to use view binding. In my app everting works well I'm able to create a view binding object of the variable with a particular layout. But when I call the views from the binding variable it's working in the .kt file but not while running the app. Binding object shows the view. But when I run the app it's not working as stated in the code.
class EducationActivity : AppCompatActivity() {
private lateinit var binding : ActivityEducationBinding
private lateinit var toolbar : Toolbar
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityEducationBinding.inflate(layoutInflater)
setContentView(R.layout.activity_education)
toolbar = findViewById(R.id.toolbar_eduction_activity)
setUpToolbar()
}
private fun setUpToolbar(){
setSupportActionBar(toolbar)
val actionBar = supportActionBar
if (actionBar!=null){
actionBar.setDisplayHomeAsUpEnabled(true)
actionBar.setHomeAsUpIndicator(R.drawable.ic_back_button_action_bar)
actionBar.setDisplayShowTitleEnabled(false)
}
toolbar.setNavigationOnClickListener { onBackPressed() }
}
The code above is working with : setSupportActionBar(toolbar)
but when I use, setSupportActionBar(binding.toolbarEducationActivity). It's not working while running the app. There is no error or anything. I didn't understand the problem. Thanks in advance!
CodePudding user response:
Why are u using findViewByID's with viewBinding?
Your code should be like this
--> KOTLIN
class EducationActivity : AppCompatActivity() {
private lateinit var binding : ActivityEducationBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityEducationBinding.inflate(layoutInflater)
setContentView(binding.root)
setUpToolbar()
}
private fun setUpToolbar(){
setSupportActionBar(binding.toolbar)
val actionBar = supportActionBar
if (actionBar!=null){
actionBar.setDisplayHomeAsUpEnabled(true)
actionBar.setHomeAsUpIndicator(R.drawable.ic_back_button_action_bar)
actionBar.setDisplayShowTitleEnabled(false)
}
binding.toolbar.setNavigationOnClickListener { onBackPressed() }
}
Do mark this as the answer if this helps.
Hope this helps! :)
CodePudding user response:
The problem is you're inflating your layout twice:
binding = ActivityEducationBinding.inflate(layoutInflater)
setContentView(R.layout.activity_education)
The inflate
call inflates your layout XML, builds a view hierarchy, and stores references to that in the binding
object.
Then the setContentView
call with a layout reference inflates another, completely separate view hierarchy and displays it.
So you have two sets of views, one is visible and the other isn't. The ones in binding
are the ones that aren't being displayed - the user can't see or interact with them, so they're pretty much useless. That's why things aren't working when you try to set stuff up with the views in binding
.
Using findViewById
instead is implicitly calling it on the Activity's view
hierarchy, i.e. the stuff that's displayed. That way you get a reference to the Toolbar
that's actually on-screen, instead of the stray one in binding
. So when you set things up with that one, you actually see it working!
So to solve it, you need to ensure you're inflating your layout once, and then make everything use that. There's two common ways to do it:
// inflate your Binding class, and pass the resulting layout to setContentView to display
binding = ActivityEducationBinding.inflate(layoutInflater)
// this root property is the inflated view hierarchy
setContentView(binding.root)
or
// use setContentView with a layout resource, and let it inflate the views as normal
setContentView(R.layout.activity_education)
// now that the 'view' property for the Activity has been set with the inflated layout,
// you can grab that and -bind- its views to the properties in your Binding class
binding = ActivityEducationBinding.bind(view)
The bind
call is basically what happens with inflate
, except you're skipping the inflation step because you already have an inflated layout.
You can use either approach - I prefer the first because you only specify the layout resource once by referencing the appropriate binding class. Then you just pass whatever you inflate to setContentView
for display. With the second approach, you have to make sure the Binding class you use matches the layout resource ID you pass into setContentView
. Not a huge deal and sometimes one is more convenient than the other!
The important thing though is that in both cases, you only inflate something once. Then everything is using the same set of views, and nothing weird is going on. If you ever find yourself inflating more than once, and you don't have a very specific reason for doing it, then that's a warning sign!