How can pass data from recyclerview to New Activity - android

hi i want parse my data in to new activity .
I did this but it doesn't work properly and it doesn't transfer data
You can see my code below
my adapter
ItemViewAdapter.kt
package com.example.app.adapter
import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.app.R
import com.example.app.models.products.Results
import com.example.app.ui.home.DescriptionActivity
import java.security.AccessController.getContext
class ItemViewAdapter(private val context: Context) :
RecyclerView.Adapter<ItemViewAdapter.MyViewHolder>() {
private var itemList: MutableList<Results> = mutableListOf()
private var page: Int = 0
fun setListItem(item: List<Results>) {
itemList.addAll(item)
notifyItemRangeInserted(page * 10, (page.plus(1) * 10) - 1)
}
class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
private val title = view.findViewById<TextView>(R.id.tvTitle)
private val code = view.findViewById<TextView>(R.id.tvNumber)
private val quantity = view.findViewById<TextView>(R.id.tvQuantity)
private val price = view.findViewById<TextView>(R.id.tvPrice)
private val available = view.findViewById<TextView>(R.id.tvAvailable)
private val category = view.findViewById<TextView>(R.id.tvCategory)
fun bind(item: Results) {
title.text = item.name
code.text = item.code.toString()
quantity.text = item.quantities[0].quantity.toString()
price.text = item.prices[0].price.toString()
available.text = item.active.toString()
category.text = item.category?.name
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false)
return MyViewHolder(v)
}
override fun getItemCount(): Int {
return itemList.size
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val data = itemList[position]
holder.bind(data)
holder.itemView.setOnClickListener {
val intent = Intent(context, DescriptionActivity::class.java)
intent.putExtra("title", getItemId(position))
intent.putExtra("code", getItemId(position))
intent.putExtra("quantity", getItemId(position))
intent.putExtra("price", getItemId(position))
intent.putExtra("category", getItemId(position))
intent.putExtra("info", getItemId(position))
context.startActivity(intent)
}
}
}
and my description activity
Description.kt
package com.example.app.ui.home
import android.graphics.Color
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.view.WindowInsetsController
import android.view.WindowManager
import com.example.app.R
import com.example.app.databinding.ActivityDescriptionBinding
#Suppress("DEPRECATION")
class DescriptionActivity : AppCompatActivity() {
private lateinit var binding: ActivityDescriptionBinding
override fun onCreate(savedInstanceState: Bundle?) {
window.apply {
clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
statusBarColor = Color.TRANSPARENT
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
this#DescriptionActivity.window.decorView.windowInsetsController
?.setSystemBarsAppearance(
0,
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
)
}
}
}
super.onCreate(savedInstanceState)
binding = ActivityDescriptionBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
getItemIntent()
}
private fun getItemIntent(){
val title = intent.getStringExtra("title")
val code = intent.getStringExtra("code")
val category = intent.getStringExtra("category")
val info = intent.getStringExtra("info")
val price = intent.getStringExtra("price")
val quantity = intent.getStringExtra("quantity")
setData(title,code,category,info,price,quantity)
}
private fun setData(title: String?, code: String?, category: String?, info: String?, price: String?, quantity: String?) {
binding.tvTitle.setText(title)
binding.tvCode.setText(code)
binding.tvCategory.setText(category)
binding.tvDescription.setText(info)
binding.tvPrice.setText(price)
binding.tvQuantity.setText(quantity)
}
}
But the data is not transferred.
If anyone can help me improve the code or offer me a sample code done with api so I can see.

When you set the data, you call getItemId(position) for every single line. This returns a long, not a string (and you put the same long for each attribute, which makes no sense)
intent.putExtra("title", getItemId(position))
intent.putExtra("code", getItemId(position))
but when you retrieve it, you look for a string
val title = intent.getStringExtra("title")
val code = intent.getStringExtra("code")
If you want to get a string, you need to put a string, probably like this (get the item for that row, then put its string attributes):
val data = itemList[position]
//...
intent.putExtra("title", data.name)
intent.putExtra("code", data.code.toString())
or if you want to get the text off the displayed views (have to make them non-private in the binding class):
intent.putExtra("title", binding.title.text.toString())
intent.putExtra("code", binding.code.text.toString())

If you need to pass the entire object or most of its properties, you can add the library
implementation 'com.google.code.gson:gson:2.8.5' //Maybe the version is not the most recent, I just copied and pasted the implementation from the internet
And convert your object to a Json and pass it as a string
intent.putExtra("data", Gson().toJson(data))
and to receive it
val data = intent.getStringExtra("data", null)?.let {
Gson().fromJson(it, Results::Java.class)
}

Related

RecyclerView only showing last item in JSON array

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.

Recycler View with duplicate rows after refreshing activity

After doing some research i found out that i need to clear the list that i am using each time i refresh the activity, after trying it to refresh the list at different places, the result remains the same and i have decided to give my brain a break and ask for help. The refreshing takes place on the PostDialogFragment class
i have circled the recycler view causing the issue
PostAdapter
package com.example.osrscritic.view
import android.text.method.ScrollingMovementMethod
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.osrscritic.databinding.PostRowItemBinding
import com.example.osrscritic.model.Skillvalue
import com.google.firebase.firestore.CollectionReference
import com.google.firebase.firestore.DocumentSnapshot
import com.google.firebase.firestore.QueryDocumentSnapshot
import com.google.firebase.firestore.QuerySnapshot
class PostsAdapter: RecyclerView.Adapter<PostsViewHolder>() {
val postsMutableList : MutableList<DocumentSnapshot> = mutableListOf()
fun setPostsList(statsList: List<DocumentSnapshot>) {
postsMutableList.addAll(statsList)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PostsViewHolder {
val binding = PostRowItemBinding.inflate(LayoutInflater.from(parent.context)
,parent,false)
return PostsViewHolder(binding)
}
override fun onBindViewHolder(holder: PostsViewHolder, position: Int) {
val post = postsMutableList[position]
holder.binding.tvCritic.text = post["critic"].toString()
val posts = post["posts"] as List<String>
var count = 0;
holder.binding.tvActualPost.movementMethod = ScrollingMovementMethod()
for(p in posts) {
holder.binding.tvActualPost.append("${count}: " + p + "\n")
count++
}
}
override fun getItemCount() = postsMutableList.size
}
class PostsViewHolder(val binding: PostRowItemBinding) : RecyclerView.ViewHolder(binding.root)
DisplayUserActivty
package com.example.osrscritic
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.osrscritic.databinding.ActivityDisplayUserBinding
import com.example.osrscritic.view.PostDialogFragment
import com.example.osrscritic.view.PostsAdapter
import com.example.osrscritic.view.StatsAdapter
import com.example.osrscritic.viewmodel.DisplayUserViewModel
import com.google.android.gms.tasks.OnCompleteListener
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.firestore.DocumentSnapshot
import org.koin.androidx.viewmodel.ext.android.viewModel
class DisplayUserActivity : AppCompatActivity() {
private val displayUserViewModel : DisplayUserViewModel by viewModel()
lateinit var binding: ActivityDisplayUserBinding
val statsAdapter = StatsAdapter()
val postsAdapter = PostsAdapter()
lateinit var critiquing: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val extras = intent.extras
critiquing = extras?.getString("c")!!
binding = ActivityDisplayUserBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.rsStatsRv.adapter = statsAdapter
binding.rsStatsRv.layoutManager = LinearLayoutManager(this,
LinearLayoutManager.VERTICAL, false)
binding.rvPosts.adapter = postsAdapter
binding.rvPosts.layoutManager = LinearLayoutManager(this,
LinearLayoutManager.VERTICAL, false)
configureObservers()
displayUserViewModel.getFirebaseRef()
displayUserViewModel.getOSRSPlayer()
binding.ivWritePost.setOnClickListener {
PostDialogFragment.newInstance(critiquing).show(supportFragmentManager
, PostDialogFragment.KEY)
}
}
private fun configureObservers() {
displayUserViewModel.displayUserLiveData.observe(this, {
statsAdapter.setStatsList(it.skillvalues)
binding.tvRunescapeName.text = String.format("Account Name: %s", it.name)
binding.tvCombat.text = String.format("Combat Level: %s", it.combatlevel.toString())
})
displayUserViewModel.loadingState.observe(this, {
when(it){
true -> binding.pgBar.visibility = View.VISIBLE
false -> binding.pgBar.visibility = View.GONE
}
})
displayUserViewModel.errorData.observe(this, {
Toast.makeText(this, it, Toast.LENGTH_LONG).show()
})
displayUserViewModel.displayUserPostsLiveData.observe(this, {
postsAdapter.postsMutableList.clear()
it.document(critiquing).collection("posts").get()
.addOnSuccessListener {
postsAdapter.setPostsList(it.documents)
}
})
}
}
PostDialogFragment
package com.example.osrscritic.view
import android.app.AlertDialog
import android.app.Dialog
import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import androidx.fragment.app.DialogFragment
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.EditText
import android.view.Gravity
import androidx.core.app.ActivityCompat.recreate
import com.example.osrscritic.DisplayUserActivity
import com.example.osrscritic.viewmodel.DisplayUserViewModel
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.firestore.FieldPath
import com.google.firebase.firestore.FieldValue
import com.google.firebase.firestore.SetOptions
import org.koin.androidx.viewmodel.ext.android.viewModel
class PostDialogFragment: DialogFragment() {
private val displayUserViewModel : DisplayUserViewModel by viewModel()
val currentUser = FirebaseAuth.getInstance().currentUser
lateinit var critiquing: String
val postsAdapter = PostsAdapter()
companion object {
const val KEY: String = "KEY2"
//lateinit var param: String
fun newInstance(text: String): PostDialogFragment {
val args = Bundle()
val postDialogFragment = PostDialogFragment()
args.putString(KEY, text)
postDialogFragment.arguments = args
return postDialogFragment
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
critiquing = arguments?.getString(KEY)!!
Log.d("*******8", critiquing)
val builder = AlertDialog.Builder(activity)
val layout = LinearLayout(activity)
val parms = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
layout.orientation = LinearLayout.VERTICAL
layout.layoutParams = parms
layout.gravity = Gravity.CLIP_VERTICAL
layout.setPadding(2, 2, 2, 2)
val tv = TextView(activity)
tv.text = "Text View title"
tv.setPadding(40, 40, 40, 40)
tv.gravity = Gravity.CENTER
tv.textSize = 20f
val et = EditText(activity)
var etString = ""
et.addTextChangedListener(object: TextWatcher{
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
override fun afterTextChanged(p0: Editable?) {
Log.d("etText", et.text.toString())
etString = et.text.toString()
}
})
val tv1 = TextView(activity)
tv1.text = "Input Student ID"
val tv1Params = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
tv1Params.bottomMargin = 5
//layout.addView(tv1, tv1Params)
layout.addView(
et,
LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
)
//param = arguments?.getString(KEY)!!
builder.setTitle("New Post")
builder.setView(layout).setPositiveButton("Done", object: DialogInterface.OnClickListener{
override fun onClick(p0: DialogInterface?, p1: Int) {
activity?.let {
displayUserViewModel.displayUserPostsLiveData.observe(it, {
val post : MutableMap<String, Any> = mutableMapOf()
val posts : MutableList<String> = mutableListOf()
posts.add(etString)
post["critic"] = currentUser?.email!!
post["posts"] = posts
if(it.document(critiquing).collection("posts").document().equals(null)) {
it.document(critiquing).collection("posts")
.document(currentUser?.email!!).set(post)
}
it.document(critiquing).collection("posts")
.document(currentUser?.email!!).update("posts", FieldValue.arrayUnion(etString))
})
}
activity!!.finish()
activity!!.overridePendingTransition( 0, 0);
startActivity(activity!!.intent)
//trying to clear the list here once being refreshed
postsAdapter.postsMutableList.clear()
activity!!.overridePendingTransition( 0, 0);
}
})
builder.setNegativeButton("Cancel", object:DialogInterface.OnClickListener{
override fun onClick(p0: DialogInterface?, p1: Int) {
dismiss()
}
})
return builder.create()
}
}
Overriding those usually solves this kind of issues:
getItemId: return long that uniquely identifies every item. For example, you could use an autoincrementing variable id for each new item object, or some hashcode. This should be paired with setHasStableIds(true). (By default it returns RecyclerView.NO_ID which value is -1).
This helps to make sure RecyclerView e.g. identifies items properly, knows when OnBindViewHolder must be called or to return precise values on getAdapterPosition().
getItemCount: return an int with current number of items. Usually the Array.size() where the data is. (By default it returns 0).
getItemType: If there's multiple view types, return a unique number for each type of ViewHolder (usually starting with 0). (By default it returns 0).

intent.putExtra: None of the following functions can be called with the arguments supplied

I'm trying to pass data from one activity to another through an intent with putExtra. The thing is, I get the error that says: None of the following functions can be called with the arguments supplied.
I'm not sure why it's not working, since the variable that I'm referencing is in the viewholder. Any clue as to what's going on and how to fix it would help a lot.
This is my recycler adapter:
package com.example.newsapp
import android.content.Intent
import android.icu.text.CaseMap
import android.net.Uri
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat.startActivity
import androidx.recyclerview.widget.RecyclerView
import com.example.newsapp.databinding.NewsItemBinding
import com.squareup.picasso.Picasso
class RecyclerAdapter (
private var Titles: List<String>,
private var Images: List<String>,
private var Authors: List<String>,
private var Descriptions: List<String>
) : RecyclerView.Adapter<RecyclerAdapter.ViewHolder>(){
inner class ViewHolder(
view: View
): RecyclerView.ViewHolder(view){
private val binding = NewsItemBinding.bind(view)
val itemTitle: TextView = binding.tvTitle
val itemImage: ImageView = binding.ivNewsImage
fun bind(urlToImage:String){
Picasso.get().load(urlToImage).into(binding.ivNewsImage)
}
init {
itemImage.setOnClickListener{
val intent = Intent(view.context, PostActivity::class.java)
intent.putExtra("title",itemTitle)
view.context.startActivity(intent)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.news_item, parent, false)
return ViewHolder(v)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.itemTitle.text = Titles[position]
val itemImage = Images[position]
holder.bind(itemImage)
}
override fun getItemCount(): Int {
return Titles.size
}
}
The part with the issue is this one:
init {
itemImage.setOnClickListener{
val intent = Intent(view.context, PostActivity::class.java)
intent.putExtra("title",itemTitle) view.context.startActivity(intent)
}
}
This is my main activity:
package com.example.newsapp
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.newsapp.databinding.ActivityMainBinding
import kotlinx.coroutines.*
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.lang.Exception
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var adapter: RecyclerAdapter
private val newsTitles = mutableListOf<String>()
private val newsImages = mutableListOf<String>()
private val newsAuthors = mutableListOf<String>()
private val newsDescriptions = mutableListOf<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
makeAPIRequest()
}
private fun initRecyclerView() {
adapter = RecyclerAdapter( newsTitles, newsImages)
binding.rvNews.layoutManager = LinearLayoutManager(this)
binding.rvNews.adapter = adapter
}
private fun addToList(title:String, image:String, author:String, description:String){
newsTitles.add(title)
newsImages.add(image)
newsAuthors.add(author)
newsDescriptions.add(description)
}
private fun makeAPIRequest() {
val api = Retrofit.Builder()
.baseUrl("https://newsapi.org/")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(APIService::class.java)
GlobalScope.launch(Dispatchers.IO){
val response = api.getNews()
val posts = response.body()
try{
if (posts != null) {
for(art in posts.Articles){
Log.i("Main Activity", "Result = $art")
addToList(art.Title,art.urlToImage, art.Author, art.Description)
}
}
withContext(Dispatchers.Main){
initRecyclerView()
}
} catch (e:Exception){
Log.e("Main Activity", e.toString())
}
}
}
}
intent.putExtra("title",itemTitle)
Here, itemTitle is a TextView. You cannot pass a TextView between activities. You could switch to:
intent.putExtra("title",itemTitle.text)
...to put the text from the TextView into the extra.
Also, you might want to consider whether these should be separate activities or just two fragments (or composables) in a single activity.

how to add multiple values in shared preferences and load them in recyclerview?

I am trying to make a todo list app and want to save all todo title in the shared preference (I know it's a bad idea) but only one value is stored in the shared preference and only that loads on app restart. How to add and load multiple items from shared preference in recyclerView ?
MainActivity.kt
import android.content.Context
import android.content.SharedPreferences
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
private lateinit var todoAdapter: TodoAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
todoAdapter = TodoAdapter(mutableListOf())
rvTodoItems.adapter = todoAdapter
rvTodoItems.layoutManager = LinearLayoutManager(this)
val sharedPreferences = getSharedPreferences("myPref", Context.MODE_APPEND)
val editor = sharedPreferences.edit()
fun getData():List<String>{
val name = sharedPreferences.getString("todoName",null)
val list = mutableListOf<String>()
list.add(name.toString())
return list
}
fun loadData(list:List<String>){
for(item in list){
val td = Todo(item)
todoAdapter.addTodo(td)
}
}
val data:List<String> = getData()
loadData(data)
btnAddTodo.setOnClickListener {
val todoTitle = addTodo.text.toString()
if(todoTitle.isNotEmpty()){
val todo = Todo(todoTitle)
todoAdapter.addTodo(todo)
editor.apply {
putString("todoName",todoTitle)
apply()
}
}
}
btnRemoveTodo.setOnClickListener {
todoAdapter.deleteDoneTodos()
}
}
}
Todo data class file (Todo.kt)
data class Todo(
val title:String,
var isChecked: Boolean = false
)
TodoAdapter.kt
import android.graphics.Paint.STRIKE_THRU_TEXT_FLAG
import android.text.style.StrikethroughSpan
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.item_todo.view.*
class TodoAdapter(
private val todos: MutableList<Todo>
) : RecyclerView.Adapter<TodoAdapter.TodoViewHolder>() {
class TodoViewHolder(itemView:View): RecyclerView.ViewHolder(itemView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder {
return TodoViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.item_todo,
parent,
false
)
)
}
fun addTodo(todo: Todo){
todos.add(todo)
notifyItemInserted(todos.size-1)
}
fun deleteDoneTodos(){
todos.removeAll { todo ->
todo.isChecked
}
notifyDataSetChanged()
}
private fun toggleStrikeThrough(tvTodoTitle:TextView, isChecked: Boolean){
if(isChecked){
tvTodoTitle.paintFlags = tvTodoTitle.paintFlags or STRIKE_THRU_TEXT_FLAG
}else{
tvTodoTitle.paintFlags = tvTodoTitle.paintFlags and STRIKE_THRU_TEXT_FLAG.inv()
}
}
override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
val currentTodo = todos[position]
holder.itemView.apply {
tvTodoTitle.text = currentTodo.title
cbDone.isChecked = currentTodo.isChecked
toggleStrikeThrough(tvTodoTitle,currentTodo.isChecked)
cbDone.setOnCheckedChangeListener{_, isChecked ->
toggleStrikeThrough(tvTodoTitle,isChecked)
currentTodo.isChecked = !currentTodo.isChecked
}
}
}
override fun getItemCount(): Int {
return todos.size
}
}
Please take a look at code and help me out. Thanks :)
If you specifically want to save in shared preferences you can convert your list to json and save then read as json and convert to list. You can use Google's Gson library for that.
//Save
editor.putString("todoName", Gson().toJson(list))
//Read
val list = Gson().fromJson(sharedPreferences.getString("todoName"), object: TypeToken<List<String>>(){}.javaClass)
But I kindly suggest you to use Room library for this kind of stuff.
official doc: https://developer.android.com/training/data-storage/room
You can use work like with Parcelable classes.
#Parcelize
data class ToDoKit {
var todos: ArrayList<Todo>
}: Parcelable
and use SharedPreferences.Editor.putParcelable and SharedPreferences.Editor.getParcelable to operate with data.

how to add filter to RecyclerViewAdapter using kotlin?

I want to add a filter to this RecyclerViewAdapter please help in this code
NOTE : I USE A CLASS To fill the LIST ,this Class TAkes four
parameters as INPUTS (three Strings and an Image (Int)).
like the following example :
booksList.add(Book("The Wild Robot", "A 2 Categorie Book", "Description book", R.drawable.thewildrobot))
booksList.add(Book("Maria Semples", "Categorie Book", "Description book", R.drawable.mariasemples))
RecyclerView Adapter
import android.content.Intent
import android.support.v7.widget.CardView
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import kotlin.collections.ArrayList
#Suppress("UNREACHABLE_CODE")
class RecyclerViewAdapter(private val mContext: List_of_Books, private val mData: MutableList<Book>) : RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder>() {
private var mFilteredList: MutableList<Book>? = null
init {
mFilteredList = mData
}
override fun getItemCount(): Int {
return mData.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view: View
val mInflater = LayoutInflater.from(mContext)
view = mInflater.inflate(R.layout.cardveiw_item_book, parent, false)
return MyViewHolder(view)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.tv_book_title.text = mData[position].getTitle()
holder.img_book_thumbnail.setImageResource(mData[position].thumbnail)
holder.cardView.setOnClickListener {
val intent = Intent(mContext, Book_Activity::class.java)
// passing data to the book activity
intent.putExtra("Title", mData[position].getTitle())
intent.putExtra("Description", mData[position].description)
intent.putExtra("Thumbnail", mData[position].thumbnail)
intent.putExtra("Category", mData[position].category)
// start the activity
mContext.startActivity(intent)
}
}
fun setfilter(listitem: MutableList<Book>): MutableList<Book>? {
mFilteredList!!.clear()
/*mFilteredList = ArrayList()*/
mFilteredList!!.addAll(listitem)
notifyDataSetChanged()
return mFilteredList
}
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
internal var tv_book_title: TextView = itemView.findViewById(R.id.book_title_id) as TextView
internal var img_book_thumbnail: ImageView = itemView.findViewById(R.id.book_img_id) as ImageView
internal var cardView: CardView = itemView.findViewById(R.id.cardview_id) as CardView
}
}
When I write in the EdiText nothing is changing , i'm using this code for the Editext:
fun filter(pl: MutableList<Book>, query: String): MutableList<Book> {
var query = query
query = query.toLowerCase()
val filteredModeList = ArrayList<Book>()
for (model in pl) {
val text = model.getTitle()!!.toLowerCase()
if (text.startsWith(query) || (text.contains(query))) {
filteredModeList.add(model)
}
}
return filteredModeList
}
val editText = findViewById<EditText>(R.id.editText)
editText.hint = getString(R.string.Search_here)
editText.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(p0: Editable?) {
val filtermodelist = filter(booksList, p0.toString())
myAdapter.setfilter(filtermodelist)
}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
})
BOOK CLASS
import com.medanis.fneclisbooks.R.attr.title
import com.medanis.fneclisbooks.R.string.category
import com.medanis.fneclisbooks.R.string.description
import java.util.ArrayList
import kotlin.reflect.KMutableProperty1
import android.R.attr.name
class Book(title: String, category: String, description: String, var thumbnail: Int) {
private var title: String? = title
var category: String? = category
var description: String? = description
fun getTitle(): String? {
return title
}
fun setTitle(title: String) {
this.title = title
}}
I THINK THE PROBLEM IS IN THE FILTER IN THE ADAPTER THERE IS SOMETHING
WRONG THERE PLEASE HELP ME TO FIX IT
Please Help me , and if you need any more informations let me know in comments.

Categories

Resources