implement data transfer issue according to viewbinding - android

The code I wrote is not working because viewbinding is not suitable. I got some help from my friend but I still couldn't do the application please help me my application is interrupted
/*MainActivity*/
class MainActivity : AppCompatActivity() {
private var _binding: ActivityMainBinding?=null//
private val binding
get()=_binding!!
override fun onCreate(savedInstanceState: Bundle?) {
_binding=ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.apply{ //5.işlemimiz ;)
editText
}
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun aktiviteDegistir (view:View){
val kullaniciVerisi = editText.text.toString()
val intent = Intent(applicationContext,IkinciActivity::class.java)
intent.putExtra("yollananVeri",kullaniciVerisi)
startActivity(intent)//activiteyi başlatım güzel yer
}
/*Activity2*/
val intent = intent//intent
val alinanVeri = intent.getStringExtra("yollananVeri")
textView2.text = alinanVeri
class MainActivity : AppCompatActivity() {
private var _binding: ActivityMainBinding?=null//3.islemimiz
private val binding
get()=_binding!!
override fun onCreate(savedInstanceState: Bundle?) {//4.işlemiiz
_binding=ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.apply{ //5.işlemimiz ;)
editText
}
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
After adding this code, I waited for the messages to go away, but they didn't.
my application will write something about this to the editText button will be pressed then it needs to come to the textview part in the other activity

you are following approach, that is used to bind in fragment binding. The problem is that you are setting the binding data but not connecting it with the content view. for better approach in activity view binding just the same for more cleaner activity binding.
class MainActivity : AppCompatActivity() {
private lateinit var binder : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binder = ActivityMainBinding.inflate(layoutInflater)
setContentView(binder.root)
viewImpl()
}
/**you view calls...
* like button.setonclick() and all UI related interactions...
*/
private fun viewImpl() {
binder.run {
//here...
}
}
}
In here I have created binding lateinit var for activity binder which will be initialise when binder = ActivityMainBinding.inflate(layoutInflater) and then using that binder reference for setting my content view as setContentView(binder.root).
Happy Coding ✌️.

Related

Android access view binding val outside onCreate activity

I have an activity that has a button. On the button click I want to update text in text view.
I want to use ViewBinding instead of the normal findViewById
This is how I created the val binding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater);
setContentView(binding.root)
binding.btnRoll.setOnClickListener {
rollDice()
}
}
Now in rollDice I want to update the text view but I'm not able to access binding which make sense because its scope is limited to onCreate() , so what is the best practice for this?
private fun rollDice() {
val random = Random().nextInt(6) + 1
binding.txt_random.setText("random")
}
You have two options.
1. Store in a property
Since the inflated content of Activity is fully bound to it's lifecycle, it's safe to keep the reference as a property
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater);
setContentView(binding.root)
binding.btnRoll.setOnClickListener {
rollDice()
}
}
private fun rollDice() {
val random = Random().nextInt(6) + 1
binding.txt_random.setText("random")
}
}
2. Pass the binding to the methods
That's what I usually do, it avoids creating a property where it's not really a necessity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater);
setContentView(binding.root)
binding.btnRoll.setOnClickListener {
rollDice(binding)
}
}
private fun rollDice(binding: ActivityMainBinding) {
val random = Random().nextInt(6) + 1
binding.txt_random.setText("random")
}
}
Both options are valid ways to make the binding visible to Activities methods.
Store the binding in an instance variable on the Activity. Then you have access to it from all the methods in the Activity.
As the question has accepted answer and it is already addressed but here is my approach to the viewBinding
class MainActivity : AppCompatActivity() {
private val binding by lazy{
ActivityMainBinding.inflate(layoutInflater)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
binding.btnRoll.setOnClickListener {
rollDice()
}
}
private fun rollDice() {
val random = Random().nextInt(6) + 1
binding.txt_random.setText("random")
}
}
I go with lazy initialization of binding so that way it is only intitialized if it is required.
More you can read about lazy initialization here
https://www.baeldung.com/kotlin/lazy-initialization

How to use binding object across functions inside a Kotlin android activity class

I have this class in a file named MainActivity.kt:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater)
binding.fab.setOnClickListener {
}
setContentView(binding.root)
}
override fun onResume() {
super.onResume()
fetchData()
displayBudget()
}
private fun fetchData() {
//how to use binding here? for example: binding.tvTotal.setText("0")
}
}
As you can see, I use view binding feature on Android Studio to replace findViewById. How to use binding object (val binding) in fetchData function?
By trial & error, I can use Kotlin's lateinit variable for binding object.
class MainActivity : AppCompatActivity() {
//declare the binding object here
lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//initialize the binding object here
binding = ActivityMainBinding.inflate(layoutInflater)
binding.fab.setOnClickListener {
}
setContentView(binding.root)
}
override fun onResume() {
super.onResume()
fetchData()
displayBudget()
}
private fun fetchData() {
//I can use binding object here
binding.tvTotal.setText("0")
}
}
you need to initialize binding as an optional var for the entire class and then set it in the onCreate function and that will allow you to use it on the onResume without a problem
here's how to do it
class MainActivity : AppCompatActivity() {
//what the below does is create a nullable object binding of type ActivityMainBinding
var binding: ActivityMainBinding? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
binding?.fab.setOnClickListener {
}
setContentView(binding.root)
}
override fun onResume() {
super.onResume()
fetchData()
displayBudget()
}
private fun fetchData() {
//you can now access the binding var here by using the ? operator
binding?.tvTotal.setText("0")
}
}
Try this
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding= DataBindingUtil.setContentView(this, R.layout.activity_main)
binding.fab.setOnClickListener {
}
}
}

How to initialize and use UI elements

I am currently working on my first Android app using Kotlin. In my activity are a lot of UI elements which I use to show dynamic information (see example below). For performance reasons I learned:
"Define a variable in the class and initialize it in the onCreate()
method."
This is kind of messy and my question is: are there other techniques to fulfill the same task but have a cleaner code? The variables are used in other methods later.
class MainActivity : AppCompatActivity() {
private lateinit var text_1: TextView
private lateinit var text_2: TextView
private lateinit var text_3: TextView
private lateinit var text_4: TextView
[...]
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
text_1 = findViewById(R.id.text1)
text_2 = findViewById(R.id.text2)
text_3 = findViewById(R.id.text3)
text_4 = findViewById(R.id.text4)
[...]
}
From ViewBinding official docs:
View binding is a feature that allows you to more easily write code that interacts with views
First, enable ViewBinding in your module:
android {
...
buildFeatures {
viewBinding true
}
}
Then, if you're calling views from activity, you should:
private lateinit var binding: ResultProfileBinding
override fun onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
binding = ResultProfileBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
}
and then you use binding instance to call the views:
binding.name.text = viewModel.name
binding.button.setOnClickListener { viewModel.userClicked() }
If you are calling views from a fragment, you should do it like following to avoid leaks:
private var _binding: ResultProfileBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = ResultProfileBinding.inflate(inflater, container, false)
val view = binding.root
return view
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
In Kotlin you just need to use the id directly without binding. The class will import this:
import kotlinx.android.synthetic.main.<your_layout_xml>.*
In this case it will import: kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
text_1.text = "Text1"
text_2.text = "Text2"
[...]
}

How to use abstraction with ViewBinding with base activity?

I was making a base class so that all bindings for child will be set in base
I have done till this
abstract class BaseActivity2<B : ViewBinding?, T : BaseViewModel?> : AppCompatActivity() {
private var viewBinding: B? = null
private var baseViewModel: T? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
}
but am unable to get a way to bind view in oncreat()
generally we bind layout in view binding as
binding = ActivityLoginBinding.inflate(layoutInflater)
setContentView(binding.root)
but i am looking for generalized way in base activity
You can declare a lambda property in the constructor to create the binding object
abstract class BaseActivity<B : ViewBinding>(val bindingFactory: (LayoutInflater) -> B) : AppCompatActivity() {
private lateinit var binding: B
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = bindingFactory(layoutInflater)
setContentView(binding.root)
}
}
You can also define binding as lazy property
private val binding: B by lazy { bindingFactory(layoutInflater) }
Then you need to override nothing in your activities
class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::inflate)
Other answer will also solve problem but I would like to do in a clean way.
My Base Class
abstract class BaseVMActivity<VM : ViewModel, B : ViewBinding> : BaseActivity() {
lateinit var viewModel: VM
lateinit var binding: B
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel = ViewModelProvider(this, factory).get(getViewModelClass())
binding = getViewBinding()
setContentView(binding.root)
}
private fun getViewModelClass(): Class<VM> {
val type = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0]
return type as Class<VM>
}
abstract fun getViewBinding(): B
}
My activity:
class MainActivity : BaseVMActivity<AppViewModel, ActivityMainBinding>() {
override fun getViewBinding() = ActivityMainBinding.inflate(layoutInflater)
}
Now I can directly access viewModel or binding:
fun dummy(){
binding.bvReport.text = viewModel.getReportText()
}
It's cleaner to override binding object getter inside the child activity I think. So:
abstract class VBActivity<VB : ViewBinding> : AppCompatActivity() {
protected abstract val binding: VB
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
}
}
And lets say MainActivity will be something like:
class MainActivity : VBActivity<ActivityMainBinding>() {
override val binding get() = ActivityMainBinding.inflate(layoutInflater)
}

How to initialize ViewBinding?

How to initialize VievBinding? In AppCompactActivity version 1.0.0, it became possible to pass a layout to the parent constructor so that you would not write OnCreateView.
I do so, but then I want to use VievBinding, but it doesn’t work for me. Text is not displayed. What can be done?
class MainActivity : AppCompatActivity(R.layout.activity_main) {
override fun onStart() {
super.onStart()
var binding = ActivityMainBinding.inflate(layoutInflater)
binding.hello.text = "Hello"
}
}
class MainActivity : AppCompatActivity(R.layout.activity_main) {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.bind(findViewById(Window.ID_ANDROID_CONTENT).getChildAt(0))
}
Although it's easier if you rely on __Binding.inflate().
class MainActivity : AppCompatActivity {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater, R.layout.activity_main)
setContentView(binding.root)
}
Layout inflation should not be in onStart. It goes in onCreate in Activity, and onCreateView in Fragment.
// Activity class
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState);
val binding:YourActivityLayoutBinding =
DataBindingUtil.setContentView(this, R.layout.your_activity_layout);
}
Layout views in xml should be surrounded by <layout> tag
<layout>
...// your activity view layout
</layout>
var binding = ActivityMainBinding.inflate(layoutInflater)
This will inflate the layout again and you will get a different instance of the views than what is already set in the activity
Try using the below code to bind the activity view to the binder. Where ROOT_VIEW_ID is view id of root view in your layout
var binding = ActivityMainBinding.bind(findViewById(ROOT_VIEW_ID))*
*binding.hello.text = "Hello"

Categories

Resources