Using Kotlin to update ActionBar in Android RecyclerViewAdapter - android

I have a RecyclerViewAdapter for a shopping cart application written in Kotlin. When users change the quantity of items in their cart I would like to update the title of the ActionBar with the current cart total.
I've looked at various code using callbacks, listeners, and passing context to try to access the ActionBar from the RecyclerViewAdapter but I don't know if these are applicable to Kotlin nor do they make too much sense having always kept all of my code within the RecyclerViewAdapter (database lookups, writes, CardView updates, etc.)
Here is the highly abbreviated code for my calling code and the RecyclerViewAdapter (but I hope that I have all of the important components):
class ItemRecyclerViewAdapter(private val itemArray: MutableList<ItemObject>, private val contextABC: Context) : RecyclerView.Adapter<ItemRecyclerViewAdapter.ViewHolder>() {
inner class ViewHolder(v: View) : RecyclerView.ViewHolder(v) {
private val cardViewAdd: Button
init {
cardViewAdd = v.findViewById<View>(R.id.cardview_item_Add) as Button
// Add one to Qty Ordered
cardViewAdd.setOnClickListener { updateItemQty(adapterPosition, itemArray[adapterPosition].qtyOrdered + 1, v) }
}
}
private fun updateItemQty(arrayPosition: Int, pQtyOrdered: Int, v: View) {
itemArray[arrayPosition].qtyOrdered = pQtyOrdered
notifyItemChanged(arrayPosition)
}
}
class CartActivity : BaseActivity() {
internal var cartItemsList: MutableList<ItemObject> = ArrayList()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.cart_master)
cartItemsList = DatabaseAdapter.cartItems
cart_RecyclerView.setHasFixedSize(true)
cart_RecyclerView.layoutManager = LinearLayoutManager(this)
rvAdapter = ItemRecyclerViewAdapter(cartItemsList, this)
cart_RecyclerView.adapter = rvAdapter
}
}
Can anyone get me going in the correct direction? I certainly appreciate the help!
[Edit]
With the great help of Birju Vachhani, here is my working code:
class ItemRecyclerViewAdapter(private val itemArray: MutableList<ItemObject>,
private val contextABC: Context, val updateActionBarTitle: (ItemObject) -> Unit = {})
: RecyclerView.Adapter<ItemRecyclerViewAdapter.ViewHolder>() {
inner class ViewHolder(v: View) : RecyclerView.ViewHolder(v) {
private val cardViewAdd: Button
init {
cardViewAdd = v.findViewById<View>(R.id.cardview_item_Add) as Button
// Add one to Qty Ordered
cardViewAdd.setOnClickListener { updateItemQty(adapterPosition, itemArray[adapterPosition].qtyOrdered + 1, v) }
}
}
private fun updateItemQty(arrayPosition: Int, pQtyOrdered: Int, v: View) {
itemArray[arrayPosition].qtyOrdered = pQtyOrdered
notifyItemChanged(arrayPosition)
updateActionBarTitle(itemArray[arrayPosition])
}
}
class CartActivity : BaseActivity() {
internal var cartItemsList: MutableList<ItemObject> = ArrayList()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.cart_master)
cartItemsList = DatabaseAdapter.cartItems
cart_RecyclerView.setHasFixedSize(true)
cart_RecyclerView.layoutManager = LinearLayoutManager(this)
rvAdapter = ItemRecyclerViewAdapter(cartItemsList, this){item->
supportActionBar?.setTitle("hi")
}
cart_RecyclerView.adapter = rvAdapter
}
}

You can do it by using Kotlin's lambda functions like this:
Adapter:
class ItemRecyclerViewAdapter(
private val itemArray: MutableList<ItemObject>,
val onItemAdded: (ItemObject) -> Unit = {}
) :
RecyclerView.Adapter<ItemRecyclerViewAdapter.ViewHolder>() {
override fun getItemCount(): Int {
return itemArray.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_layout,parent,false))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.cardViewAdd.setOnClickListener {
updateItemQty(position, itemArray[position].qtyOrdered + 1)
onItemAdded(itemArray[position])
}
}
class ViewHolder(v: View) : RecyclerView.ViewHolder(v) {
val cardViewAdd: Button = v.findViewById(R.id.cardview_item_Add)
fun bind(item:ItemObject){
// bind your data with view here
}
}
fun updateItemQty(arrayPosition: Int, pQtyOrdered: Int) {
itemArray[arrayPosition].qtyOrdered = pQtyOrdered
notifyItemChanged(arrayPosition)
}
}
In Your Activity:
class CartActivity : BaseActivity() {
internal var cartItemsList: MutableList = ArrayList()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.cart_master)
cartItemsList = DatabaseAdapter.cartItems
cart_RecyclerView.setHasFixedSize(true)
cart_RecyclerView.layoutManager = LinearLayoutManager(this)
rvAdapter = ItemRecyclerViewAdapter(cartItemsList, this){item->
// here you can access your ActionBar as perform actions on it
}
cart_RecyclerView.adapter = rvAdapter
}
}

Related

null cannot be cast to non-null type RecyclerView with stateFlow

I got some categories from an api and trying to show them on a recycler view but it doesn't work for some reason.
Although the data appears correctly in the logcat, it is sent as null to the Category adapter.
This is the Main Activity (where I'm trying to show the data):
`
#AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private val TAG = "MEALZ"
private lateinit var binding: ActivityMainBinding
private val viewModel:MealsViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val adapter = CategoryAdapter(this)
binding.categoriesRv.adapter = adapter
viewModel.getMeals()
lifecycleScope.launch {
viewModel.categories.collect {
adapter.setData(it?.categories as List<Category>)
Log.d(TAG, "onCreate: ${it?.categories}")
}
}
}
}
`
This is Recycler Category Adapter :
`
class CategoryAdapter(private val context: Context?) :
RecyclerView.Adapter<CategoryAdapter.CategoryViewHolder>() {
private var categoryList: MutableList<Category?> = mutableListOf<Category?>()
inner class CategoryViewHolder(itemView: CategoryLayoutBinding) :
RecyclerView.ViewHolder(itemView.root) {
val name = itemView.categoryNameTv
val img = itemView.categoryIv
val des = itemView.categoryDesTv
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CategoryViewHolder {
val binding = CategoryLayoutBinding.inflate(LayoutInflater.from(context), parent, false)
return CategoryViewHolder(binding)
}
override fun onBindViewHolder(holder: CategoryViewHolder, position: Int) {
var category = categoryList[position]
holder.name.text = category?.strCategory
holder.des.text = category?.strCategoryDescription
Glide.with(context as Context).load(category?.strCategoryThumb).into(holder.img)
}
override fun getItemCount(): Int {
return categoryList.size
}
fun setData(CategoryList: List<Category>) {
this.categoryList.addAll(CategoryList)
notifyDataSetChanged() //to notify adapter that new data change has been happened to adapt it
}
}
`
This is the View Model class:
#HiltViewModel
class MealsViewModel #Inject constructor(private val getMealsUseCase: GetMeals): ViewModel() {
private val TAG = "MealsViewModel"
private val _categories: MutableStateFlow<CategoryResponse?> = MutableStateFlow(null)
val categories: StateFlow<CategoryResponse?> = _categories
fun getMeals() = viewModelScope.launch {
try {
_categories.value = getMealsUseCase()
} catch (e: Exception) {
Log.d(TAG, "getMeals: ${e.message.toString()}")
}
}
}
you create your _categories with null as initial value, so first value of categories flow will be null and only second one will contain fetched data. As a workaround, you can check that data is not null:
viewModel.categories.collect {
if (it != null) {
adapter.setData(it?.categories as List<Category>)
Log.d(TAG, "onCreate: ${it?.categories}")
}
}
or introduce some kind of "loading" state

android - RecyclerView and Intent : No value passed for parameter 'ListUserAdapter'

hi im currently using kotlin for my android project,as per instruction,i was told to make an apps that has recycleview to show list item and intent when you click on one of the list shown.
but i have this error when i want to run the app,the error was "No value passed for parameter 'ListUserAdapter'"
here is my code
ListUserAdapter.kt
class ListUserAdapter(private val ListUserAdapter: ArrayList<User>) : RecyclerView.Adapter<ListUserAdapter.ListViewHolder>() {
private lateinit var onItemClickCallBack: OnItemClickCallBack
fun setOnItemClickCallback(onItemClickCallback: OnItemClickCallBack) {
this.onItemClickCallBack = onItemClickCallback
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListViewHolder {
val view: View = LayoutInflater.from(parent.context).inflate(R.layout.row_user, parent, false)
return ListViewHolder(view)
}
override fun onBindViewHolder(holder: ListViewHolder, position: Int) {
val (name, username) = ListUserAdapter[position]
holder.tvName.text = name
holder.tvUserName.text= username
holder.itemView.setOnClickListener {
onItemClickCallBack.onItemClicked(ListUserAdapter[holder.adapterPosition])
}
}
override fun getItemCount(): Int = ListUserAdapter.size
class ListViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var tvName: TextView = itemView.findViewById(R.id.tv_username)
var tvUserName: TextView = itemView.findViewById(R.id.tv_name)
}
interface OnItemClickCallBack {
fun onItemClicked(data : User)
}
}
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var adapter: ListUserAdapter
private lateinit var dataName: Array<String>
private lateinit var dataUsername: Array<String>
private lateinit var dataLocation: Array<String>
private lateinit var dataRepo: Array<String>
private lateinit var dataCompany: Array<String>
private lateinit var dataFollowers: Array<String>
private lateinit var dataFollowing: Array<String>
private lateinit var dataPhoto: TypedArray
private var users = arrayListOf<User>()
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setAdapter()
prepare()
addItem()
}
private fun setAdapter() {
adapter = ListUserAdapter() //error in here
with(binding) {
rvList.adapter = adapter
rvList.layoutManager =
GridLayoutManager(this#MainActivity, 2, GridLayoutManager.HORIZONTAL, false)
rvList.setHasFixedSize(true)
}
adapter.setOnItemClickCallback(object : ListUserAdapter.OnItemClickCallBack{
override fun onItemClicked(user: User) {
val intent = Intent(this#MainActivity, DetailActivity::class.java)
intent.putExtra(DetailActivity.KEY_USER, user)
startActivity(intent)
}
})
}
private fun prepare() {
dataName = resources.getStringArray(R.array.name)
dataUsername = resources.getStringArray(R.array.username)
dataPhoto = resources.obtainTypedArray(R.array.avatar)
dataLocation = resources.getStringArray(R.array.location)
dataRepo = resources.getStringArray(R.array.repository)
dataCompany = resources.getStringArray(R.array.company)
dataFollowers = resources.getStringArray(R.array.followers)
dataFollowing = resources.getStringArray(R.array.following)
}
private fun addItem() {
for (position in dataName.indices) {
val user = User(
dataUsername[position],
dataName[position],
dataLocation[position],
dataCompany[position],
dataRepo[position],
dataFollowers[position],
dataFollowing[position],
dataPhoto.getResourceId(position, -1)
)
users.add(user)
}
}
}
DetailActivity.kt
class DetailActivity : AppCompatActivity() {
private lateinit var binding: ActivityDetailBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDetailBinding.inflate(layoutInflater)
setContentView(binding.root)
setData()
}
private fun setData() {
val dataUser = intent.getParcelableExtra<User>(KEY_USER) as User
with(binding) {
Glide.with(root)
.load(dataUser.photo)
.circleCrop()
.into(ivDetailAvatar)
}
}
companion object {
const val KEY_USER = "key_user"
}
}
just you need to replace adapter = ListUserAdapter() //error in here with adapter = ListUserAdapter(users) then your problem solve
You're just forgetting the constructor parameter :)
Your adapter class needs to receive a ArrayList of User to be instantiated, you already have it in your Activity, you just need to pass it as the constructor parameter :)
I would also rename the parameter name to something like users or usersList instead of `ListUserAdapter but because currently it is misleading, since this parameter is not an adapter, it is a list of users.
Just change the line with error to
adapter = ListUserAdapter(users)
But I think it is best for you to first call prepare() and addItem() and then instantiate your adapter. Or you can instantiate your adapter, but also create a addItems function, since it is a best practice for adapters.
fun addItems(users: List<User>) {
this.ListUserAdapter.addAll(users)
notifyDataSetChanged()
}
and use it after setting everything up inside onCreate doing something like
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setAdapter()
prepare()
addItem()
adapter.addItems(users)
}
but you could probably reorganize these methods to improve readability as well, but it will work :)

Can I press a button in Activity A to filter a RecyclerView in Activity B?

What I want to reach is that the same RecyclerView shows different data depending on which button the App user pressed before in the MainActivity.kt.
In my MainActivity.kt I have two buttons, which both send the user to the same RecyclerView Activity (RecyclerViewLayout.kt) via Intent.
Example: The RecyclerView contains a picture of an apple and a banana. By pressing button A in MainActivity.kt, the RecyclerView in RecyclerViewLayout.kt should only show the apple. By pressing button B it should only show the banana. In my real app there are no fruits. but Tutorials, which should be filtered like described.
I gently ask for help here how to do that. Maybe there is also a better way to reach my target to filter the RecyclerView?
Thanks in Advance!
MainActivity.kt
class MainActivity : AppCompatActivity() {
private var binding:ActivityMainBinding? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding?.root)
val buttonRecyclerView = findViewById<Button>(R.id.btn_recyclerview)
buttonRecyclerView.setOnClickListener {
val intent = Intent(this, RecyclerViewLayout::class.java)
startActivity(intent)
}
}}
RecyclerViewLayout.kt
class RecyclerViewLayout : AppCompatActivity() {
private lateinit var newRecylerview : RecyclerView
private lateinit var newArrayList : ArrayList<RecyclerViewDataClass>
private lateinit var tempArrayList : ArrayList<RecyclerViewDataClass>
lateinit var imageId : Array<Int>
lateinit var tutorialHeading : Array<String>
lateinit var tutorialText : Array<String>
lateinit var url : Array<String>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_recycler_view_layout)
imageId = arrayOf(
R.drawable.brake,
R.drawable.brake,
)
tutorialHeading = arrayOf(
getString(R.string.scheibenbremse_lüften_heading),
getString(R.string.felgenbremse_richten_heading),
)
tutorialText = arrayOf(
getString(R.string.scheibenbremse_lüften_text),
getString(R.string.felgenbremse_richten_text),
)
url = arrayOf(
getString(R.string.url_a),
getString(R.string.url_b),
)
newRecylerview =findViewById(R.id.recyclerView)
newRecylerview.layoutManager = LinearLayoutManager(this)
newRecylerview.setHasFixedSize(true)
newArrayList = arrayListOf<RecyclerViewDataClass>()
tempArrayList = arrayListOf<RecyclerViewDataClass>()
getUserdata()
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.menu_item,menu)
val item = menu?.findItem(R.id.search_action)
val searchView = item?.actionView as SearchView
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener{
override fun onQueryTextSubmit(query: String?): Boolean {
TODO("Not yet implemented")
}
override fun onQueryTextChange(newText: String?): Boolean {
tempArrayList.clear()
val searchText = newText!!.toLowerCase(Locale.getDefault())
if (searchText.isNotEmpty()){
newArrayList.forEach {
if (it.heading.toLowerCase(Locale.getDefault()).contains(searchText)){
tempArrayList.add(it)
}
}
newRecylerview.adapter!!.notifyDataSetChanged()
}else{
tempArrayList.clear()
tempArrayList.addAll(newArrayList)
newRecylerview.adapter!!.notifyDataSetChanged()
}
return false
}
})
return super.onCreateOptionsMenu(menu)
}
private fun getUserdata() {
for(i in imageId.indices){
val news = RecyclerViewDataClass(imageId[i],tutorialHeading[i],url[i])
newArrayList.add(news)
}
tempArrayList.addAll(newArrayList)
val adapter = RecyclerViewAdapter(tempArrayList)
newRecylerview.adapter = adapter
adapter.setOnItemClickListener(object : RecyclerViewAdapter.onItemClickListener{
override fun onItemClick(position: Int) {
val intent = Intent(this#RecyclerViewLayout,TutorialsActivity::class.java)
intent.putExtra("tutorialHeading",newArrayList[position].heading)
intent.putExtra("imageId",newArrayList[position].titleImage)
intent.putExtra("url",newArrayList[position].url)
intent.putExtra("tutorialText",tutorialText[position])
startActivity(intent)
}
})
}}
RecyclerViewAdapter.kt
class RecyclerViewAdapter(private val newsList : ArrayList<RecyclerViewDataClass>) : RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder>(),
Filterable {
private lateinit var mListener : onItemClickListener
interface onItemClickListener{
fun onItemClick(position : Int)
}
fun setOnItemClickListener(listener: onItemClickListener){
mListener = listener
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.list_item,
parent,false)
return MyViewHolder(itemView,mListener)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = newsList[position]
holder.titleImage.setImageResource(currentItem.titleImage)
holder.tvHeading.text = currentItem.heading
}
override fun getItemCount(): Int {
return newsList.size
}
class MyViewHolder(itemView : View, listener: onItemClickListener) : RecyclerView.ViewHolder(itemView){
val titleImage : ShapeableImageView = itemView.findViewById(R.id.title_image)
val tvHeading : TextView = itemView.findViewById(R.id.tvHeading)
init {
itemView.setOnClickListener {
listener.onItemClick(adapterPosition)
}
}
}
override fun getFilter(): Filter {
TODO("Not yet implemented")
}}
RecyclerViewDataClass.kt
data class RecyclerViewDataClass(var titleImage: Int, var heading: String, val url: String)
**Tutorials Activity**
class TutorialsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_tutorials)
val headingNews : TextView = findViewById(R.id.heading)
val mainNews : TextView = findViewById(R.id.news)
val imageNews : ImageView = findViewById(R.id.image_heading)
val bundle : Bundle?= intent.extras
val tutorialHeading = bundle!!.getString("tutorialHeading")
val imageId = bundle.getInt("imageId")
val tutorialText = bundle.getString("tutorialText")
val url = bundle.getString("url")
headingNews.text = tutorialHeading
mainNews.text = tutorialText
imageNews.setImageResource(imageId)
imageNews.setOnClickListener {
val openURL = Intent(Intent.ACTION_VIEW)
openURL.data = Uri.parse(url.toString())
startActivity(openURL)
}
}}
I believe you can pass data about which button is clicked using intents. Here's a link about that:
How to Pass custom object via intent in kotlin
For example, you can pass "A" if button A is clicked and "B" if button B is clicked, and then get that string in RecyclerViewLayout.kt to determine which elements should be shown.
According to me the simplest solution for doing this is you should have a boolean in preferences you can set preferences according to the button clicked and set data in your adapter to by getting the preferences value.
If you want to set data according to the button clicked
Other way is to pass the action onClick while starting a new Activity and getAction() in your second Activity.
This way you can also set data of your recyclerView by passing different data

Kotlin] I want to send some data from One class to Other class by using Intent

I just want to say sorry to my English skill
I've studied the Android Studio and Kotlin these days.
but I'd got a problem on RecyclerViewer and Adapter, for Intent method
work flow chart
this image, this is what i want to do
so i coded the three classes
ShoppingAppActivity.kt, MyAdapter.kt, CartActivity.kt
At ShoppingAppActivity, If I click the itemId ( in the Red box texts)
I make it move to other context(CartActivity)
ShoppingAppActivity working
if i clicked the red box then
cartStatus
go to cart Activity
it worked but already I said, I just want to send only send itemID
covert to String (i will use toString())
SO i tried to use Intent method in ShoppingAppActivity.kt
///PROBLEM PART
adapter?.setOnItemClickListener{
val nextIntent = Intent(this, CartActivity::class.java)
//nextIntent.putExtra("itemID", )
startActivity(nextIntent)
}
///PROBLEM PART
like this but the problem is I don't know what am i have to put the parameter in
nextIntent.putExtra("itemID", )
what should i do?
I think, I should fix MyAdaptor.kt or ShopingAppActivity.kt for this problem.
But in my knowledge, this is my limit. :-(
below
Full Codes of ShoppingAppActivity.kt, MyAdapter.kt, CartActivity.kt
ShoppingAppActivity.kt
class ShoppingAppActivity : AppCompatActivity() {
lateinit var binding: ActivityShoppingAppBinding
private var adapter: MyAdapter? = null
private val db : FirebaseFirestore = Firebase.firestore
private val itemsCollectionRef = db.collection("items")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityShoppingAppBinding.inflate(layoutInflater)
setContentView(binding.root)
updateList()
binding.recyclerViewItems.layoutManager = LinearLayoutManager(this)
adapter = MyAdapter(this, emptyList())
binding.recyclerViewItems.adapter = adapter
///PROBLEM PART
adapter?.setOnItemClickListener{
val nextIntent = Intent(this, CartActivity::class.java)
//nextIntent.putExtra("itemID", )
startActivity(nextIntent)
}
///PROBLEM PART
}
private fun updateList() {
itemsCollectionRef.get().addOnSuccessListener {
val items = mutableListOf<Item>()
for (doc in it) {
items.add(Item(doc))
}
adapter?.updateList(items)
}
}
}
MyAdapter.kt
data class Item(val id: String, val name: String, val price: Int, val cart: Boolean) {
constructor(doc: QueryDocumentSnapshot) :
this(doc.id, doc["name"].toString(), doc["price"].toString().toIntOrNull() ?: 0, doc["cart"].toString().toBoolean() ?: false)
constructor(key: String, map: Map<*, *>) :
this(key, map["name"].toString(), map["price"].toString().toIntOrNull() ?: 0, map["cart"].toString().toBoolean() ?: false)
}
class MyViewHolder(val binding: ItemBinding) : RecyclerView.ViewHolder(binding.root)
class MyAdapter(private val context: Context, private var items: List<Item>)
: RecyclerView.Adapter<MyViewHolder>() {
fun interface OnItemClickListener {
fun onItemClick(student_id: String)
}
private var itemClickListener: OnItemClickListener? = null
fun setOnItemClickListener(listener: OnItemClickListener) {
itemClickListener = listener
}
fun updateList(newList: List<Item>) {
items = newList
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding: ItemBinding = ItemBinding.inflate(inflater, parent, false)
return MyViewHolder(binding)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val item = items[position]
val itemID : String
holder.binding.textID.text = item.id
holder.binding.textName.text = item.name
if(item.cart)
{
holder.binding.textCart.text = "in Cart"
}
else
{
holder.binding.textCart.text = ""
}
holder.binding.textID.setOnClickListener {
AlertDialog.Builder(context).setMessage("You clicked ${item.id}.").show()
itemClickListener?.onItemClick(item.id)
}
holder.binding.textName.setOnClickListener {
//AlertDialog.Builder(context).setMessage("You clicked ${student.name}.").show()
itemClickListener?.onItemClick(item.id)
}
//return item.id.toString()
}
override fun getItemCount() = items.size
}
CartActivity.kt
class CartActivity : AppCompatActivity() {
lateinit var binding: ActivityCartBinding
private val db: FirebaseFirestore = Firebase.firestore
private val itemsCollectionRef = db.collection("items")
private var adapter: MyAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityCartBinding.inflate(layoutInflater)
setContentView(binding.root)
updateList()
//binding.recyclerViewItems.layoutManager = LinearLayoutManager(this)
//adapter = MyAdapter(this, emptyList())
//binding.recyclerViewItems.adapter = adapter
binding.changeCartStatus.setOnClickListener{
//change the button's text if the itemID is corrected
//if(){
// binding.changeCartStatus.text = ""
//}
}
}
private fun updateList() {
itemsCollectionRef.get().addOnSuccessListener {
val items = mutableListOf<Item>()
for (doc in it) {
items.add(Item(doc))
}
adapter?.updateList(items)
}
}
}
You just need to implement listener to your activity
class ShoppingAppActivity : AppCompatActivity() ,MyAdapter.OnItemClickListener {
In oncreate add below line after adapter
adapter?.setOnItemClickListener(this)
Then override its method
override fun onItemClick(id: String){
val nextIntent = Intent(this, CartActivity::class.java)
nextIntent.putExtra("itemID",id )
startActivity(nextIntent)
}

Get clicked item in recyclerview adapter

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])

Categories

Resources