Android Studio Kotlin app "keeps stopping" when I run it - android-studio

I am just trying to set up a spinner configured as a dropdown menu, but I can't even test my app to see if it works because every time I run it, it immediately crashes. I know that my issue is related to a null object reference at line 21 in my MainActivity.kt file. Here is the problem code:
val spinner: Spinner = findViewById<Spinner>(R.id.locations)
The id of the spinner is locations, so I'm not sure why this is coming back as a null value.
Here is also the full code for the file:
import android.app.Activity
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Spinner
import android.widget.ArrayAdapter
import android.widget.AdapterView
private var userLocation: Any = ""
private var userDestination: Any = ""
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
val spinner: Spinner = findViewById<Spinner>(R.id.locations)
val locationsAdapter: ArrayAdapter<CharSequence> = ArrayAdapter.createFromResource(
this,
R.array.rooms,
android.R.layout.simple_spinner_item
).also { adapter ->
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinner.adapter = adapter
}
}
class SpinnerActivity : Activity(), AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>, view: View?, pos: Int, id:Long) {
userLocation = parent.getItemAtPosition(pos)
val spinner: Spinner = findViewById(R.id.locations)
spinner.onItemSelectedListener = this
}
override fun onNothingSelected(parent: AdapterView<*>) = Unit
}

Declare spinner global for MainActivity:
private lateinit var spinner: Spinner
On the method onCreate initialise the spinner and set its adapter, I would recommend you to set the array adapter as follows:
spinner = findViewById<Spinner>(R.id.locations)
spinner.adapter = ArrayAdapter(this, R.layout.drop_down_generic_item, resources.getStringArray(R.array.rooms))
I don't really understand the SpinnerActivity you showed in the question, sorry. But in MainActivity you can set the spinner.onItemSelectedLister() as follows:
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(adapterView: AdapterView<*>?, view: View?, position: Int, p3: Long) {
val selectedRoom = adapterView?.getItemAtPosition(position)
}
override fun onNothingSelected(p0: AdapterView<*>?) {
}
}
I don't want to confuse you, but have a look at a TextInputLayout with an AutoCompleteTextView, just as a hint. :D

Related

Expecting member declaration even though the val is declared the line above

I looked at all of the other questions about this error, but none of them helped. I am trying to create a reference to a button in my layout file, and when I set the onClickListener, I get "expecting member declaration." This occurs on line 35. Side note, I am also getting the error "Function declaration must have a name" on the same line. Here is the code:
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.*
private var userLocation: Any = ""
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val spinner: Spinner = findViewById<Spinner>(R.id.locations)
spinner.adapter = ArrayAdapter(
this,
android.support.v7.appcompat.R.layout.support_simple_spinner_dropdown_item,
resources.getStringArray(R.array.rooms)
)
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
adapterView: AdapterView<*>?,
view: View?,
position: Int,
p3: Long
) {
userLocation = adapterView?.getItemAtPosition(position)!!
}
override fun onNothingSelected(p0: AdapterView<*>?) {
}
}
}
val button: Button = findViewById<Button>(R.id.button)
button.setOnClickListener{
Toast.makeText(this, "Selected $userLocation", Toast.LENGTH_SHORT).show()
}
}
These lines of code:
val button: Button = findViewById<Button>(R.id.button)
button.setOnClickListener{
Toast.makeText(this, "Selected $userLocation", Toast.LENGTH_SHORT).show()
}
you have defined outside any functions. That means button is a class-level property you are defining. Properties are initialized before any functions are called, so this findViewById call will fail at runtime because it will be called before onCreate().
And you cannot simply call a function like setOnClickListener at the the top level of a function in the middle of nowhere. That's why you have the "expecting member declaration" error.
You need to move all of this code inside your onCreate() function.

How to add onClickListener on images in recyclerView?

I am trying to attach onclick listener on images in this code, using Glide framework but I'm not able to find a solution for that. Can someone help with this?
Images are showing in emulator already.
Thanks in advance
package com.example.andoridlifecycle.adapters
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.example.andoridlifecycle.R
import kotlinx.android.synthetic.main.item_custom_row.view.*
class ItemAdapter(private val context: Context, private val urls: ArrayList<String>) :
RecyclerView.Adapter<ItemAdapter.ViewHolder>() {
/**
* Inflates the custom view which is designed in xml layout file
*/
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
LayoutInflater.from(context).inflate(
R.layout.item_custom_row,
parent,
false
)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
// Array with urls
val url = urls[position]
Glide.with(context)
.load(url)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.placeholder(R.drawable.placeholder)
.into(holder.imageView)
}
// Gets the number of items in the list
override fun getItemCount(): Int {
return urls.size
}
// A ViewHolder describes an item view and metadata about its place within the RecyclerView.
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val imageView: ImageView = view.iv_image
}
}
I'm Java Developer so I cannot code with Kotlin but I'll show you how to set OnClickListener on your imageView. For using OnclickListener on imageView no need for Glide Library.
Just add the below lines in your onBindViewHolder
holder.imageView.setOnClickListener(view -> {
Toast.makeText(context, "this is number: "+position+" Image Selected", Toast.LENGTH_SHORT).show();
// or your code for imageView
});
Your new code looks like the below:-
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
// Array with urls
val url = urls[position]
//code for onClick on image
holder.imageView.setOnClickListener(view -> {
Toast.makeText(context, "this is number: "+position+" Image Selected", Toast.LENGTH_SHORT).show();
// or your code for imageView
});
Glide.with(context)
.load(url)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.placeholder(R.drawable.placeholder)
.into(holder.imageView)
}
Make sure to change JAVA to Kotlin in my code. If you any problem is causing, Let me know

findViewById keeps giving me errors and a headache

Hello all,
I am new to Kotlin and was trying to keep recreating my code to get it easier for me to learn. i have created an dice app and it works. but everytime i create a new project and start. I always get the error on findViewById(R.id.) i make the layout first with all the ID`s assigned but no matter what i do i keep getting this error. I use Android Studio.
I hope someone can help me get this frustration out of my head.I want to know why it keeps getting that error. thanks in advance.
package com.example.dicedicebaby
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//button action`
val rollButton: Button = findViewById(R.id.button)
//action of the button when pressed.
rollButton.setOnClickListener{ stones()}
}
}
fun stones(){
//The normal dice
val fDice=Dice(6)
//D20
val dDice = Dice(20)
//action of dice roll
val dice = fDice.roll()
//D20 action
val secondDice = dDice.roll()
//view
val resultView: TextView = findViewById(R.id.dice)
resultView.text = dice.toString()
val secondView: TextView = findViewById(R.id.Ddice)
secondView.text = secondDice.toString()
}
//makes the dice a dice.
class Dice(private val numSides:Int){
fun roll():Int{
return (1..numSides).random()
}
}
The suggested approach is to migrate to view binding.
Plus, you should declare the stones() function inside the MainActivity class body:
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
//action of the button when pressed.
binding.rollButton.setOnClickListener{ stones() }
}
fun stones(){
//The normal dice
val fDice=Dice(6)
//D20
val dDice = Dice(20)
//action of dice roll
val dice = fDice.roll()
//D20 action
val secondDice = dDice.roll()
//view
binding.dice.text = dice.toString()
binding.Ddice.text = secondDice.toString()
}
}

Can one reference id directly in kotlin?My small program can't seem to run

Hi im new in android and i read that i can directly reference id from activity_main to mainAcctivity.kt without using findviewbyid.When i do that i get an error but my ids are correct:
This is the error Unresolved reference: button and Unresolved reference: textView
This is my code
import android.os.Bundle
import android.widget.Button
import android.widget.Toast
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// get reference to button
//val btnClickMe = findViewById(R.id.button) as Button
//val myTextView = findViewById(R.id.textView) as TextView
var timesClicked = 0
// set on-click listener
button.setOnClickListener {
timesClicked += 1
textView.text = timesClicked.toString()
Toast.makeText(this#MainActivity, "Hello Don.", Toast.LENGTH_SHORT).show()
}
}
}```
Please help out,i tried to import android.widget.button and textView that option is not available but when i hardcode the text appears inactive.
You can make use of ViewBinding to reduce the use of findViewById. You can find an example here.
You can go through this blog to have more insight on how to use ViewBinding.
For the above code, you can resolve the issue using the code below:
val myTextView = findViewById<TextView>(R.id.textView)
val btnClickMe = findViewById<Button>(R.id.button)

Kotlin AddOnPageChangeListener not working

I wanted to connect a viewPager with an adapter (like this: viewPager.addOnPageChangeListener()), but the letters of the pageChangeListener just turn red like it wasn't a valid code...What am I doing wrong?? Heres a screenshot:
[1]: https://i.stack.imgur.com/IOYJY.png
Context: I'm currently working on a game with a few fragments where you can choose your game cards. I need the pageChangeListener to change the pictures of them cards. Maybe there could be another way to do this but i don't know how...
package com.suffv1
import android.os.Bundle
import androidx.appcompat.app.ActionBar
import androidx.appcompat.app.AppCompatActivity
import androidx.viewpager.widget.ViewPager
import com.example.suff_02.Adapter2
import com.example.suff_02.R
import com.example.suff_02.kartenmodell
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity(){
private lateinit var actionbar: ActionBar
private lateinit var liste: ArrayList<kartenmodell>
private lateinit var myAdapter: Adapter2
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
super.setContentView(R.layout.activity_main)
actionbar = this.supportActionBar!!
loadCards()
viewpager2.addOnPageChangeListener(object: ViewPager.OnPageChangeListener{
override fun onPageScrolled(
position: Int,
positionOffset: Float,
positionOffsetPixels: Int
) {
val title = liste[position].KartenImage
actionbar.title = title
}
})
}
private fun loadCards() {
liste = ArrayList()
liste.add(kartenmodell(R.drawable.bier_radler_klein_level_1))
liste.add(kartenmodell(R.drawable.bier_hopfentrunk_klein_level_1))
liste.add(kartenmodell(R.drawable.bier_butt_light_klein_level_1))
liste.add(kartenmodell(R.drawable.bier_becks_klein_level_1))
liste.add(kartenmodell(R.drawable.bier_tyskie_klein_level_1))
myAdapter = Adapter2(this, liste)
viewpager2.adapter = myAdapter
viewpager2.setPadding(100, 0, 100, 0)
}
}
Looks like you are using ViewPager2 not the original Viewpager and Viewpager2 does not have Page Change Listeners it instead has Page Change Callbacks
So you are using the wrong method to get notified when a pages is changed.
Instead do something like
var myPageChangeCallback = object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
Toast.makeText(this#MainActivity, "Selected position: ${position}",
Toast.LENGTH_SHORT).show()
}
}
viewpager.registerOnPageChangeCallback(myPageChangeCallback)
Though architecturally a lot of times it is bad form to use a OnPageChangeCallback as you are likely breaking the encapsulation idea of the Fragment and it can be better to use the lifecycle state change to Resumed of the Fragment to do things when a page(Fragment) is selected. e.g. put the code in the Fragments onResume method.
Though in this case of setting the actionbar title it is probably ok architecturally to use a OnPageChangeCallback
To create a AddOnPageChangeListener(), you do it as:
//See how, you have to use object to create an Object of the interface OnPageChangeListener.
//This is how you do for other listeners/interfaces/class as well when you've to implement its member functions instead of new in java.
viewPager.addOnPageChangeListener(object: ViewPager.OnPageChangeListener{
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
TODO("Not yet implemented")
}
override fun onPageSelected(position: Int) {
TODO("Not yet implemented")
}
override fun onPageScrollStateChanged(state: Int) {
TODO("Not yet implemented")
}
})
But, further in Kotlin, you can use Kotlin functions as
//This is for onPageSelected only.
viewPager.onPageChangeListener{ position: Int ->
//This position is the selected Page's position
}

Resources