So I'm trying to send a text data from text entered in edit text through another activity with intent. I'm trying to send the text data from HomeActivity to SearchResultActivity. However, when I clicked the button that calls the startActivity(intent), my application forced closed and I get this exception:
2021-04-27 02:46:30.622 13861-13861/com.dicoding.movieapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.dicoding.movieapp, PID: 13861
kotlin.UninitializedPropertyAccessException: lateinit property activityHomeBinding has not been initialized
at com.dicoding.movieapp.home.HomeActivity.onClick(HomeActivity.kt:39)
at android.view.View.performClick(View.java:7500)
at android.view.View.performClickInternal(View.java:7472)
at android.view.View.access$3600(View.java:824)
at android.view.View$PerformClick.run(View.java:28657)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:239)
at android.app.ActivityThread.main(ActivityThread.java:8107)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:626)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1015)
I'm quite confused what I did wrong here. This is my code for the home activity. I have already initialized the binding in the onCreate function but why is it still saying that its uninitialized?
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val activityHomeBinding = ActivityHomeBinding.inflate(layoutInflater)
setContentView(activityHomeBinding.root)
activityHomeBinding.btnSearch.setOnClickListener(this)
}
override fun onClick(v: View?) {
when (v?.id){
R.id.btn_search -> {
val searchText = activityHomeBinding.editTextSearch.text.toString().trim()
if (searchText == null){
activityHomeBinding.editTextSearch.error = "Field cannot be empty"
} else {
val intent = Intent(this#HomeActivity, SearchResultActivity::class.java)
intent.putExtra(SearchResultActivity.EXTRA_SEARCH,searchText)
startActivity(intent)
}
}
}
And this is the code inside my SearchResultActivity:
private lateinit var searchResultActivity: ActivitySearchResultBinding
companion object {
const val EXTRA_SEARCH = "extra_search"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
searchResultActivity = ActivitySearchResultBinding.inflate(layoutInflater)
setContentView(searchResultActivity.root)
searchResultActivity.testIntent.text = intent.getStringExtra(EXTRA_SEARCH)
}
The error message points that on line 39 of your HomeActivity class, you're pointing at an uninitialized property. This is because you have defined 2 activityHomeBindings with different scopes
class HomeActivity : AppCompatActivity(), View.OnClickListener {
...
lateinit var activityHomeBinding: ActivityHomeBinding <-- 1st one, globally scoped
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val activityHomeBinding = ActivityHomeBinding.inflate(layoutInflater) <-- 2nd one, function-scoped (to onCreate)
setContentView(activityHomeBinding.root)
activityHomeBinding.btnSearch.setOnClickListener(this)
}
override fun onClick(v: View?) {
when (v?.id){
R.id.btn_search -> {
val searchText = activityHomeBinding.editTextSearch.text.toString().trim() <-- this points at 1st one, (i.e. globally scoped)
if (searchText == null){
activityHomeBinding.editTextSearch.error = "Field cannot be empty"
}
...
}
}
}
}
The solution is to simply remove val from the line where you're inflating the binding. This way, instead of creating a new variable, you're assigning the inflated binding to globally scoped lateinit var activityHomeBinding which then can be used by your onClick callback.
So make the change from
override fun onCreate(savedInstanceState: Bundle?) {
...
val activityHomeBinding = ActivityHomeBinding.inflate(layoutInflater)
...
}
to
override fun onCreate(savedInstanceState: Bundle?) {
...
activityHomeBinding = ActivityHomeBinding.inflate(layoutInflater)
...
}
Related
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 ✌️.
Why I'm getting a null string through Intent even after passing the value?
MainActivity
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding=ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.btnFirst.setOnClickListener {
val name=binding.etName.text.toString()
Intent(this,SecondActivity::class.java).also{
it.putExtra("EXTRA_NAME",name)
startActivity(it)
}
}
}
}```
SecondActivity
```class SecondActivity:AppCompatActivity() {
private lateinit var binding: ActivitySecondBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding= ActivitySecondBinding.inflate(layoutInflater)
setContentView(binding.root)
val name=intent.getStringArrayExtra("EXTRA_NAME")
val toPrint="$name hahahaha"
binding.tvNameIntent.text=toPrint
}
}
toPrint is getting "null hahahaha"
Can someone please rectify my error
You are putting in a String so you should be also reading a String and not StringArray. You can use e.g. getStringExtra() for that.
val name=intent.getStringArrayExtra("EXTRA_NAME") should be changed to
val name=intent.getStringExtra("EXTRA_NAME")
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
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 convert a string to EditText , i make a EditText in one activity and then make a second activity and i get this edittext through the intent in the string then
how to assign it to the second activity's edittext , but i don't find it how to assign string to edittext.Here i used a go function that is used when onclick event is occured of button
This is my first activity
class MainActivity : AppCompatActivity() , View.OnClickListener{
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun go(v:View){
val intent=Intent(this#MainActivity,Main2Activity::class.java)
var aa=EditText1.text
intent.putExtra("name",aa)
startActivity(intent)
}
}
This is my second activity
class Main2Activity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
var str=intent.getStringExtra("name").toString()
et21.setText(str)
}
}
In your first activity change go function as below,
fun go(v:View){
val intent=Intent(this#MainActivity,Main2Activity::class.java)
var aa=EditText1.text.toString()
intent.putExtra("name",aa)
startActivity(intent)
}
In your second activity change the last line of onCreate as below, you need to unwrap the value from an nullable type. Which can be done using let block over nullable type. Also I am assuming et21 is reference to the edit text and is properly initialised.
This solution is null safe
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
intent.getStringExtra("name")?.let {
et21.setText(it)
}
}
Its because you was trying to set charSequence to your EditText , just convert to String while getting value from FirstEditText.
inside your Second Activity -
class Main2Activity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
intent.getStringExtra("name")?.let {
et21.setText(it)
}
}
}
Inside your first activity
fun go(v:View){
val intent=Intent(this#MainActivity,Main2Activity::class.java)
var aa=EditText1.text.toString()
intent.putExtra("name",aa)
startActivity(intent)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
val extras:Bundle =intent.extras
val nn=extras.getString("name")
eT21.setText("${nn}")
}
Or
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
eT21.setText(intent.getStringExtra("name"))
}