Display onBindViewHolder value in Kotlin Main Class - android

I am trying to get onBindViewHolder variable value in the main class but I am not sure how to call this variable. Any help is appreciated.
override fun onBindViewHolder(p0: TestDetailMenuViewHolder, p1: Int) {
val Testmenudetail = TestMenudetails.get(p1)
p0?.customView?.itemname.text = Testmenudetail.price.toString()
var menuname: String = Testmenudetail.menu
var itemprice: String = Testmenudetail.price.toString()
//Let's say itemprice=50
}
class TestMenuDetail() : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
var Test1 = itemprice //???
}
}

Try to do so:
class Adapter : RecyclerView.Adapter<Holder> {
var itemprice = 0
override fun onBindViewHolder(p0: TestDetailMenuViewHolder, p1: Int) {
val Testmenudetail = TestMenudetails.get(p1)
p0?.customView?.itemname.text = Testmenudetail.price.toString()
var menuname: String = Testmenudetail.menu
var itemprice: String = Testmenudetail.price.toString()
itemprice=50
}
}
And then:
class TestMenuDetail() : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
var itemprice = Adapter().itemprice
}
}
But I don't understand why you need to get variable from you adapter. You need to know that the method onBindViewHolder is called frequently and the value itemprice will change.

Related

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

Not sure where to implements parcelable ArrayList after click item in RecyclerView

I wanna pass some of informations of the selected item to be viewed in new activity AboutApp.kt, but here I test by one info only (name). I do not have any trouble with RecyclerView, it works. I've seen many ways to do parcelable ArrayList object but feeling confuse where activity to be implemented, so it's getting error in MainActivity and AboutApp (destination intent).
A piece code MainActivity.kt getting error in showSelectedHerbal, when I use position to putExtra
class MainActivity : AppCompatActivity() {
private lateinit var rvHerbal: RecyclerView
private var list: ArrayList<Herbal> = arrayListOf()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
rvHerbal = findViewById(R.id.rv_herbal)
rvHerbal.setHasFixedSize(true)
list.addAll(HerbalData.listData)
showRecyclerList()
}
private fun showRecyclerList() {
rvHerbal.layoutManager = LinearLayoutManager(this)
val listHerbalAdapter = ListHerbalAdapter(list)
rvHerbal.adapter = listHerbalAdapter
listHerbalAdapter.setOnItemClickCallback(object : ListHerbalAdapter.OnItemClickCallback {
override fun onItemClicked(data: Herbal) {
showSelectedHerbal(data)
}
})
}
........
private fun showSelectedHerbal(data: Herbal) {
val moveIntent = Intent(this, AboutApp::class.java)
moveIntent.putExtra("Example_Item", list!![position])
this.startActivity(moveIntent)
}
.......
}
A piece code from AboutApp.kt that getting error in herbalName(). I know that I haven't implemented the parcelable so it's wrong
val intent = intent
val herbalData: HerbalData = intent.getParcelableExtra("Example_Item")
val title: String = herbalData.herbalName()
val itemName = findViewById<TextView>(R.id.item_name)
itemName.text = title
I'm so sorry, I attach you some of activities that I confuse may be one of them is the right place to be implement parcelable. Here is my data class Herbal.kt
data class Herbal(
var name: String = "",
var detail: String = "",
var photo: Int = 0
)
A piece code of the object HerbalData.kt
object HerbalData {
private val herbalName = arrayOf("Cengkeh",
"Ginseng",
"Jahe")
..........
val listData: ArrayList<Herbal>
get() {
val list = arrayListOf<Herbal>()
for (position in herbalName.indices) {
val herbal = Herbal()
herbal.name = herbalName[position]
herbal.detail = herbalDetail[position]
herbal.photo = herbalImage[position]
list.add(herbal)
}
return list
}
}
Help me please where activity to be write the parcelable ArrayList and how to fix it. Thanks in advance for any help.
First of all the error in your AboutApp.kt is because you have herbalName private in your HerbalData object. Remove the private modifier to access it there.
Just add #Parcelize annotation over your data class to automatically generate writeToParcel and createFromParcel methods for you!
#Parcelize
data class Herbal(...) : Parcelable
Add this in your build.gradle file:
androidExtensions {
features = ["parcelize"]
}
PS: Reference: https://medium.com/#BladeCoder/a-study-of-the-parcelize-feature-from-kotlin-android-extensions-59a5adcd5909
I recommend you read this.
You just have to make the Herbal class Parcelable.
data class Herbal(
var name: String = "",
var detail: String = "",
var photo: Int = 0
) : Parcelable {
companion object {
#JvmField
val CREATOR = object : Parcelable.Creator<Herbal> {
override fun createFromParcel(parcel: Parcel) = Herbal(parcel)
override fun newArray(size: Int) = arrayOfNulls<Herbal>(size)
}
}
private constructor(parcel: Parcel) : this(
name = parcel.readString(),
detail = parcel.readString(),
photo = parcel.readInt(),
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(name)
parcel.writeString(detail)
parcel.writeInt(photo)
}
override fun describeContents() = 0
}

Spinner onItemSelected() not being called

I've implemented an ArrayAdapter to populate my Spinner view. The Spinner is working fine, however android is not detecting when I click an item in the spinner.
I've abided by all the requirements in the spinner example in the Android docs
including implementing AdapterView.OnItemSelectedListener to my Activity and overriding it's two methods OnItemSelectedListener and onNothingSelected, however, none of my Log statements in those methods print so they are not being called.
I've also set the listener to my spinner via choose_user.onItemSelectedListener = this#PlayerDetails.
Here's my activity:
class PlayerDetails : AppCompatActivity(), View.OnClickListener, TextWatcher, AdapterView.OnItemSelectedListener {
val TAG: String = "PlayerDetails"
val FirebaseTAG: String = "FirebaseDebug"
var numOfPlayers: Int = 1
var currentPlayer: Int = 1
var name: String = ""
var age: Int = 0
var genderId: Int = 0
var genderResult: String = ""
val db = FirebaseFirestore.getInstance()
var users: MutableList<String> = mutableListOf()
private lateinit var binding: ActivityPlayerDetailsBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val sharedPref = this#PlayerDetails.getPreferences(Context.MODE_PRIVATE)
val applicationID: String? = sharedPref.getString("applicationID", null)
binding = DataBindingUtil.setContentView(this, R.layout.activity_player_details)
if (applicationID != null) {
db.collection("phones").document(applicationID)
.collection("users")
.get()
.addOnSuccessListener { result ->
for (document in result){
val name = document.get("name").toString()
users.add(name)
}
}
Log.d(FirebaseTAG, users.toString())
val spinnerAdaptor = ArrayAdapter<String>(this#PlayerDetails, android.R.layout.simple_spinner_item, users)
spinnerAdaptor.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
choose_user?.adapter = spinnerAdaptor
choose_user.onItemSelectedListener = this#PlayerDetails
}
val intent = getIntent()
numOfPlayers = intent.getIntExtra("number_of_players", 1)
next_details.setOnClickListener(this)
player_name.addTextChangedListener(this)
player_age.addTextChangedListener(this)
gender.setOnCheckedChangeListener(object: RadioGroup.OnCheckedChangeListener {
override fun onCheckedChanged(radiogroup: RadioGroup, checked: Int) {
if (fieldsArePopulated()) next_details.visibility = View.VISIBLE
}
})
}
override fun onItemSelected(parent: AdapterView<*>?, name: View?, position: Int, rowId: Long) {
val chosenName: String = parent?.getItemAtPosition(position).toString()
Log.d("ChosenName", chosenName)
Log.d("adapterclicked", "adapterclicked")
}
override fun onNothingSelected(parent: AdapterView<*>?) {
Log.d("Nothing", "NOTHINGCALLED")
}
...
Any idea what the problem is?
Also, when I select an item in the Spinner the view next to my spinner moves, so it's obviously being detected but onItemSelected() is still not being called.
I set an initial value to the users MutableList:
var users: MutableList<String> = mutableListOf("Choose User")
and now onItemSelected() is successfully being called.
I'm pretty sure onItemSelected returns an int of the item's position in array. So you have to save that as an int instead of string, and then add another variable that us a string and array[intSaved]
Edit
var chosenName = choose_user.onItemSelected("name")
try this
before :
override fun onItemSelected(parent: AdapterView<*>?, name: View?, position: Int, rowId: Long) {
val chosenName: String = parent?.getItemAtPosition(position).toString()
Log.d("ChosenName", chosenName)
Log.d("adapterclicked", "adapterclicked")
}
after :
override fun onItemSelected(parent: AdapterView<*>?, name: View?, position: Int, rowId: Long) {
val chosenNameTextView = parent!!.getChildAt(0) as TextView
Log.e("MainActivity","choose Spin : ${chosenNameTextView.text.toString()}")
}

java.lang.ClassCastException: CustomAdapter cannot be cast to android.widget.ArrayAdapter In Kotlin

I got the above-mentioned error when I try to create a custom adapter class in Kotlin
Source code
MainActivity.kt
var adapterC:CustomAdapter = CustomAdapter(this,Statearray)
spinnerState.adapter=adapterC
CustomAdapter.kt
class CustomAdapter(val activity: Activity,val array:JSONArray) : BaseAdapter(), ListAdapter
{
lateinit var ItemName: TextView
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? {
var view=convertView
if (view == null)
view = activity.layoutInflater.inflate(R.layout.spinnerlayout, null)
try {
ItemName = view?.findViewById(R.id.ItemName) as TextView
val obj = array.getJSONObject(position)
ItemName.setText(obj.getString("Name"))
view.setTag(obj.getString("Id"))
} catch ( e:JSONException) {
Log.e("At Custom Class",e.toString())
}
return view
}
override fun getItem(position: Int): JSONObject {
return array.optJSONObject(position)
}
override fun getItemId(position: Int): Long {
var jsonObject=getItem(position)
return jsonObject.optLong("id")
}
override fun getCount(): Int {
return array.length()
}
}
Need Help I don't know what I did wrong.
I finally figure it out.. the problem was, iwas using a spinner library which only support ArrayAdapter
the library that i used was
com.toptoche.searchablespinner:searchablespinnerlibrary:1.3.1
it only support arrayadapter
ClassCastException
Thrown to indicate that the code has attempted to cast an object to a
subclass of which it is not an instance.
FYI
You added Multiple Adapter. Remove 2nd One.
Don't
class CustomAdapter(val activity: Activity,val array:JSONArray) : BaseAdapter(), ListAdapter
Do
class CustomAdapter(context: Context,var arrayLIST: ArrayList<Response>) : BaseAdapter() {
DEMO
var arrayLIST: ArrayList<Response>? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
arrayLIST=ArrayList()
val jsonObj = ("[{\"Id\":\"35\",\"Name\":\"Kerala\"},{\"Id\":\"36\",\"Name\":\"Tamilnadu\"}]")
val jo = JSONArray(jsonObj)
val num = 0 until jo.length()
for (i in num) {
val loanObj = jo.getJSONObject(i)
val Id = loanObj.getString("Id")
val Name = loanObj.getString("Name")
arrayLIST!!.add(Response(Id,Name))
}
var adapterC:CustomAdapter = CustomAdapter(this#MainActivity,arrayLIST)
Response.kt
data class Response
(
#SerializedName("id") val id : String,
#SerializedName("name") val name : String
)
NOTE
Make sure add,
implementation "com.google.code.gson:gson:2.3.0"
implementation "com.squareup.retrofit2:converter-gson:2.3.0"

Categories

Resources