I have a RecyclerView that gets information from FirebaseFirestore, I need that when I click on an item I change the activity and add a putExtra. I try to call an Intent inside the Adapter of my RecyclerView but I get the error 'Function declaration must have a name' and 'Expecting member declaration'.
How can I change the Activity and add a putExtra by clicking on an Item in the RecyclerView?
this is MyAdapter
package com.example.atipicoapp
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.view.menu.ActionMenuItemView
import androidx.core.content.ContextCompat.startActivity
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.list_item.view.*
class MyAdapter(private val platoList : ArrayList<Plato>,
private val itemClickListener: OnPlatoClickListener
) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
interface OnPlatoClickListener{
fun onItemClick(nombre: String)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyAdapter.MyViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false)
itemView.platoTouch.setOnClickListener(View.OnClickListener { v: View ->
})
return MyViewHolder(itemView)
}
override fun onBindViewHolder(holder: MyAdapter.MyViewHolder, position: Int) {
val plato : Plato = platoList[position]
holder.platoName.text = plato.platoName
holder.platoDescription.text = plato.platoDescription
holder.platoPrecio.text = plato.platoPrecio.toString()
holder.platoCantidad.text = plato.platoCantidad.toString()
}
override fun getItemCount(): Int {
return platoList.size
}
public class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
val platoName : TextView = itemView.findViewById(R.id.platoNombre)
val platoDescription : TextView = itemView.findViewById(R.id.platoDescripcion)
val platoPrecio : TextView = itemView.findViewById(R.id.platoPrecio)
val platoCantidad : TextView = itemView.findViewById(R.id.platoCant)
platoCantidad.setOnClickListener(View.OnClickListener {
val intent = Intent(itemView.getContext(),SlotActivity::class.java)itemView.getContext().startActivity(intent)})
}
}
You're getting an error here because you have two lines of code jammed together on one line.
val intent = Intent(itemView.getContext(),SlotActivity::class.java)itemView.getContext().startActivity(intent)})
A better way to handle this is to expose your click as a listener that the Activity (or Fragment) can implement. It would be more versatile if you change your listener function to use the item type as the parameter instead of a name String explicitly, so I would change it like this. Also, if you mark it as a fun interface, you can use more concise syntax when you define it in your Activity.
fun interface OnPlatoClickListener{
fun onItemClick(item: Plato)
}
Then in your view holder, add a parameter for the item so the click listener you put on your view can pass the item to the Activity's OnPlatoClickListener. Mark the view holder class as inner so it has access to the itemClickListener property of the adapter.
inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView){
var item: Plato? = null
val platoName : TextView = itemView.findViewById(R.id.platoNombre)
val platoDescription : TextView = itemView.findViewById(R.id.platoDescripcion)
val platoPrecio : TextView = itemView.findViewById(R.id.platoPrecio)
val platoCantidad : TextView = itemView.findViewById(R.id.platoCant)
// maybe you should set this on itemView instead so the whole row is clickable
platoCantidad.setOnClickListener {
item?.let(itemClickListener::onItemClick)
}
}
In onBindViewHolder you need to pass the item to the holder:
override fun onBindViewHolder(holder: MyAdapter.MyViewHolder, position: Int) {
val plato : Plato = platoList[position]
with(holder) {
item = plato
platoName.text = plato.platoName
platoDescription.text = plato.platoDescription
platoPrecio.text = plato.platoPrecio.toString()
platoCantidad.text = plato.platoCantidad.toString()
}
}
Then in your Activity (or Fragment), you can set a listener on the adapter when you create it:
val adapter = MyAdapter(theDataList) { clickedItem ->
val name = clickedItem.platoName
val intent = Intent(this#YourActivityName, SlotActivity::class.java)
// do something with name and intent?...
startActivity(intent)
}
// ...
override fun onBindViewHolder(holder: MyAdapter.MyViewHolder, position: Int) {
when (holder) {
is MyViewHolder -> {
holder.bind(platoList[position])
}
}
}
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val platoName : TextView = itemView.findViewById(R.id.platoNombre)
val platoDescription : TextView = itemView.findViewById(R.id.platoDescripcion)
val platoPrecio : TextView = itemView.findViewById(R.id.platoPrecio)
val platoCantidad : TextView = itemView.findViewById(R.id.platoCant)
private val mActivity = itemView.context as Activity
private val intent = Intent(mActivity, SlotActivity::class.java)
fun bind(plato: Plato) {
platoName.text = plato.platoName
platoDescription.text = plato.platoDescription
platoPrecio.text = plato.platoPrecio.toString()
platoCantidad.text = plato.platoCantidad.toString()
platoCantidad.setOnClickListener {
intent.putExtra("key", value)
mActivity.startActivity(intent)
}
}
}
Note: it is much better to use English in variable names and comments so that developers who read your code later can easily understand it.
Related
I'm creating a POS system where I'm trying to display items name in a suggestion list under the autocompletetextview and i was able to create it, But when it came to the onItemClick i hit a wall and i couldn' t display the item in a recyclerview. i did my research but couldn't find how to get these info from the database and display them in the recyclerview and i had a hard time trying to figure out if it's a problem from the Adapter or i wrote my code wrong. so can anyone help me ?
i'm trying to display the selected items from the suggestions list in the recyclerview with more info about about the item like unit price.
this is what i tried
this is the Activity where the autocompletetextview is and the listview
package com.mycodlabs.pos.ui
import android.content.Context
import android.os.Bundle
import android.view.View
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.mycodlabs.pos.R
import com.mycodlabs.pos.db.AndroidDatabase
import com.mycodlabs.pos.db.DatabaseTables
import com.mycodlabs.pos.db.inventory.InventoryDao
import com.mycodlabs.pos.db.inventory.InventoryDbo
import com.mycodlabs.pos.domain.inventory.ProductModel
import com.mycodlabs.pos.ui.sale.adapter.MyAdapter
import kotlinx.android.synthetic.main.activity_pos.*
import kotlinx.android.synthetic.main.dialog_saleedit.*
import kotlinx.android.synthetic.main.pos_bottom_sheet.*
class PosActivity : AppCompatActivity() {
private lateinit var bottomSheetBehavior: BottomSheetBehavior<LinearLayout>
private lateinit var autoCompleteTextView: AutoCompleteTextView
private lateinit var productNames: ArrayList<String>
private lateinit var recyclerView: RecyclerView
private lateinit var adapter: MyAdapter
private var selectedItems = ArrayList<ProductModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pos)
// for Back button
back.setOnClickListener {
finish()
}
//for the bottomsheet
bottomSheetBehavior = BottomSheetBehavior.from<LinearLayout>(std_btm_sht)
bottomSheetBehavior.setBottomSheetCallback(object :
BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, state: Int) {
print(state)
when (state) {
BottomSheetBehavior.STATE_HIDDEN -> {
}
BottomSheetBehavior.STATE_EXPANDED -> {
}
BottomSheetBehavior.STATE_COLLAPSED -> {
}
BottomSheetBehavior.STATE_DRAGGING -> {
}
BottomSheetBehavior.STATE_SETTLING -> {
}
BottomSheetBehavior.STATE_HALF_EXPANDED -> {
}
}
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {
}
})
// Auto Complete Textview filtering from Product table colm "productName"
val autoCompleteTextView = findViewById<AutoCompleteTextView>(R.id.searchBoxPos)
val productNames = ArrayList<String>()
var dbHelper = AndroidDatabase(this)
val db = dbHelper.readableDatabase
val cursor = db.rawQuery(
"SELECT DISTINCT ${InventoryDbo.colm_productName} FROM ${DatabaseTables.TABLE_PRODUCT} WHERE ${InventoryDbo.colm_productName} like '%%'"
,null
)
if (cursor.moveToFirst()) {
do {
productNames.add(cursor.getString(cursor.getColumnIndex("${InventoryDbo.colm_productName}")))
} while (cursor.moveToNext())
}
cursor.close()
db.close()
val adapterr = ArrayAdapter(this, android.R.layout.simple_dropdown_item_1line, productNames)
autoCompleteTextView.setAdapter(adapterr)
//// Auto Complete suggestion item display in recyclerview on select
// Create the RecyclerView
val recyclerView = findViewById<RecyclerView>(R.id.sale_List_Pos)
//// Create a layout manager for the RecyclerView
val layoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = layoutManager
//// Create an empty list to store the selected items
var selectedItems = ArrayList<ProductModel>()
//// Create an adapter for the RecyclerView
val adapter = MyAdapter(selectedItems)
recyclerView.adapter = adapter
// Set an item click listener for the AutoCompleteTextView
searchBoxPos.setOnItemClickListener { _, _, position, _ ->
// Get the selected product name and product from the list
val selectedProductName = productNames[position]
val selectedProduct = InventoryDbo.getInstance(applicationContext).getProductByName(selectedProductName)
//InventoryDbo.getProductByName(selectedProductName)
// Add the selected product to the selected items list
selectedItems.add(selectedProduct as ProductModel)
// Notify the adapter that the data has changed
adapter.notifyDataSetChanged()
// Clear the focus and text from the AutoCompleteTextView
searchBoxPos.clearFocus()
searchBoxPos.setText("")
}
}
}
this is the Adapter
package com.mycodlabs.pos.ui.sale.adapter
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.mycodlabs.pos.R
import com.mycodlabs.pos.domain.inventory.ProductModel
import com.mycodlabs.pos.domain.inventory.ProductModel1
import kotlinx.android.synthetic.main.pos_item_card.view.*
class MyAdapter(var selectedItems: List<ProductModel>) : RecyclerView.Adapter<MyAdapter.ViewHolder>() {
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val pname = itemView.pos_name
val pprice = itemView.pos_price
// val pqty = itemView.pos_qty
// val pimage = itemView.pos_image
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.pos_item_card, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val pos: ProductModel = selectedItems[position]
holder.pname.text = pos.name
holder.pprice.text = pos.unitPrice.toString()
// holder.pimage.= pos.image
// holder.pqty.text = pos.stockQty.toString()
}
override fun getItemCount() = selectedItems.size
}
Based on the logs I added in, the request is receiving all the data correctly, and the issues lies somewhere in displaying the list in the recycler list. It just prints out the last item in the your server pets array and prints its according to the length of the database array. My leaderboard seems to only been showing the last entry into the database and repeating it for the pets array length. I would like to show the entire database items in each slot. Also, I am not sure why petPhoto is not being passed through like everything other thing.
***************************************ListAcitivty.kt:****************************************
package com.example.specialpets
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.volley.Request
import com.android.volley.toolbox.JsonObjectRequest
import com.android.volley.toolbox.Volley
import org.json.JSONArray
import org.json.JSONObject
class ListActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_list)
var findArray: JSONArray
val url = "https://jwuclasses.com/ugly/leaderboard"
val jsonData=JSONObject();
val queue = Volley.newRequestQueue(this);
val request = JsonObjectRequest(Request.Method.POST, url, jsonData,
{ response ->
if (response.getInt("success") == 1) {
Log.e("app", "We have something good going on here");
findArray = response.getJSONArray("pets")
for (i in 0 until findArray.length()) {
val pet = findArray.getJSONObject(i)
val petListID = pet.getInt("id")
val petName = pet.getString("name")
val petBirthdate = pet.getString("birthdate")
val petRating = pet.getInt("rating")
val petVotes = pet.getDouble("votes")
val petPhoto = pet.getString("url")
jsonData.put("token",TokenBox.token)
//pay no attention to the man behind the curtain
//val petName = response.getString("name")
// val petListID = response.getInt("id")
//val petRating = response.getInt("rating")
// val petBirthdate = response.getString("birthdate")
// val petVotes = response.getInt("votes")
val data = ArrayList<petViewModel>()
//data.sortDescending(); Why won't this work??? Maybe because it has to be in the declaration of the array
for(i in 0 until findArray.length()) {
data.add(
petViewModel(
petListID,
petName,
petBirthdate,
petRating,
petVotes,
petPhoto
)
)
val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)
val adapter = petAdapter(data)
recyclerView.adapter = adapter
}
}
} else {
Log.e("app", "something isn't right here")
}
},{
error ->
Log.e("app", "Request did not go through and no JSON data was sent")
})
request.setShouldCache(false);
queue.add(request);
//val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
//val data = ArrayList<petViewModel>()
// for(i in 1..20){}
//****These are all my attempts at passing the data through a jsonObject request....
// data.add(petViewModel("petListID", "petName", "petBirthdate", "petRating", "petVotes",)
//take it from JSON, store it in a local array and store it
//data.add(petViewModel("Item" + i, i))
// data.add(petViewModel((response.getString("id"), response.getString("name"), response.getString("birthdate"), response.getString("rating"), response.getString("votes"))
//data.add(petViewModel(2, 2, 3, 10))
// data.add(petViewModel(response.getInt,"id", response.getString,"birthdate", response.getString""
//data.add(petViewModel(reponse.getString,"name", response.getString,"birthdate", response.getString,"rating")
//data.add(petViewModel("id", "", "", "", ""))
//data.add(petViewModel((response.getString"")))
//data.add(petViewModel("id", "name", "rating", "birthdate", "votes"))
//}
}
}
******************************************PetViewModel:****************************************
package com.example.specialpets
//class designed to hold data
data class petViewModel(val id: Int, val name: String, val birthdate: String, val rating: Int, val votes: Double, val url: String){
//id name birthdate rating votes url(picasso image)
}
******************************************PetAdapterModel:****************************************
package com.example.specialpets
import android.content.Intent
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.volley.Request
import com.android.volley.toolbox.JsonObjectRequest
import com.android.volley.toolbox.Volley
import com.squareup.picasso.Picasso
import org.json.JSONArray
import org.json.JSONObject
//an array of petviewmodel instances
class petAdapter(val dataset: ArrayList<petViewModel>): RecyclerView.Adapter<petAdapter.ViewHolder>() {
//creates a new item or a new card for a pet
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.petcard, parent, false)
return ViewHolder(view)
}
//puts the position. specific information
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val petViewModel = dataset[position]
holder.petListID.text = petViewModel.id.toString()
holder.petName.text = petViewModel.name
holder.petBirthdate.text = petViewModel.birthdate
holder.petRating.text = petViewModel.rating.toString()
holder.petVotes.text = petViewModel.votes.toString()
//picassoimg
holder.petListID.setOnClickListener{
//grab id from data object which is inside the petviewmodel
val zoomies = Intent(holder.petListID.context,ZoomerActivity::class.java)
//store with the one click one
zoomies.putExtra("ID", petViewModel.id.toString())
zoomies.putExtra("name", petViewModel.name)
zoomies.putExtra("birthdate", petViewModel.birthdate)
zoomies.putExtra("rating", petViewModel.rating.toString())
zoomies.putExtra("votes", petViewModel.votes.toString())
zoomies.putExtra("url", petViewModel.url)
//start the activity
holder.petListID.context.startActivity(zoomies)
}
}
//tells me how many items are in the list
override fun getItemCount(): Int {
return dataset.size
}
class ViewHolder(ItemView: View) : RecyclerView.ViewHolder(ItemView){
val petListID: TextView = ItemView.findViewById(R.id.petListID)
val petName: TextView = ItemView.findViewById(R.id.petName)
val petBirthdate: TextView = ItemView.findViewById(R.id.petBirthdate)
val petRating: TextView = ItemView.findViewById(R.id.petRating)
val petVotes: TextView = ItemView.findViewById(R.id.petVotes)
}
}
I would like it to have every item instead of just the last item in the JSON array.I have tried changing the for loop to a forEach loop with no changes. I have tried altering the data class: dataset with no changes as well.
this is what the app recyler view looks like
You can try following this:
class YourAdapterName(
private val context: Context,
private val dataset: ArrayList<petViewModel>
) :
RecyclerView.Adapter<HistoryAdapter.ViewHolder>() {
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val yourview: TextView = view.findViewById(R.id.historyInput)
// and your other views
init {
item.setOnClickListener {
// here is what you want do when an item is clicked
}
}
}
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.yourRecyclerViewLayoutShouldBeHere, viewGroup, false)
return ViewHolder(v)
}
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
val petViewModel = dataset[position]
viewHolder.yourview.text = petViewModel.name
// and your other views here
}
// Return the size of your ids
override fun getItemCount() = dataset.size
}
It should be all you need.
Objective
I want to expand new items in a RecyclerView at the same time, and the old selected items will be automatically collapsed.
What I done, it can be like this >>
The items expand and collapse on click but do not automatically collapse if another item is expanded
image1
Actually, what I want to make it like this >>
Any expanded item should be automatically collapse when another item is expanded.
image2
What I had researched
From this stack overflow had done what I want, but I don't how to convert into Kotlin, basically as I know it store the previous position then compare to the current position, through the If-Else Statement to determine and perform the action.
There are one more stack overflow, it also from java, slightly understand, briefly know the whole concept, but cannot go deeply explain for myself line-by-line.
This Github Sample is pretty matched my needs, but code styling quite complicated, and not fexible enough for me to add other feature and design.
Question
Why the previousPosition need to be -1?
How should separate currentPosition and previousPosition, and store the previousPosition to different object and value?
If the previousPosition is workable, how should I implement into my project?
If available, can share any related resources to me?
like: screen shot the part of sample code, or other resources
Code
product_list_item.kt
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.volley.Request
import com.android.volley.RequestQueue
import com.android.volley.toolbox.JsonObjectRequest
import com.android.volley.toolbox.Volley
import com.google.android.material.floatingactionbutton.FloatingActionButton
import org.json.JSONArray
import org.json.JSONObject
class ViewPartActivity : AppCompatActivity() {
private lateinit var newRecylerview : RecyclerView
private lateinit var newArrayList : ArrayList<Product>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_view_part)
val btnInsertView: FloatingActionButton = findViewById(R.id.btnInsertView)
btnInsertView.setOnClickListener {
val insertViewIntent = Intent(this, AddPartActivity::class.java)
startActivity(insertViewIntent)
}
getData()
}
private fun getData() {
val url = "WEBAPI"
val requestQueue: RequestQueue = Volley.newRequestQueue(this)
val jsonObjectRequest: JsonObjectRequest = JsonObjectRequest(Request.Method.GET, url, null,
{ response ->
val jsonArray: JSONArray = response.getJSONArray("tbl_product")
val namelist = ArrayList<String>()
val categorylist = ArrayList<String>()
val quantitylist = ArrayList<String>()
val pricelist = ArrayList<String>()
for (x in 0 until jsonArray.length()) {
val jsonObject: JSONObject = jsonArray.getJSONObject(x)
val name: String = jsonObject.getString("NAME")
val category: String = jsonObject.getString("CATOGORYID")
val quantity: String = jsonObject.getString("QUANTITY")
val price: String = jsonObject.getString("PRICE")
namelist.add(name)
categorylist.add(category)
quantitylist.add(quantity)
pricelist.add(price)
}
newRecylerview =findViewById(R.id.recyclerView)
newRecylerview.layoutManager = LinearLayoutManager(this)
newRecylerview.setHasFixedSize(true)
newArrayList = arrayListOf<Product>()
for(i in namelist.indices){
val product = Product(namelist[i],categorylist[i],quantitylist[i],pricelist[i])
newArrayList.add(product)
}
val adapter = ProductAdapter(newArrayList)
newRecylerview.adapter = adapter
}, { error ->
Toast.makeText(this, error.message, Toast.LENGTH_LONG).show()
})
requestQueue.add(jsonObjectRequest)
}
}
ProductAdapter.kt
class ProductAdapter(private val productList : ArrayList<Product>) : RecyclerView.Adapter<ProductAdapter.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.product_list_item, parent,false)
return MyViewHolder(itemView)
}
#SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = productList[position]
holder.tvProductName.text = currentItem.name
holder.tvProductCategory.text= currentItem.category
holder.tvProductQuantity.text=currentItem.quantity
holder.tvProductPrice.text= "RM "+currentItem.price
val isVisible : Boolean = currentItem.visibility
holder.constraintLayout.visibility = if (isVisible) View.VISIBLE else View.GONE
holder.tvProductName.setOnClickListener{
currentItem.visibility =!currentItem.visibility
notifyItemChanged(position)
}
}
override fun getItemCount(): Int {
return productList.size
}
class MyViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {
val tvProductName: TextView = itemView.findViewById(R.id.productName)
val tvProductCategory : TextView = itemView.findViewById(R.id.productCategory)
val tvProductQuantity : TextView = itemView.findViewById(R.id.productQuantity)
val tvProductPrice : TextView = itemView.findViewById(R.id.productPrice)
val constraintLayout : ConstraintLayout = itemView.findViewById(R.id.expandedLayout)
}
}
Product.kt
data class Product(
var name: String, var category: String, var quantity: String, var price: String, var visibility: Boolean = false
)
Promise
Once I get the solution, I would try my best to explain the code more deeply and update at here.
in my Main Activity I have a RecyclerView. There are multiple types of Views that can be added. All with various types of data. One View Type carries & displays Customer Information, while another View Type displays a food item with additional text and a price.
After the User is done in main activity and moves onto another Activity I want to pass all the views and their data that are in the RecyclerView and re-create it in another Activity.
How can I encapsulate all the Views that have been entered into the RecyclerView so they can be passed back and forth between Activities? It also needs to be capable of handling different View Types with different Data.
MainActivity.kt - Here is where the RecyclerView is born with multiple View types, I want to encapsulate it so it can be sent to different Activities and re-opened.
package com.example.app
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.multiplerecyclerview.Adapter
import com.example.app.*
import com.example.app.Activites.*
import com.example.app.model.DataModel
import kotlinx.android.synthetic.main.main_activity.*
const val INDEX = 0
class OrderActivity : AppCompatActivity() {
val list = ArrayList<DataModel>() /*ArrayList that is type Data Model. */
val adapter = Adapter(this, getItemsList()) /* Adapter class is initialized and list is passed in the param. */
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
recyclerView.layoutManager = LinearLayoutManager(this) /* Set the LayoutManager that this RecyclerView will use. */
recyclerView.adapter = orderAdapter /* Adapter instance is set to the recyclerview to inflate the items. */
/* Complete Button is clicked, now encapsulating RecyclerView and passing to next Activity. */
complete_btn.setOnClickListener {
val total = textViewPrice.text.toString()
val intent = Intent(this#MainActivity, LiveOrderActivity::class.java)
intent.putExtra("total", total)
intent.putExtra("customerName", customerName)
intent.putExtra("customerNumber", customerNumber)
intent.putExtra("customerPostal", customerPostal)
intent.putExtra("customerAddress", customerAddress)
/* HOW DO I PASS ALL THE DATA FROM THE RECYCLER VIEW HERE??? */
startActivity(intent)
}
}
/* One ViewType, customer with a certain criteria of data. */
private fun insertCustomer(customerName: String, customerNumber: String, customerPostal: String, customerAddress: String) {
val newItem = DataModel(
customerName = customerName,
customerNumber = customerNumber,
customerPostal = customerPostal,
customerAddress = customerAddress,
viewType = OrderAdapter.CUSTOMER
) /* Adding the item with correct arguments */
list.add(INDEX, newItem) /* Adding Item at Position Index. */
orderAdapter.notifyItemInserted(INDEX) /* Notifying the Adapter of the addition. */
}
/* Another ViewType, with a different set of data. */
private fun insertCharge(charge: String) {
Toast.makeText(this, "Delivery Charge Added!", Toast.LENGTH_SHORT).show() /* Toast Message to confirm insertion. */
val newItem = DataModel(
delivery = "$charge",
viewType = OrderAdapter.DELIVERY_CHARGE
) /* Adding the item with correct arguments */
list.add(INDEX, newItem) /* Adding Item at Position Index. */
orderAdapter.notifyItemInserted(INDEX) /* Notifying the Adapter of the addition. */
}
/* Another ViewType, with a different set of data. */
private fun insertOpenFood(openFoodDetails: String, openFoodPrice: String) {
Toast.makeText(this, "Open Food Added!", Toast.LENGTH_SHORT).show() /* Toast Message to confirm insertion. */
val newItem = DataModel(
openFoodDetails = "$openFoodDetails",
openFoodCharge = "$openFoodPrice",
viewType = OrderAdapter.OPEN_FOOD_CHARGE
) /* Adding the item with correct arguments */
list.add(INDEX, newItem) /* Adding Item at Position Index. */
orderAdapter.notifyItemInserted(INDEX) /* Notifying the Adapter of the addition. */
}
private fun getItemsList(): ArrayList<DataModel> {
//list.add(DataModel("Ham Burger","1","12.50", viewType = OrderAdapter.NO_TOPPING))
//list.add(DataModel("American","1","12.50", viewType = OrderAdapter.NO_TOPPING))
return list
}
}
Adapter.kt - This is the Adapter I am using for the RecyclerView in MainActivity.kt
package com.example.multiplerecyclerview
import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat.startActivity
import androidx.recyclerview.widget.RecyclerView
import com.example.app.model.DataModel
import com.example.app.R
import kotlinx.android.synthetic.main.openfood_charge.view.*
import kotlinx.android.synthetic.main.delivery_charge.view.*
import kotlinx.android.synthetic.main.customer_item.view.*
class Adapter(val context: Context, val items: ArrayList<DataModel>) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
companion object {
const val NO_TOPPING = 1
const val DELIVERY_CHARGE = 9
const val OPEN_FOOD_CHARGE = 12
const val CUSTOMER = 21
}
/* Depending on the View Type, the correct one is passed. */
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
if(viewType == NO_TOPPING)
return ViewHolder(LayoutInflater.from(context).inflate( R.layout.food_item,parent,false))
else if (viewType == DELIVERY_CHARGE)
return ViewHolder2(LayoutInflater.from(context).inflate(R.layout.delivery_charge,parent,false))
else if (viewType == OPEN_FOOD_CHARGE)
return ViewHolder3(LayoutInflater.from(context).inflate(R.layout.openfood_charge,parent,false))
else if (viewType == CUSTOMER)
return ViewHolder7(LayoutInflater.from(context).inflate(R.layout.customer_item,parent,false))
else
return ViewHolder(LayoutInflater.from(context).inflate( R.layout.food_item,parent,false))
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val item = items.get(position)
if(holder is ViewHolder) {
holder.productQuantity.text = item.itemQuantity
holder.productName.text = item.itemName
holder.productPrice.text = item.itemPrice
}else if(holder is ViewHolder2) {
holder.deliveryPrice.text = item.delivery
} else if(holder is ViewHolder3) {
holder.openFoodDetails.text = item.openFoodDetails
holder.openFoodPrice.text = item.openFoodCharge
} else if(holder is ViewHolder7) {
holder.customer.text = item.customerName
holder.number.text = item.customerNumber
holder.eircode.text = item.customerPostal
holder.address.text = item.customerAddress
}
}
override fun getItemViewType(position: Int): Int {
return items[position].viewType
}
override fun getItemCount(): Int {
return items.size
}
class ViewHolder(view: View) : RecyclerView.ViewHolder(view), View.OnClickListener {
val productQuantity = view.productQuantityView
val productName = view.productNameView
val productPrice = view.productPriceView
init { /* Acts like a constructor in Java. */
view.setOnClickListener(this)
}
override fun onClick(v: View?) {
TODO("Not yet implemented")
}
}
interface onItemClickListener {
fun onItemClick()
}
class ViewHolder2(view: View) : RecyclerView.ViewHolder(view), View.OnClickListener {
var deliveryPrice = view.deliveryPriceView
val intent: Intent? = null
init {
view.setOnClickListener(this)
}
override fun onClick(v: View?) {
}
}
class ViewHolder3(view: View) : RecyclerView.ViewHolder(view) {
var openFoodDetails = view.openFoodView
var openFoodPrice = view.openFoodPriceView
}
class ViewHolder7(view: View) : RecyclerView.ViewHolder(view) {
val customer = view.nameView
val number = view.mobileView
val eircode = view.eircodeView
val address = view.address1View
}
}
SecondActivity.kt - Here I want to recieve the RecyclerView's Data and recreate it.
package com.example.app
class ActiveOrderActivity : AppCompatActivity() {
private val aorderList = generateList(50)
private val adapter = AOrdersAdapter(aorderList)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_active_order)
recyclerview.adapter = adapter
recyclerview.layoutManager = LinearLayoutManager(this)
recyclerview.setHasFixedSize(true)
insertItem()
/* Here I want to recieve the RecyclerView Data! */
val customerName: String = intent.getStringExtra("customerName").toString()
val customerNumber: String = intent.getStringExtra("customerNumber").toString()
if (customerName == "null") { /*If no RecyclerView has been passed. */
} else {
insertNewOrder(customerName, customerNumber, customerPostal, customerAddress, paymentType, paymentTotal)
}
}
fun insertItem() {
}
private fun insertNewOrder(customerName: String, customerNumber: String, customerPostal: String, customerAddress: String, paymentType: String, paymentTotal: String) {
val newItem = ActiveOrderModel(customerName,customerNumber, customerPostal, customerAddress, paymentTotal, paymentType)
aorderList.add(0, newItem) /* Adding Item at Position Index. */
adapter.notifyItemInserted(0) /* Notifying the Adapter of the addition. */
/* Creating a new Customer. */
val order = hashMapOf(
"customer Name" to customerName,
"customer Number" to customerNumber,
"eircode" to customerPostal,
"address" to customerAddress,
"paymentTotal" to paymentTotal
)
}
private fun generateList(size: Int): ArrayList<ActiveOrderModel> {
val list = ArrayList<ActiveOrderModel>()
return list
}
}
Create an interface
interface ViewHolderCallback{ fun onViewHolderSumitData(val data: Data) }
Then your ViewHolder, ViewHolder2, ViewHolder3, ViewHolder7 will require an implementation of this ViewHolderCallback interface via their constructor
class ViewHolder(view: View, val callback: ViewHolderCallback)
Your activity will implement ViewHolderCallback which requires it to override onViewHolderSumitData method. You will receive the Viewholder data here. Do whatever you want.
Then in your View Holders, when ever you feel need to sent data to activity execute callback.onViewHolderSumitData - you will need to create the Data param yourself base on the data inside your ViewHolder.
If the Data param in onViewHolderSumitData give you a hard time. Just create the method no param. Have activity implement it then set debug breakpoint. You will get the idea.
P/s you can foward the interface imlementation from Activty to View Holders vis Adapter
class Adapter(callback: ViewHolderCallback)
I want to create an android app with Kotlin. In this app, i use swagger also to get all the web service in a file.
I want to create an interface, the description is as follows:
A RecyclerView horizontal that contains all the list of categories
comes from a web service apiMobileProductCategoriesGetAllPost.
after that, when i click on a which category, a RecyclerView(Grid)
appear that contains all the product by category id.
I want to know how can i get the category id when i click on item,and how to use it in the activity
The following the RecyclerView category adapter:
class CategoryAdapter(private val categories: Array<ProductCategoryData>) :
RecyclerView.Adapter<CategoryAdapter.ViewHolder>(), View.OnClickListener {
private var onItemClickListener: OnItemClickListener? = null
override fun onClick(v: View?) {
if (v != null) {
onItemClickListener?.onItemClick(v, ProductCategoryData())
}
}
fun setOnItemClickListener(onItemClickListener: OnItemClickListener) {
this.onItemClickListener = onItemClickListener
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.category_item, parent, false)
view.setOnClickListener(this)
return ViewHolder(view)
}
override fun getItemCount() = categories.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val itemCategory: ProductCategoryData = categories[position]
holder.categoryId.text = itemCategory.id.toString()
println(holder.categoryId.text)
println(itemCategory.name?.get("En").toString())
holder.categoryName.text = itemCategory.name?.get("En").toString()
println(itemCategory.id)
if (itemCategory.logo != null) {
Picasso.get()
.load("..../T/${itemCategory.logo}")
.into(holder.categoryImage, object : com.squareup.picasso.Callback {
override fun onError(e: Exception?) {
holder.categoryImage.setImageResource(R.drawable.homecraftdefault)
}
override fun onSuccess() {
Picasso.get().load("....T/${itemCategory.logo}")
.into(holder.categoryImage)
}
})
holder.itemView.setOnClickListener {
onItemClickListener?.onItemClick(holder.itemView,itemCategory)
}
}
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
val categoryName: TextView = itemView.categoryName
val categoryImage: ImageView = itemView.categoryImage
val categoryId: TextView = itemView.categoryId
override fun onClick(v: View?) {
if (v != null) {
onItemClickListener?.onItemClick(v, ProductCategoryData())
}
}
}
interface OnItemClickListener {
fun onItemClick(view : View, viewModel:ProductCategoryData)
}
}
The following code is relative to the activity:
class CategoryByProduct : AppCompatActivity(), CategoryAdapter.OnItemClickListener {
override fun onItemClick(view: View, viewModel: ProductCategoryData) {
var params = "CategoryProductID";"5cc057458c4d9823743736d2"
println(viewModel.id)
val products = mobileApi!!.apiMobileProductsGetAllPost(params, 0, 50, "", "")
recyclerViewProductByCategory.apply {
recyclerViewProductByCategory.layoutManager = GridLayoutManager(this#CategoryByProduct, 2)
recyclerViewProductByCategory.adapter = ProductAdapter(products)
} }
var mobileApi: MobileApi? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.list_product_by_category)
mobileApi = MobileApi()
val params = HashMap<String, String>()
GlobalScope.launch(Dispatchers.IO) {
val categories = mobileApi!!.apiMobileProductCategoriesGetAllPost(params, 0, 50, "", "")
withContext(Dispatchers.Main) {
recyclerViewCategories.apply {
recyclerViewCategories.layoutManager =
LinearLayoutManager(this#CategoryByProduct, OrientationHelper.HORIZONTAL, false)
recyclerViewCategories.adapter = CategoryAdapter(categories)
}
}
}
}
}
First of all , never put your onclick in onBindViewHolder That's not a good practice, after that i think you need to get the ID of the category i will give you simple example in all of the Adapter Class
class NewsAdapter (val context: Context, private val arrayList: ArrayList <NewsModel>):
RecyclerView.Adapter <NewsAdapter.Holder> () {
companion object {
// val TAG: String = OperationAdapter::class.java.simpleName
}
override fun onCreateViewHolder (parent: ViewGroup, viewType: Int): Holder {
return Holder (LayoutInflater.from (parent.context ).inflate (R.layout.newslist , parent, false))
}
override fun getItemCount (): Int = arrayList. size
override fun onBindViewHolder (holder: Holder, position: Int) {
val mynews = arrayList[position]
holder.setData(mynews , position)
}
inner class Holder (itemView: View): RecyclerView.ViewHolder (itemView) {
private var currentnews: NewsModel? = null
private var currentPosition: Int = 0
init {
//The click listener
itemView.newscardview.setOnClickListener {
//do it here
Toast.makeText(this,currentnews!!.id,Toast.LENGTH_SHORT).show()
}
//the end of the init
}
//getting data from model and bind it into View
fun setData(news: NewsModel?, position: Int) {
news?.let {
itemView.newsid.text = news.id
itemView.newstitle.text = news.title
itemView.body.text = news.body
itemView.txtdate.text = news.ndate
}
this.currentnews = news
this.currentPosition = position
}
}
}
In this example you will get the news ID when you click newscardview, i hope to understand it
In your Activity
put this code in onCreate
//set up the recycleview
mRecyclerView.setHasFixedSize (true)
mRecyclerView. layoutManager = LinearLayoutManager(this)
mRecyclerView is my RecycleView
also call your Adapter class in anywhere you want
//adapter
val adapter = NewsAdapter (this,arrayList)
adapter.notifyDataSetChanged()
mRecyclerView.adapter = adapter
you get the position of the category inside a viewholder by calling adapterPosition and with this you can get the category from your list you provide to your adapter in the constructor (categories[adapterPosition])
In your case it is very simple.Try these:-
holder.tv_broadcast_title.text=broadList[position].name
where broadlist is my array list created in the adapter itself.In this list the json data is getting stored from api.
internal var broadList = ArrayList<Model>()
and .name is the name of key to fetch name from json data.
holder.categoryName.text = itemCategory.name?.get("En").toString()
in your case do something like this:-
itemCategory[position].name
To get data from adapter to activity, you can make an interface in the adapter or globally and from the activity you can pass that interface in adapter's constructor and use that to get data. I am giving you an example.
interface ProductCategoryListner {
fun getProductCategory(viewModel:ProductCategoryData)
}
Not in adapter's constructor add this interface.
class CategoryAdapter(private val categories: Array<ProductCategoryData>,private val productCategoryListner: ProductCategoryListner):
RecyclerView.Adapter<CategoryAdapter.ViewHolder>(), View.OnClickListener {
Now you can use this to pass data in the activity when you click on view.
productCategoryListner.getProductCategory(categories[adapterPosition])