All intent's extras are null while starting a new activity - android

This is an application with a list of dogs and information about the dog.
I'm trying to run a DetailActivity that contains information about a dog. It is launched after clicking the Show Details button, which has a setOnClickListener and runs the Intent, passing the name, age, hobby and other parameters of the dog to the running DetailActivity. But when I try to take those parameters in the DetailActivity code, they all equal null.
It's actually very simple and I've done the same thing in google course codelab before (now I decided to practice a bit) and I repeat everything as it's written there, but I don't understand what I'm doing wrong.
I'll insert the DetailActivity and DogCardAdapter code below. You can also see all the code at this link on GitHub: https://github.com/theMagusDev/DogglersApp
DetailActivity.kt:
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.example.dogglers.databinding.ActivityDetailBinding
class DetailActivity() : AppCompatActivity() {
private lateinit var binding: ActivityDetailBinding
private val TAG = "DetailActivity"
companion object {
const val DOG_IMAGE = "dogImage"
const val DOG_NAME = "dogName"
const val DOG_AGE = "dogAge"
const val DOG_HOBBIES = "dogHobbies"
const val DOG_SEX = "dogSex"
}
val dogImageResourceId = intent?.extras?.getString(DOG_IMAGE)
val dogName = intent?.extras?.getString(DOG_NAME)
val dogAge = intent?.extras?.getString(DOG_AGE)
val dogHobbies = intent?.extras?.getString(DOG_HOBBIES)
val dogSex = intent?.extras?.getString(DOG_SEX)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Setup view binding
binding = ActivityDetailBinding.inflate(layoutInflater)
setContentView(binding.root)
val heOrShe: String = when(dogSex){
"male" -> "He"
else -> "She"
}
binding.dogName.text = dogName
Log.d(TAG, "${dogAge.toString()}, ${dogName.toString()}, $dogHobbies, $heOrShe, $dogImageResourceId")
binding.dogDescription.text = getString(R.string.dog_description, dogName, dogAge, dogSex, dogHobbies)
//binding.dogImage.setImageResource(dogImageResourceId!!.toInt())
binding.dogImage.setImageResource(R.drawable.bella)
Log.d(TAG, "dogDescription and dogImage were set")
title = getString(R.string.details_about, dogName)
}
Logcat:
2022-10-02 08:32:25.545 9660-9660/com.example.dogglers D/DetailActivity: null, null, null, She, null
2022-10-02 08:32:25.558 9660-9660/com.example.dogglers D/DetailActivity: dogDescription and dogImage were set
DogCardAdapter.kt:
import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.dogglers.DetailActivity
import com.example.dogglers.DetailActivity.Companion.DOG_AGE
import com.example.dogglers.DetailActivity.Companion.DOG_HOBBIES
import com.example.dogglers.DetailActivity.Companion.DOG_IMAGE
import com.example.dogglers.DetailActivity.Companion.DOG_NAME
import com.example.dogglers.DetailActivity.Companion.DOG_SEX
import com.example.dogglers.R
import com.example.dogglers.const.Layout.GRID
import com.example.dogglers.data.DataSource
/**
* Adapter to inflate the appropriate list item layout and populate the view with information
* from the appropriate data source
*/
class DogCardAdapter(
private val context: Context?,
private val layout: Int
): RecyclerView.Adapter<DogCardAdapter.DogCardViewHolder>() {
// Initialize the data using the List found in data/DataSource
val data = DataSource.dogs
/**
* Initialize view elements
*/
class DogCardViewHolder(view: View?): RecyclerView.ViewHolder(view!!) {
// Declare and initialize all of the list item UI components
val imageView: ImageView = view!!.findViewById(R.id.dog_image)
val dogName: TextView = view!!.findViewById(R.id.dog_name)
val dogAge: TextView = view!!.findViewById(R.id.dog_age)
val dogHobbies: TextView = view!!.findViewById(R.id.dog_hobbies)
var dogSex = "n/a"
val showDetailsButton: Button = view!!.findViewById(R.id.details_button)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DogCardViewHolder {
// Use a conditional to determine the layout type and set it accordingly.
// if the layout variable is Layout.GRID the grid list item should be used. Otherwise the
// the vertical/horizontal list item should be used.
val layoutType = when(layout) {
GRID -> R.layout.grid_list_item
else -> R.layout.vertical_horizontal_list_item
}
// Inflate the layout
val adapterLayout =LayoutInflater.from(parent.context)
.inflate(layoutType, parent, false)
// Null should not be passed into the view holder. This should be updated to reflect
// the inflated layout.
return DogCardViewHolder(adapterLayout)
}
override fun getItemCount(): Int = data.size
override fun onBindViewHolder(holder: DogCardViewHolder, position: Int) {
val resources = context?.resources
// Get the data at the current position
val item = data[position]
// Set the image resource for the current dog
holder.imageView.setImageResource(item.imageResourceId)
// Set the text for the current dog's name
holder.dogName.text = item.name
// Set the text for the current dog's age
holder.dogAge.text = resources?.getString(R.string.dog_age, item.age)
// Set the text for the current dog's hobbies by passing the hobbies to the
// R.string.dog_hobbies string constant.
holder.dogHobbies.text = resources?.getString(R.string.dog_hobbies, item.hobbies)
// Passing an argument to the string resource looks like:
// resources?.getString(R.string.dog_hobbies, dog.hobbies)
// Set the dog's sex variable
holder.dogSex = item.sex
// Declare context var
val context = holder.itemView.context
// Setting up OnClickListener
holder.showDetailsButton.setOnClickListener {
val intent = Intent(context, DetailActivity::class.java)
intent.putExtra(DOG_IMAGE, item.imageResourceId.toInt())
intent.putExtra(DOG_NAME, holder.dogName.toString())
intent.putExtra(DOG_AGE, holder.dogAge.toString())
intent.putExtra(DOG_HOBBIES, holder.dogHobbies.toString())
intent.putExtra(DOG_SEX, holder.dogSex.toString())
context.startActivity(intent)
}
}
}

Related

How to create a button on click to move to next page (RecyclerView + ViewPager2)

Here are the adapter class and I am trying to create a button on click listener within OnCreateViewHolder to click and move on to the next page of the Pager2ViewHolder and nothing seems to work for me.
I really appreciate any help that will be given.
package com.example.apitestquiz.viewmodel
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.core.view.children
import androidx.recyclerview.widget.RecyclerView
import com.example.apitestquiz.R
import com.example.apitestquiz.model.QuestionModelItem
class ViewPagerAdapter(private var list:List<QuestionModelItem>):RecyclerView.Adapter<ViewPagerAdapter.Pager2ViewHolder>() {
private lateinit var radioButton: RadioButton
private var score:IntArray = IntArray(list.size)
private var answerCorrect = Array(list.size){""}
private var count:IntArray = IntArray(list.size)
inner class Pager2ViewHolder(itemView : View): RecyclerView.ViewHolder(itemView){
//item_page content
val radioGroup: RadioGroup = itemView.findViewById(R.id.radioGroup2)
val textView: TextView = itemView.findViewById(R.id.textQuestion2)
val buttonRight: Button = itemView.findViewById(R.id.buttonRight)
val buttonLeft: Button = itemView.findViewById(R.id.buttonLeft)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewPagerAdapter.Pager2ViewHolder {
return Pager2ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_page,parent,false))
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: ViewPagerAdapter.Pager2ViewHolder, position:Int){
holder.textView.text = list[position].question
val answers = getAnswerCollection(list,position)
holder.radioGroup.children.forEachIndexed { index, view ->
radioButton = view as RadioButton
radioButton.text = answers[index]
}
holder.radioGroup.setOnCheckedChangeListener { _, checkedId ->
val radio:RadioButton = holder.radioGroup.findViewById(checkedId)
if(radio.text.toString().equals(answerCorrect[position],true)){
if (score[position]<=0)
count[position] = 1
score[position] = 1
}else{
if (score[position]>=0){
count[position] = 1
score[position] = 0
}
}
}
// holder.buttonRight.setOnClickListener {
// val context = holder.itemView.context
// if(count.sum() == 5){
// val intent = Intent (context, EndActivity::class.java)
// intent.putExtra("scoreFin",score.sum().toString())
// context.startActivity(intent)
// }else{ Toast.makeText(context,"Answer All Question",Toast.LENGTH_SHORT).show() }
// }
when(position){
0-> {
holder.buttonLeft.visibility = View.INVISIBLE
holder.buttonRight.visibility = View.VISIBLE
holder.buttonRight.text = "Next"
}
4 ->{
holder.buttonLeft.visibility = View.VISIBLE
holder.buttonRight.visibility = View.VISIBLE
holder.buttonRight.text = "Finish"
holder.buttonLeft.text = "Previous"
}
else -> {
holder.buttonLeft.visibility = View.VISIBLE
holder.buttonRight.visibility = View.VISIBLE
holder.buttonRight.text = "Next"
holder.buttonLeft.text = "Previous"
}
}
}
private fun getAnswerCollection(x:List<QuestionModelItem>,y:Int): MutableList<String> {
answerCorrect[y] = x[y].correctAnswer //Getting answer from API
val answerWrong:List<String> = x[y].incorrectAnswers
val answerCollect = answerWrong + x[y].correctAnswer //Getting answer collections and shuffling
val answerShuffle = answerCollect.toMutableList()
answerShuffle.shuffle()
return answerShuffle
}
}
I have tried some animation but that does not scroll/swipe to the next activity only a blank page
if you take a look into the documentation of ViewPager2 https://developer.android.com/reference/kotlin/androidx/viewpager2/widget/ViewPager2 you can see that has setCurrentItem method. I suggest you add a callback for clicking on button that has to move to the next page. It will look something like this:
class ViewPagerAdapter(private var list:List<QuestionModelItem>, val onButtonRightClick: (Int) -> Unit))
And in buttonRight onClickListener you call that callback with current index:
buttonRight.setOnClickListener {
onButtonRightClick(position)
}
The last step is to properly add a callback to the adapter, so in your Fragment or Activity wherever you have your adapter you must create it in that way:
val adapter = ViewPagerAdapter(list) {
viewPager2.setCurrentItem(it + 1)
}
I made an assumption that your ViewPagerAdapter can be referenced as viewPager2.

Can't change editText input from string to float

package com.example.tipcalculator
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import kotlin.text.toFloat as kotlinTextToFloat
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportActionBar?.hide()
val tenPerTip: Button = findViewById(R.id.tenPerTipButton)
val fifteenPerTip: Button = findViewById(R.id.fifteenPerTipButton)
val twentyPerTip: Button = findViewById(R.id.twentyPerTipButton)
val customTip: Button = findViewById(R.id.customTipSubmit)
val sumRaw: EditText = findViewById(R.id.billEnter)
val tipOnlyResult: TextView = findViewById(R.id.tipOnlyResult)
val totalResult: TextView = findViewById(R.id.totalResult)
val sumString = sumRaw.toString()
val sumInput = sumString.toInt()
tenPerTip.setOnClickListener{
val sumTotal = sumInput * 1.1
val tipOnly = sumInput * 0.1
tipOnlyResult.text = tipOnly.toString()
totalResult.text = sumTotal.toString()
}
fifteenPerTip.setOnClickListener{
}
twentyPerTip.setOnClickListener{
}
customTip.setOnClickListener{
}
}
}
I was trying to switch the EditText input to a string and from there to a float so that I can do calculations on it. On the line with val sumInput = sumString.toInt() the code breaks. It will compile, but when I try to run an emulator it casts error codes about the toInt declaration. The code is using toInt in this because I was trying to see if the emulator would like that. Also whenever I declare that toInt it highlights in a light yellow italic font, which I haven't seen before.
I have Edited your code.
Changes to the code is explained with the comments below.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportActionBar?.hide()
val tenPerTip: Button = findViewById(R.id.tenPerTipButton)
val fifteenPerTip: Button = findViewById(R.id.fifteenPerTipButton)
val twentyPerTip: Button = findViewById(R.id.twentyPerTipButton)
val customTip: Button = findViewById(R.id.customTipSubmit)
val sumRaw: EditText = findViewById(R.id.billEnter)
val tipOnlyResult: TextView = findViewById(R.id.tipOnlyResult)
val totalResult: TextView = findViewById(R.id.totalResult)
/** if you put sumString and sumInput here, what happens is when your app
* is created and the onCreate method is called sumString is initialized
* here without using .text, i.e., sumRaw.text command what happens is sumString
* will be initialized with sumRaw value (i guess maybe sumRaw id) and you will
* get error.
* Also, this is only called once when all the other variable are initialized.
* If you want to use it outside use a TextWatcher and change the variable as
* soon as it is updated in the EditText.
* A work-around would be initializing this value inside OnClickListener, what
* happens here is whenever you click tenPerTip Button sumString is Initialized
* with current values in sumRaw EditText.
*
* Do use .text else it will give errors.
*/
tenPerTip.setOnClickListener {
val sumString = sumRaw.text.toString()
// what happens here is sumString is converted to Double if it has valid pattern
// else it will return null
// And then the elvis operator will check for null. If its null, it will not
// not proceed further and will get out the listener.
val sumInput = sumString.toDoubleOrNull() ?: return#setOnClickListener
val sumTotal = sumInput * 1.1
val tipOnly = sumInput * 0.1
tipOnlyResult.text = tipOnly.toString()
totalResult.text = sumTotal.toString()
}
fifteenPerTip.setOnClickListener {
}
twentyPerTip.setOnClickListener {
}
customTip.setOnClickListener {
}
}
}
You seem to think the that when you write val sumString = sumRaw.toString(), it gives you the text entered in R.id.billEnter which is not correct. to get text from an EditText you have to use text property. As for your code it can be fixed as
tenPerTip.setOnClickListener{
val sumString = sumRaw.text.toString()
val sumInput = sumString.toInt()
val sumTotal = sumInput * 1.1
val tipOnly = sumInput * 0.1
tipOnlyResult.text = tipOnly.toString()
totalResult.text = sumTotal.toString()
}

Android with Kotlin recyclerView with checkboxes randomly checked after delete list item

apologies for my limited knowledge of programming and any sloppiness. I have a reyclerview with alarm objects that I can add and it creates them. When I add say 4 alarms, and delete three of them. The last alarms checkbox is checked by itself. I can not in anyway use the checkbox.setChecked() method for some reason. android studio is not recognizing it, if anyone could please let me know why that is. Also if you know of a solution to the auto check on the last alarm object please.
package com.example.alarmclock
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.Checkable
import android.widget.EditText
import android.widget.TextView
import androidx.core.widget.doAfterTextChanged
import androidx.core.widget.doBeforeTextChanged
import androidx.recyclerview.widget.RecyclerView
import java.security.Key
class AlarmAdapter (private val alarmList: MutableList<Alarm>) : RecyclerView.Adapter<AlarmAdapter.ViewHolder>() {
//start viewholder
inner class ViewHolder(alarm: View) : RecyclerView.ViewHolder(alarm) {
val alarmLabel = itemView.findViewById<EditText>(R.id.alarmLabel)
val editTextTime = itemView.findViewById<EditText>(R.id.editTextTime)
val textView1 = itemView.findViewById<TextView>(R.id.textView1)
val deleteCheckBox = itemView.findViewById<Button>(R.id.deleteAlarmCheckBox)
//val deleteButton = itemView.findViewById<Button>(R.id.deleteAlarmButton)
//val addButton = itemView.findViewById<Button>(R.id.addAlarmButton)
val mondayCheckBox = itemView.findViewById<Button>(R.id.mondayCheckBox)
val tuesdayCheckBox = itemView.findViewById<Button>(R.id.tuesdayCheckBox)
val wednesdayCheckBox = itemView.findViewById<Button>(R.id.wednesdayCheckBox)
val thursdayCheckBox = itemView.findViewById<Button>(R.id.thursdayCheckBox)
val fridayCheckBox = itemView.findViewById<Button>(R.id.fridayCheckBox)
val saturdayCheckBox = itemView.findViewById<Button>(R.id.saturdayCheckBox)
val sundayCheckBox = itemView.findViewById<Button>(R.id.sundayCheckBox)
val amCheckBox = itemView.findViewById<Button>(R.id.amCheckBox)
val pmCheckBox = itemView.findViewById<Button>(R.id.pmCheckBox)
}//end viewholder
fun addAlarm (alarm: Alarm) {
alarmList.add(alarm)
notifyItemInserted(alarmList.size - 1)
}
fun returnAlarmList (): MutableList<Alarm> {
return alarmList
}
fun removeAlarms() {
alarmList.removeAll {
alarm -> alarm.deleteCheck == true
}
//notifyDataSetChanged()
}
fun deleteAlarm (deletedAlarmList: List<Int> ) {
val deletedListIterator = deletedAlarmList.iterator()
val alarmListIterator = alarmList.iterator()
while (deletedListIterator.hasNext()){
while (alarmListIterator.hasNext()){
if (deletedListIterator.next() == alarmListIterator.next().alarmId){
alarmList.remove(alarmListIterator.next())
}
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val context = parent.context
val inflater = LayoutInflater.from(context)
val alarmView = inflater.inflate(R.layout.alarms, parent, false)
return ViewHolder(alarmView)
}
override fun getItemCount(): Int {
return alarmList.size
}
override fun onBindViewHolder(holder: AlarmAdapter.ViewHolder, position: Int) {
val alarm: Alarm = alarmList[position]
val alarmLabel = holder.alarmLabel
var textView1 = holder.textView1
var editTextTime = holder.editTextTime
var mondayCheckBox = holder.mondayCheckBox
var tuesdayCheckBox = holder.tuesdayCheckBox
var wednesdayCheckBox = holder.wednesdayCheckBox
var thursdayCheckBox = holder.thursdayCheckBox
var fridayCheckBox = holder.fridayCheckBox
var saturdayCheckBox = holder.saturdayCheckBox
var sundayCheckBox = holder.sundayCheckBox
var amCheckBox = holder.amCheckBox
var pmCheckBox = holder.pmCheckBox
var deleteAlarmCheckBox = holder.deleteCheckBox
var lastCharacter = ""
var secondLastCharacter = ""
deleteAlarmCheckBox.setOnClickListener {
alarm.deleteCheck = !alarm.deleteCheck
}
alarmLabel.doAfterTextChanged {
alarm.alarmLabel = alarmLabel.text.toString()
textView1.text = alarm.alarmLabel
}
editTextTime.doAfterTextChanged {
//lastCharacter = editTextTime.text.get(editTextTime.text.length-1).toString()
textView1.text = lastCharacter
if (editTextTime.text.length == 2 && secondLastCharacter != ":"){
//if (lastCharacter != ":") {
editTextTime.setText(editTextTime.text.toString().plus(":"))
editTextTime.setSelection(editTextTime.text.length)
//}
}
editTextTime.doBeforeTextChanged { _, _, _, _ ->
if (editTextTime.length() != 0) {
secondLastCharacter = editTextTime.text.get(editTextTime.text.length - 1).toString()
}
}
if (editTextTime.text.length == 5 ){
alarm.hour = editTextTime.text.get(0).toString().plus(editTextTime.text.get(1).toString())
if (alarm.hour.toInt() < 10) alarm.hour = "0".plus(alarm.hour)
///////
var inputedTimeList = editTextTime.text.toList()
val timeIterator = inputedTimeList.iterator()
}
}
mondayCheckBox.setOnClickListener {
alarm.monday = !alarm.monday
textView1.text = alarm.monday.toString()
}
tuesdayCheckBox.setOnClickListener {
alarm.tuesday = !alarm.tuesday
}
wednesdayCheckBox.setOnClickListener {
alarm.wednesday = !alarm.wednesday
}
thursdayCheckBox.setOnClickListener {
alarm.thursday = !alarm.thursday
}
fridayCheckBox.setOnClickListener {
alarm.friday = !alarm.friday
}
saturdayCheckBox.setOnClickListener {
alarm.saturday = !alarm.saturday
}
sundayCheckBox.setOnClickListener {
alarm.sunday = !alarm.sunday
}
amCheckBox.setOnClickListener {
alarm.amPm = !alarm.amPm
}
}
}
The answer is quite simple, RecyclerView items are reused, so be sure that you set the all the values onBindViewHolder, because after your item is deleted, the actual view is not, so previously set values might be preset although they are not correct according to your data.
The easiest way would be to have isChecked Boolean value store in the Alarm object, onBindViewHolder always set the isChecked param on the Checkbox according to the value returned from the Alarm and when you change the isChecked inside the Checkbox listener - make sure you also update the value inside the Alarm object.
Another solution would be calling notifyDatasetChanged() on the RecyclerView, but it's definitely not the best solution especially if you have dynamic row deletion (and possibly a neat animation).
P.S. consider using viewBinding in your project, it will save you time writing all that ugly findViewById code :)))

I can't change a public variable Kotlin

I try to change a public variable in kotlin but i can't. When I receive the variable in another script, it has not changed. I print the variable in the second script but then it says zero. I have no idea why. Please help me. I'm stuck. Here are my code:
package com.backal.bingolooooooooooooto
import android.content.Intent
import android.os.Bundle
import android.util.Log.d
import android.view.View
import androidx.appcompat.app.AppCompatActivity
class AddFavourActivity: AppCompatActivity() {
public var clicked = 0;
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.add_favour)
val alt1: View = findViewById(R.id.alt1)
val alt2: View = findViewById(R.id.alt2)
val alt3: View = findViewById(R.id.alt3)
val alt4: View = findViewById(R.id.alt4)
val alt5: View = findViewById(R.id.alt5)
val alt6: View = findViewById(R.id.alt6)
val alt7: View = findViewById(R.id.alt7)
alt1.setOnClickListener {
var clicked = 50
startActivity(Intent(this, EnterPasswordActivity::class.java))
}
alt2.setOnClickListener {
var clicked = 80
d("Alexander", "Clicked is: $clicked")
startActivity(Intent(this, EnterPasswordActivity::class.java))
}
alt3.setOnClickListener {
startActivity(Intent(this, EnterPasswordActivity::class.java))
clicked = 100
}
alt4.setOnClickListener {
startActivity(Intent(this, EnterPasswordActivity::class.java))
clicked = 300
}
alt5.setOnClickListener {
startActivity(Intent(this, EnterPasswordActivity::class.java))
clicked = 500
}
alt6.setOnClickListener {
startActivity(Intent(this, EnterPasswordActivity::class.java))
clicked = 100
}
alt7.setOnClickListener {
startActivity(Intent(this, EnterPasswordActivity::class.java))
clicked = 1000
}
}
}
every time you are doing var clicked = 50 you're declaring a new variable (even if it's the same name) so just remove the var :
clicked = 50
something else you might want to consider is to rather make use of a companion object :
companion object {
var clicked = 0
}
then you can use this variable everywhere, by just using: AddFavourActivity.clicked
or AddFavourActivity.clicked = 50
A companion object will ensure the same instance of the variable is used everywhere
You keep creating a new variable called clicked when you do:
var clicked = 80
You should simply do:
clicked = 80
Notice I removed the var as if you don't it simply creates a new variable withing the scope of the block called clicked and it doesn't modify the global clicked variable that you created.

Kotlin, Android Studio: I can't get my program to use a second adapter. List Views

I'm relatively new to programing on Kotlin, with Android Studio, and I'm currently developing some issues with my List Views.
I'm currently following this tutorial, and having made some changes managed to make it work for my program, even though it is focused to get data from a JSON file and I'm getting it from Firestore.
I have my data read from Firestore database. Firstly I read it to make a list of restaurants (documents) from my area, which I have no problem with. But as soon as I try to create another list based on the data from those restaurants (documents), such as categories of products on their menus (Drinks, Salads, Burgers, etc.), I am unable to get anything shown on screen, even though I'm using exactly the same methods and adapters on this new class.
This is the code I use from the first class, in which I get the list properly displayed:
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.ListView
import androidx.appcompat.app.AppCompatActivity
import com.al.tfmteleco.utiles.AdaptadorListaEstablecimientos
import com.google.firebase.firestore.FirebaseFirestore
val db = FirebaseFirestore.getInstance()
class Explorar : AppCompatActivity() {
lateinit var listView: ListView
private val establecimientosList = ArrayList<ModelEstablecimientos>()
private var establecimiento: ModelEstablecimientos? = null
private var IDEstablecimiento: Int? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_explorar)
listView = findViewById<ListView>(R.id.listaEstablecimientos)
// 1
getEstablecimientos()
listView.setOnItemClickListener{_,_,position,_ ->
finish()
establecimiento = establecimientosList[position]
IDEstablecimiento = establecimiento!!.ID
println("La ID es: $IDEstablecimiento")
val intent = Intent(this#Explorar, Establecimiento::class.java)
intent.putExtra("establecimientoID", IDEstablecimiento.toString())
startActivity(intent)
}
}
private fun getEstablecimientos() {
db.collection("establecimientos")
.get()
.addOnSuccessListener { result ->
for (document in result) {
establecimientosList.add(
ModelEstablecimientos(
document.getString("Nombre"),
document.getString("Categoria1"),
document.getString("Categoria2"),
document.getString("Categoria3"),
document.getString("Precio"),
document.getString("Localizacion"),
document.getLong("MesasDisponibles")?.toInt(),
document.getLong("MesasOcupadas")?.toInt(),
document.getLong("Abierto")?.toInt(),
document.getLong("PuntosOpiniones")?.toFloat(),
document.getLong("OpinionesTotales")?.toInt(),
document.id.toInt()
)
)
Log.d("Documentos", "${document.id} => ${document.data}")
// 2
val listItems = arrayOfNulls<String>(establecimientosList.size)
// 3
for (i in 0 until establecimientosList.size) {
val establecimiento = establecimientosList[i]
listItems[i] = establecimiento.nombre
}
// 4
val adapter =
AdaptadorListaEstablecimientos(
this,
establecimientosList
)
listView.adapter = adapter
}
}
.addOnFailureListener { exception ->
Log.d("Documentos", "Error getting documents: ", exception)
}
}
}
This one is from the Adapter Class, used for that List.
import android.content.Context
import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import com.al.tfmteleco.ModelEstablecimientos
import com.al.tfmteleco.R
class AdaptadorListaEstablecimientos(private val context: Context,
private val dataSource: ArrayList<ModelEstablecimientos>) : BaseAdapter() {
private val inflater: LayoutInflater
= context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
//1
override fun getCount(): Int {
return dataSource.size
}
//2
override fun getItem(position: Int): Any {
return dataSource[position]
}
//3
override fun getItemId(position: Int): Long {
return position.toLong()
}
//4
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
// Get view for row item
val rowView = inflater.inflate(R.layout.lista_establecimientos, parent, false)
// Get title element
val nombreTextView = rowView.findViewById(R.id.nombreEstablecimiento) as TextView
// Get cat1 element
val cat1TextView = rowView.findViewById(R.id.cat1Establecimiento) as TextView
// Get cat1 element
val cat2TextView = rowView.findViewById(R.id.cat2Establecimiento) as TextView
// Get cat1 element
val cat3TextView = rowView.findViewById(R.id.cat3Establecimiento) as TextView
// Get rangoprecio element
//val rangoprecioTextView = rowView.findViewById(R.id.precioEstablecimiento) as TextView
// Get mapa element
val mapaButton = rowView.findViewById(R.id.mapaEstablecimiento) as ImageView
// Get mesas element
val mesasTextView = rowView.findViewById(R.id.mesasEstablecimiento) as TextView
// Get mensaje element
val mensajeTextView = rowView.findViewById(R.id.mensajeEstablecimiento) as TextView
// Get info element
val infoButton = rowView.findViewById(R.id.infoEstablecimiento) as ImageView
// Get points element
val ptsTextView = rowView.findViewById(R.id.ptsOpinion) as TextView
val ratingBarView = rowView.findViewById(R.id.ratingBar) as RatingBar
// 1
val listaEstablecimientos = getItem(position) as ModelEstablecimientos
// 2
nombreTextView.text = listaEstablecimientos.nombre // NOMBRE DEL ESTABLECIMIENTO
cat1TextView.text = listaEstablecimientos.cat1 // CATEGORIA 1 DEL ESTABLECIMIENTO
cat2TextView.text = listaEstablecimientos.cat2 // CATEGORIA 2 DEL ESTABLECIMIENTO
cat3TextView.text = listaEstablecimientos.cat3 // CATEGORIA 3 DEL ESTABLECIMIENTO
// LOCALIZACIÓN DEL ESTABLECIMIENTO
if(listaEstablecimientos.loc == null){
mapaButton.visibility = View.INVISIBLE
}
else{
mapaButton.visibility = View.VISIBLE
}
// MESAS DISPONIBLES DEL ESTABLECIMIENTO
mesasTextView.text = listaEstablecimientos.mesasOcupadas.toString() +
"/" +
listaEstablecimientos.mesasDisponibles.toString() + " mesas ocupadas"
var mesasO : Float = listaEstablecimientos.mesasOcupadas!!.toFloat()
var mesasD : Float = listaEstablecimientos.mesasDisponibles!!.toFloat()
if (mesasO/mesasD <= 0.2){
mesasTextView.setTextColor(Color.parseColor("#2D6E30"))
}
else if (mesasO/mesasD <= 0.6){
mesasTextView.setTextColor(Color.parseColor("#D14F00"))
}
else if (mesasO/mesasD >= 0.85){
mesasTextView.setTextColor(Color.parseColor("#8A0000"))
}
// ESTADO DEL ESTABLECIMIENTO
if(listaEstablecimientos.mensaje == 0){
mensajeTextView.text = "Cerrado"
mensajeTextView.setTextColor(Color.parseColor("#8A0000"))
}
else if(listaEstablecimientos.mensaje == 1){
mensajeTextView.text = "Abierto"
mensajeTextView.setTextColor(Color.parseColor("#2D6E30"))
}
// PUNTUACIÓN DEL LOCAL POR PARTE DE LOS USUARIOS
var puntos : Float = listaEstablecimientos.puntos!!.toFloat()
var opiniones : Float = listaEstablecimientos.opiniones!!.toFloat()
// Formato para mostrar el número con un solo decimal
var pts= "%.${1}f".format(puntos/opiniones).toFloat()
ptsTextView.text = pts.toString()
ratingBarView.rating = pts
// Si la posición del establecimiento en la lista es par, el fondo es algo más oscuro
if(position % 2 == 0){
rowView.setBackgroundColor(Color.parseColor("#E8E8E8"))
}
return rowView
}
}
"So well, if it works, just try to adapt it" - I thought. And I tried, it should be even simplier, as I just had to use a standard list pattern, with just one item (the category name) on the list. For some reason, it doesn't work. It reads the data fine, but it cannot get to adapt another list, it seems.
This is the code I'm using and in which I'm finding trouble:
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.ArrayAdapter
import android.widget.ListView
class Categorias : AppCompatActivity() {
private lateinit var listViewCategorias: ListView
private val categoriasList = ArrayList<ModelCategorias>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_categorias)
listViewCategorias = findViewById(R.id.listaCategorias)
val establecimientoID=intent.getStringExtra("establecimientoID")
println(establecimientoID)
getCategorias(establecimientoID.toInt())
setContentView(R.layout.activity_categorias)
}
private fun getCategorias(ID:Int) {
db.collection("establecimientos").document(ID.toString()).collection("categorias")
.get()
.addOnSuccessListener { result ->
for (document in result) {
categoriasList.add(
ModelCategorias(
document.getString("Nombre_Categoria"),
document.id.toInt()
)
)
Log.d("Categorias", "${document.id} => ${document.data}")
// 2
val listItems = arrayOfNulls<String>(categoriasList.size)
// 3
for (i in 0 until categoriasList.size) {
val categoria = categoriasList[i]
listItems[i] = categoria.nombreCategoria.toString()
println(listItems[i].toString())
}
val adapter = ArrayAdapter(this,android.R.layout.simple_list_item_1, listItems)
listViewCategorias.adapter = adapter
}
}
.addOnFailureListener { exception ->
Log.d("Documentos", "Error getting documents: ", exception)
}
}
}
I'm very sorry for this very long first post, but I'm rather desperate. Excuse me for my rusty English as well.
Thank you in advance.
Activity where it's working:
val adapter = AdaptadorListaEstablecimientos(this, establecimientosList)
Activity where it's not working:
val adapter = ArrayAdapter(this,android.R.layout.simple_list_item_1, listItems)
If ArrayAdapter and AdaptadorListaEstablecimientos are basically the same adapter it shouldn't be needing an extra property (in this case, android.R.layout.simple_list_item_1). You should take a further look into the differences between the adapters.

Categories

Resources