MainActivity.kt doesn't see button's id? - android

Code:
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
button3.setOnClickListener { }
}
Screenshot of code with IDE error: link
I haven't idea what the error might be. Reloading and rebuild didn't help.

You're writing your code outside of MainActivity's onCreate (or any other) method scope.
Your code is:
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
button3.setOnClickListener { }
}
But must be:
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button3.setOnClickListener {
// do something
}
}
}
You can use class-level declaration for methods, inner classes etc, but not for writing code.
And calling views directly by their ids is possible only using Kotlin Android Extensions. Check if you're using it and move your code to the one of methods' scope, and code will works.

All actions must be inside an any function. Your button3.setOnClickListener { } written outside the function.
And when you add apply plugin: 'kotlin-android-extensions' your app.gradle file, widgets can be used directly via ID. Without this you need to declare your btn.

you must go in gradle scripts and select build.gradle(module.....)
and add this line:
( id 'kotlin-android-extensions' )
in plugins {
id 'com.android.application'
id 'kotlin-android'
here
}
and sync now

Related

different between call view by name or use binding in android

i'am a newest in android kotlin
I want to know what is the difference between the two lines of code below and which one is better to use
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMaindinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
bindins = DataBindingutil.setContentview( this, R.layout.activity_main)
textview.text="text"//or
binding.textview.text="text"
}}
TL;DR There are a few ways of getting views - using view binding is the currently recommended method.
View Binding (recommended)
The recommended way of accessing views is to use view binding. It offers a few advantages over getting the views manually
Less boilerplate code (you don't need to write a bunch of findViewById calls)
Null safety (catches errors like trying to access views from the wrong layout at build time instead of run time)
Type safety - the type of each view is set to help avoid invalid casts
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
// or, without using DataBindingUtil
// binding = ActivityMainBinding.inflate(layoutInflater)
// setContentView(binding.root)
binding.textview.text="text"
}
}
Manually Getting Views
The old way also still works - you can always call findViewById yourself. Keep in mind that it may error or return null if the view is not found or if you try to cast it to the wrong type.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textview = findViewById<TextView>(R.id.textview)
textview.text="text"
}
}
Kotlin Synthetics (deprecated)
Kotlin synthetics were introduced in 2017 to make it easier to get views, but are now deprecated and should be replaced with view binding. With synthetics you would have an import with your layout file name, then you could just access views from it directly.
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
textview.text="text"
}
}

Why does it still say "Unresolved reference: button" even when I have button id in xml?

I have simple android app, and I want to click button to pass other activity. But it says
Unresolved reference: button
even I give id in xml. I do not know where I mistake.
Screenshot:
activity_main.xml:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/button"
android:text="Click"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
main_activity:
class MainActivity : AppCompatActivity() {
companion object {
const val USER = "user"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val user = User( "mayk", "qqqq", PersonalInfo("mayk", "james"))
button.setOnClickListener{
val intent = Intent (this, Activity2::class.java)
intent.putExtra(USER, user)
startActivity(intent)
}
}
}
val button = findViewById<View>(R.id.button)
why still say “Unresolved reference: button” even I have button id in xml?
The ids in your xml layout files are not Kotlin variables. You need to declare a variable val button before you can use it. You also need to initialize the variable to refer to a Button object. One way to do that is with
val button = findViewById<View>(R.id.button)
I suggest that you read the beginner guides at https://d.android.com to understand the fundamentals of Android programming.
No need to use findViewById()
Go to your Build.Gradle (Module: app)
Add the following line
apply plugin: 'kotlin-android-extensions'
or
id 'kotlin-android-extensions'
Then it will ask you to sync
Then press sync
After it will ask you to import that only by using ALT+ENTER
UPDATE : THIS SOLUTION IS DEPRECATED
now you have to use View Binding
set the viewBinding build option to true in the module-level build.gradle file
android {
...
buildFeatures {
viewBinding true
}
}
To set up an instance of the binding class for use with an activity, perform the following steps in the activity's onCreate() method:
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ResultProfileBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
}
You can now use the instance of the binding class to reference any of the views:
binding.name.text = viewModel.name
binding.button.setOnClickListener { viewModel.userClicked() }
For more information you can have a look at https://developer.android.com/topic/libraries/view-binding

Why does Kotlin Activity have a problem finding Buttons?

Attempting to update an older Android game project to use view binding. Android Studio version 4.1.3. I am thinking my problem has to do with the naming of my binding class.
the xml file is called activity_correct_guess.xml and I am using what I think is the name that gets generated by the view binding: ActivityCorrectGuessBinding. Appreciate and ideas!
The build errors:
Unresolved reference: ActivityCorrectGuessBinding
Unresolved reference: binding
Unresolved reference: binding
In the Gradle build module I have the following:
android {
compileSdkVersion 30
buildToolsVersion "30.0.0"
buildFeatures {
viewBinding = true
}
layout file: activity_correct_guess.xml
<Button
android:id="#+id/btnPlayAgain"
android:layout_width="wrap_content"
..... />
Activity file: CorrectGuessActivity.kt
class CorrectGuessActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityCorrectGuessBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
playAgain()
exitGame()
}
fun playAgain() {
binding.btnPlayAgain.setOnClickListener {
val intent = Intent("com.appkotlin2021v4.MainActivity")
startActivity(intent)
}
}
Typically, you define your view binding in the root of your Activity or Fragment or in an init block:
class CorrectGuessActivity : AppCompatActivity() {
//get to inflating!
private val binding = ActivityCorrectGuessBinding.inflate(layoutInflater)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
playAgain()
exitGame()
}
fun playAgain() {
binding.btnPlayAgain.setOnClickListener {
val intent = Intent("com.appkotlin2021v4.MainActivity")
startActivity(intent)
}
}
The only time you need to "wait to inflate" is when you're in a non-ViewGroup-based class like RecyclerView.Adapter, etc.
Yes, this is the correct way to define the view binding. thank you!

Is it mandatory to create a copy of View before assigning an event handler in Android in Kotlin

I am trying to set OnClickListener on an Android button in Kotlin file. Unlike java file, where I can declare button variable at the class level and initialize it in onCreate method and assign ClickListener at the same time as:
Button inlineButton;
#Override
public void onCreate(#Nullable Bundle savedInstanceState, #Nullable PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
inlineButton = findViewById(R.id.btn_inline);
inlineButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
new NotificationToast(MainActivity.this, "Inline Button");
}
});
}
when I try to follow similar pattern I get an error with the following message:
I can only set the event handler only when I create a copy of button with following code:
var inlineButton : Button? = null;
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
inlineButton = findViewById(R.id.btn_inline)
val inlineButtonCopy = inlineButton;
if (inlineButtonCopy != null) {
inlineButtonCopy.setOnClickListener({
NotificationToast(this,inlineButtonCopy.text.toString()).Show();
})
}
}
I was wondering if it is not possible to create only a single instance of Button on top level, initialize it in oncreate, and set event handler. If I can create only a single instance, I can use the event to change the property of the same button. Is it the default behavior or am I missing something.
Any clarification is highly appreciated.
In kotlin you don't need to describe the Button. You can directly call the id and set Listener. It is easier than java. Just don't get confused in your Id's
btn_inline.setOnClickListener({
NotificationToast(this,inlineButtonCopy.text.toString()).Show();
})
In Kotlin you don't need to define the Id's of the XML component.
you can directly access with the help of Id's are already defined in your XML.
let suppose you defined the Button Id in XML is btn_inline
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btn_inline.setOnClickListener({
NotificationToast(this,inlineButtonCopy.text.toString()).Show();
})
}
Also, make sure that something like this should be present there in the import section.
import kotlinx.android.synthetic.main.activity_main.*
Just check at your end.
Another option is to use Late-Initialized Property:
private lateinit var inlineButton: Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
inlineButton = findViewById<Button>(R.id.btn_inline)
inlineButton.setOnClickListener {
NotificationToast(this,inlineButtonCopy.text.toString()).Show();
}
}

UNRESOLVED_REFERENCE in widget (TextView) resolved to error element in android-kotlin

How to update the text of Textview in kotlin. Set Text on-create function works but when I tried outside main fun it says unresolved ref.
How can I declare widget for reuse TextView for update the Text Value?
I don't have exp with kotlin. Can somebody help me?
class MediaPickedActivity : AppCompatActivity() {
val fullName = "Test User"
var score = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_media_picked)
val Tv_test = findViewById(R.id.tv_text) as TextView
Tv_test.setText("$fullName :: $score ")
if (score in 0..300) {
score = 5
setText()
}
}
private fun setText() {
// Error is here. I can't set text.
Tv_test.setText("$fullName :: $score ")
}
}
You should declare your Views as class level properties, and then you can access them from anywhere within the class. A variable declared inside a function is only accessible in that function.
class MediaPickedActivity : AppCompatActivity() {
lateinit var Tv_test: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_media_picked)
Tv_test = findViewById(R.id.tv_text) as TextView
}
private fun setText() {
Tv_test.setText("$fullName :: $score ")
}
}
I used lateinit in this example, but see a detailed discussion about different ways to declare the property here.
On top of what #zsmb13 said, you can also use the Kotlin Android Extensions plugin (since you included it as one of the topics) which is super convenient for minimizing potential findViewById() bugs, excluding the use of View fields/member variables, and etc. as follows:
First apply the plugin in your local build.gradle file:
apply plugin: 'kotlin-android-extensions'
Next, import the widget properties for a certain layout in your Activity class:
import kotlinx.android.synthetic.main.<layout>.*
... and then your Activity would be as follows:
import kotlinx.android.synthetic.main.activity_media_picked.*
class MediaPickedActivity : AppCompatActivity() {
val fullName = "Test User"
var score = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_media_picked)
// Simply references via the TextView's ID, and sets its text.
tv_text.setText("$fullName :: $score ")
if (score in 0..300) {
score = 5
setText()
}
}
private fun setText() {
tv_text.setText("$fullName :: $score ")
}
}
you can also using a lazy property which will initializing the property once in needed and separate initialization from your logic, for example:
class MediaPickedActivity : AppCompatActivity() {
val Tv_test by lazy { findViewById(R.id.tv_text) as TextView }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_media_picked)
Tv_test.setText("$fullName :: $score ")
// ...
}
private fun setText() {
Tv_test.setText("$fullName :: $score ")
}
}
OR write an inline function with a reified type parameter T to makes the code more readable.
class MediaPickedActivity : AppCompatActivity() {
val nonNull by find<TextView>(R.id.tv_text)
val nullable by find<TextView?>(R.id.tv_text)
// ...
}
inline fun <reified T : View?> Activity.find(id: Int): Lazy<T> {
return lazy { findViewById(id) as T }
}

Categories

Resources