I am attempting to use startActivityForResult to return information that can be used as data to be entered into a RecyclerView in the original Activity.
In Activity 1, I have set an onClickListener for a button. Once the button is pressed Activity 2 is launched with some options. The User fills in these options and then they are returned to the Activity 1.
Activity 1 then inserts an entry into the RecyclerView with information recieved from the button press and from the options returned from Activity 2.
The problem is that once Activity 2 finishes and returns back to Activity 1 the entry is not added to the RecyclerView as it should. How can I fix my code so that the entry is added correctly?
OrderActivity.kt - Activity 1
package com.example.pos
import android.app.Activity
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.multiplerecyclerview.OrderAdapter
import kotlinx.android.synthetic.main.activity_order.*
const val FILE_ID = 1
class OrderActivity : AppCompatActivity() {
val list = ArrayList<DataModel>()
// Adapter class is initialized and list is passed in the param.
val orderAdapter = OrderAdapter(this, getItemsList())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_order)
margButton.setOnClickListener {
val food = "Margerita"
val price = 11.90
Toast.makeText(this, "$food clicked", Toast.LENGTH_LONG).show()
val intent = Intent(this#OrderActivity, PizzaActivity::class.java) /* Creating an Intent to go to Dashboard. */
intent.putExtra("foodName", "$food")
intent.putExtra("foodPrice", "$price")
startActivityForResult(intent, FILE_ID) /* Starting Activity. */
Log.i("Order", "startActivityResult.\n")
}
//Set the LayoutManager that this RecyclerView will use.
orderRecyclerView.layoutManager = LinearLayoutManager(this)
//adapter instance is set to the recyclerview to inflate the items.
orderRecyclerView.adapter = orderAdapter
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
Log.i("Order", "OnActivityResult.\n")
if(requestCode == FILE_ID && resultCode == Activity.RESULT_OK) {
val foodPrice = intent.getStringExtra("foodPrice")
val foodSize = intent.getStringExtra("foodSize")
insertItem(view = margButton, foodType = "Margherita", price = foodPrice!!.toDouble(), size = foodSize!!)
Log.i("Order", "startActivityResult success\n")
} else {
Log.i("Order", "onActivityResult failed\n")
}
}
fun insertItem(view: View, foodType: String, price: Double, size: String) {
val index = 0
Toast.makeText(this, "Margerita clicked", Toast.LENGTH_LONG).show()
val newItem = DataModel("$foodType", "$size", "$price", viewType = OrderAdapter.NO_TOPPING)
list.add(index, newItem)
orderAdapter.notifyItemInserted(index)
}
private fun getItemsList(): ArrayList<DataModel> {
list.add(DataModel("Romana","1","12.50", "Pepperoni", "Aubergine", "Ex Mozz.", "Salami", OrderAdapter.TOPPINGS_4))
list.add(DataModel("American","1","12.50", viewType = OrderAdapter.NO_TOPPING))
return list
}
}
PizzaActivity.kt - Activity 2
package com.example.pos
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.EditText
import android.widget.TextView
import android.widget.Toast
import com.example.multiplerecyclerview.OrderAdapter
import kotlinx.android.synthetic.main.activity_order.*
import kotlinx.android.synthetic.main.activity_pizza.*
class PizzaActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pizza)
val ss1:String = intent.getStringExtra("foodName").toString()
val ss2:String = intent.getStringExtra("foodPrice").toString()
val textView1: TextView = findViewById<TextView>(R.id.pizzaName)
textView1.text = ss1
val textView2: TextView = findViewById<TextView>(R.id.pizzaPrice)
val textView3: TextView = findViewById<TextView>(R.id.pizzaSize)
val editText1: EditText = findViewById<EditText>(R.id.topping1Entry)
val editText2: EditText = findViewById<EditText>(R.id.topping2Entry)
val editText3: EditText = findViewById<EditText>(R.id.topping3Entry)
val editText4: EditText = findViewById<EditText>(R.id.topping4Entry)
tenInchButton.setOnClickListener {
Toast.makeText(this, "Ten inch selected", Toast.LENGTH_LONG).show()
insertSize(size = "10", textView = textView3)
setPrice(price = 9.9, textView = textView2)
}
twelveInchButton.setOnClickListener {
Toast.makeText(this, "Twelve inch selected", Toast.LENGTH_LONG).show()
insertSize(size = "12", textView = textView3)
setPrice(price = 11.8, textView = textView2)
}
additionalButton.setOnClickListener {
var cost = .90
if(textView3.equals("10")) {
changePrice(price = cost, textView = textView2)
} else {
cost = 1.1
changePrice(price = cost, textView = textView2)
}
}
premiumButton.setOnClickListener {
var cost = 1.3
if(textView3.equals("10")) {
changePrice(price = cost, textView = textView2)
} else {
cost = 1.5
changePrice(price = cost, textView = textView2)
}
}
completeBtn.setOnClickListener {
emptyAdditions(editText1)
val intent = Intent(this#PizzaActivity, OrderActivity::class.java) /* Creating an Intent to go to Dashboard. */
intent.putExtra("foodPrice", "$textView2")
intent.putExtra("foodSize", "$textView3")
if (!emptyAdditions(editText1) || !emptyAdditions(editText2) || !emptyAdditions(editText3) || !emptyAdditions(editText4)) {
intent.putExtra("topping1", "$editText1")
intent.putExtra("topping2", "$editText2")
intent.putExtra("topping3", "$editText3")
intent.putExtra("topping4", "$editText4")
setResult(Activity.RESULT_OK, intent)
} else {
setResult(Activity.RESULT_OK, intent)
}
finish()
}
}
private fun emptyAdditions(editText: EditText): Boolean {
val msg: String = editText.text.toString()
//check if the EditText have values or not
return msg.trim().isNotEmpty()
}
private fun insertSize(size: String, textView: TextView) {
textView.text = size
}
private fun setPrice(price: Double, textView: TextView) {
textView.text = price.toString()
}
private fun changePrice(price: Double, textView: TextView) {
var cost = textView.text.toString()
var total = (cost.toDouble() + price)
textView.text = total.toString()
}
}
Here is Activity 1. The Buttons are on the left and the RecyclerView is on the right. Once the Margherita Pizza is pressed you are brought to Activity 2.
Here is Activity 2. Once you have selected a Size you can press complete Pizza. Once you press complete Pizza it returns you to Activity 1 and the 12 inch Margerita is added to the RecyclerView.
Error Message:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.pos, PID: 30885
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=Intent { cmp=com.example.pos/.OrderActivity (has extras) }} to activity {com.example.pos/com.example.pos.OrderActivity}: kotlin.KotlinNullPointerException
at android.app.ActivityThread.deliverResults(ActivityThread.java:4268)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4312)
at android.app.ActivityThread.-wrap19(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1644)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Caused by: kotlin.KotlinNullPointerException
at com.example.pos.OrderActivity.onActivityResult(OrderActivity.kt:58)
at android.app.Activity.dispatchActivityResult(Activity.java:7276)
at android.app.ActivityThread.deliverResults(ActivityThread.java:4264)
Related
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.
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)
}
}
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 11 months ago.
Improve this question
Good day. So I am trying to add data to my tables by an action. I currently have it is static and would like to know the best way to insert data. My end goal is for a driver to be selected and based on the driver name that was selected it will pull that drivers deliveries for the day. I have seen post about fragments but don't know if that will be relevant to me.
MainActivity
package com.dispatch.tripsheet
import android.os.Bundle
import android.view.View
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
private var dbHandler: DBHandler? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
recyclerViewTripsheetlist.layoutManager = LinearLayoutManager(this)
recyclerViewTripsheetlist.adapter = TableViewAdapter(Tripsheetlist)
//This is for the drivers. Drivers still need to be pulled from the database
val list : MutableList<String> = ArrayList()
list.add("Deon")
list.add("Leon")
list.add("David")
list.add("Dick")
list.add("Jim")
list.add("Harry")
val adapter = ArrayAdapter( this, androidx.appcompat.R.layout.support_simple_spinner_dropdown_item, list)
val spinner: Spinner = findViewById(R.id.spnDriver)
spinner.adapter = adapter
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener{
override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
val item :String = list[p2]
Toast.makeText(this#MainActivity, "Driver $item selected", Toast.LENGTH_SHORT).show()
}
override fun onNothingSelected(p0: AdapterView<*>?) {
//empty
}
//insert code that activates data pull of tripsheet for driver= actifavte by method the class/object that activates the data pull. so datapuul(Driver)
}
limitDropDownHeight(spinner)
//drivers end
val btnLoadData: Button = findViewById(R.id.btnLoadData)
weightsum(tvTotalweight, Tripsheetlist)
totaldelNotes(tvTotaldelv,Tripsheetlist)
setData(btnLoadData,Tripsheetlist)
}
val Tripsheetlist = ArrayList<DataModel>().apply {
add(DataModel(190617, 182832, "", 0,"", "",""))
// Need one row for dummy data. Gets removed so chance wont be seen.
add(DataModel(190617, 182832, "Jcorp", 100,"Delivery done", "Delivery not done",""))
add(DataModel(190617, 182833, "Honda", 100,"No exceptions", "Exceptions",""))
add(DataModel(190617, 182832, "Everflu", 100,"100%", "50%",""))
add(DataModel(190617, 182832, "Panado", 300,"OK", "NO",""))
add(DataModel(190617, 182832, "Gheiters", 100,"Success", "Failed",""))
add(DataModel(190617, 182832, "John", 300,"Yes", "No",""))
// need to change from hardcoded text to input
//these values will change from sql input
var a = 10000
var b = 10000
var c = "Absa"
var d = 50
var e = "No exceptions"
var f = "Exceptions"
var g = ""
// value to changes based on data size.
var x: Int = 29
for (i in 20..x)
{
add(DataModel(a,b,c,d,e,f,g))
a++
}
// })
}
//setData is not 100% ready
private fun setData(btnLoadData: Button, Tripsheetlist: ArrayList<DataModel>) {
btnLoadData.setOnClickListener(View.OnClickListener {
var x: Int = 2
for (i in 3..6)
{ //does not work
this.Tripsheetlist[x].WOrder = 20022
this.Tripsheetlist[x].DElNote = 20022
this.Tripsheetlist[x].Company = "FNB"
this.Tripsheetlist[x].Weight = 20
this.Tripsheetlist[x].Button1 = "No exceptions"
this.Tripsheetlist[x].Button2 = "Exceptions"
this.Tripsheetlist[x].tvdone = ""
x++
}
btnLoadData.setBackgroundColor(getColor(R.color.green))
}
})
}
//works
fun weightsum(args: TextView, Tripsheetlist: ArrayList<DataModel>) {
var totweight: Int = 0
var sum: Int = 0
for (i in 0 until Tripsheetlist.size -1) {
sum += Tripsheetlist[i].Weight
}
totweight = sum
tvTotalweight.setText("Total Weight: " + totweight + "kg")
}
//works
fun totaldelNotes(tvTotaldelv: TextView?, Tripsheetlist: ArrayList<DataModel>) {
var totnotes: Int = 1
var sum: Int = 0
// var input: String
totnotes = Tripsheetlist.size -1
tvTotaldelv?.setText("Total Delivery Notes: " +totnotes)
}
//works
fun limitDropDownHeight(spinner: Spinner){
val popup = Spinner::class.java.getDeclaredField( "mPopup")
popup.isAccessible = true
val popupWindow = popup.get(spinner)as ListPopupWindow
popupWindow.height = (200 * resources.displayMetrics.density).toInt()
}
}
TableViewAdapter
package com.dispatch.tripsheet
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.table_list_item.view.*
class TableViewAdapter( var Tripsheetlist: List<DataModel> = emptyList()) : RecyclerView.Adapter<TableViewAdapter.RowViewHolder>() {
// var dataItems: List<DataModel> = emptyList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RowViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.table_list_item, parent, false)
return RowViewHolder(itemView)
}
override fun getItemCount(): Int { return Tripsheetlist.size// + 1 // one more to add header row
}
private fun updateData(data: List<DataModel>) {
Tripsheetlist = data
notifyDataSetChanged()
}
override fun onBindViewHolder(holder: RowViewHolder, position: Int) {
val rowPos = holder.adapterPosition
val dataItem = Tripsheetlist[position]
if (rowPos == 0) {
// Header Cells. Main Headings appear here
holder.itemView.apply {
setHeaderBg(txtWOrder)
setHeaderBg(txtDElNote)
setHeaderBg(txtCompany)
// setHeaderBg(txtAddress)
setHeaderBg(txtWeight)
setHeaderBg(txtbutton1)
setHeaderBg(txtbutton2)
setHeaderBg(txttvdone)
txtWOrder.text = "WOrder"
txtDElNote.text = "DElNote"
txtCompany.text = "Company"
// txtAddress.text = "Address"
txtWeight.text = "Weight"
txtbutton1.text = "Delivered"
txtbutton2.text = "Exception"
txttvdone.text = ""
}
} else {
val modal = Tripsheetlist[rowPos ]
holder.itemView.apply {
setContentBg(txtWOrder)
setContentBg(txtDElNote)
setContentBg(txtCompany)
// setContentBg(txtAddress)
setContentBg(txtWeight)
setContentBg(txtbutton1)
setContentBg(txtbutton2)
setContentBg(txttvdone)
txtWOrder.text = modal.WOrder.toString()
txtDElNote.text = modal.DElNote.toString()
txtCompany.text = modal.Company.toString()
// txtAddress.text = modal.Address.toString()
txtWeight.text = modal.Weight.toString()
txtbutton1.text = modal.Button1.toString()
txtbutton2.text = modal.Button2.toString()
txttvdone.text = modal.tvdone.toString()
}
}
holder.txttvdone.apply {
setBackgroundResource(when (dataItem.state) {
DataState.Unselected -> android.R.color.transparent
DataState.Success -> R.color.green
DataState.Failure -> R.color.orange
})
text = when (dataItem.state) {
DataState.Unselected -> ""
DataState.Success -> "✓"
DataState.Failure -> "x"
//this is where I add code to export data through api maybe add it in the datastate set where it is success and Failure
}
}
holder.apply {
txtbutton1.setOnClickListener {
Log.e("Clicked", "Successful delivery")
//this is where I add code to export data through api
dataItem.state = DataState.Success
notifyDataSetChanged()
}
txtbutton2.setOnClickListener {
Log.e("Clicked", "Exception on delivery")
dataItem.state = DataState.Failure
notifyDataSetChanged()
}
}
}
class RowViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
val txttvdone:TextView = itemView.findViewById<TextView>(R.id.txttvdone)
val txtbutton1:Button = itemView.findViewById<Button>(R.id.txtbutton1)
val txtbutton2:Button = itemView.findViewById<Button>(R.id.txtbutton2)
}
class MyViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
var txtbutton1 = view.findViewById<Button>(R.id.txtbutton1)
val txtbutton2:Button = itemView.findViewById<Button>(R.id.txtbutton2)
var txttvdone = view.findViewById<TextView>(R.id.txttvdone)
}
private fun setHeaderBg(view: View) {
view.setBackgroundResource(R.drawable.table_header_cell_bg)
}
private fun setContentBg(view: View) {
view.setBackgroundResource(R.drawable.table_content_cell_bg)
}
}
I have created something with a button just to test it out. But what happens is. The data only changes after clicking the load data button and then a button on my recycler view, which is not ideal.
btnLoadData.setOnClickListener(View.OnClickListener {
var x: Int = 2
for (i in 3..6)
{ //does not work
this.Tripsheetlist[x].WOrder = 20022
this.Tripsheetlist[x].DElNote = 20022
this.Tripsheetlist[x].Company = "FNB"
this.Tripsheetlist[x].Weight = 20
this.Tripsheetlist[x].Button1 = "No exceptions"
this.Tripsheetlist[x].Button2 = "Exceptions"
this.Tripsheetlist[x].tvdone = ""
x++
}
Any and all help is appreciated. Let me know if any additional information is needed.
For my layouts. I have a activity main with my recycler view and then a table list item for my rows. Below is how my app looks.
There are two ways to approach this,
add a setData method to RV , so your part of code looks like
class TableViewAdapter(){
private var data : List<DataModel> = emptyList()
fun setData( newData : List<..>){
data = newData
notifyDataSetChanged() // and handle other events to update
}
}
then you can update data on go
use DiffUtil supported RV like ListAdapter or implement it yourself
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'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.