I created a RecyclerView that refreshes its list based on a database call. Each row has an options menu that is revealed when the user swipes. My original issue was that after an orientation change, the swipe gestures no longer revealed the menu. I hit all my expected breakpoints with onCreateViewHolder() and the onSwipe(). However, the row remained as the HIDE_MENU view type after swiping.
So I tried to introduce LiveData to persist the state of the list after orientation changes. The RecyclerView was still created and populated with items but now the swipe gesture crashes the application with an error:
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
Do I need to use LiveData to fix the original issue of preserving my swipe functionality after orientation changes? If not, please can someone explain why the item view types are no longer updated after orientation changes.
If I do need to use a ViewModel, what am I doing that is causing the list adapter not to receive the updated list?
HistoryFragment
class HistoryFragment : Fragment() {
private val historyViewModel by activityViewModels<HistoryViewModel>()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val root = inflater.inflate(R.layout.fragment_history, container, false)
historyViewModel.getHistoryList().observe(viewLifecycleOwner, {
refreshRecyclerView(it)
})
return root
}
private fun updateHistoryList() {
val dbHandler = MySQLLiteDBHandler(requireContext(), null)
val historyList = dbHandler.getHistoryList() as MutableList<HistoryObject>
historyViewModel.setHistoryList(historyList)
}
private fun refreshRecyclerView(historyList: MutableList<HistoryObject>) {
val historyListAdapter = HistoryListAdapter(historyList)
val callback = HistorySwipeHelper(historyListAdapter)
val helper = ItemTouchHelper(callback)
history_list.adapter = historyListAdapter
helper.attachToRecyclerView(history_list)
}
private fun setupSort() {
val sortSpinner: Spinner = history_list_controls_sort
sortSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) {}
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
updateHistoryList()
}
}
}
override fun onViewCreated(
view: View,
savedInstanceState: Bundle?
) {
setupSort()
}
}
HistoryListAdapter
const val SHOW_MENU = 1
const val HIDE_MENU = 2
class HistoryListAdapter(private var historyData: MutableList<HistoryObject>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == SHOW_MENU) {
val inflatedView = LayoutInflater.from(parent.context).inflate(R.layout.history_list_view_row_items_menu, parent, false)
MenuViewHolder(inflatedView)
} else {
val inflatedView = LayoutInflater.from(parent.context).inflate(R.layout.history_list_view_row_items_description, parent, false)
HistoryItemViewHolder(inflatedView)
}
}
override fun getItemViewType(position: Int): Int {
return if (historyData[position].showMenu) {
SHOW_MENU
} else {
HIDE_MENU
}
}
override fun getItemCount(): Int {
return historyData.count()
}
fun showMenu(position: Int) {
historyData.forEachIndexed { idx, it ->
if (it.showMenu) {
it.showMenu = false
notifyItemChanged(idx)
}
}
historyData[position].showMenu = true
notifyItemChanged(position)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val item: HistoryObject = historyData[position]
if (holder is HistoryItemViewHolder) {
holder.bindItem(item)
...
}
if (holder is MenuViewHolder) {
holder.bindItem(item)
...
}
}
class HistoryItemViewHolder(v: View, private val clickHandler: (item: HistoryObject) -> Unit) : RecyclerView.ViewHolder(v) {
private var view: View = v
private var item: HistoryObject? = null
fun bindItem(item: HistoryObject) {
this.item = item
...
}
}
class MenuViewHolder(v: View, private val deleteHandler: (item: HistoryObject) -> Unit) : RecyclerView.ViewHolder(v) {
private var view: View = v
private var item: HistoryObject? = null
fun bindItem(item: HistoryObject) {
this.item = item
...
}
}
}
HistorySwipeHelper
class HistorySwipeHelper(private val adapter: HistoryListAdapter) : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean { return false }
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
adapter.showMenu(viewHolder.adapterPosition)
}
override fun getSwipeThreshold(viewHolder: RecyclerView.ViewHolder): Float {
return 0.1f
}
}
HistoryViewModel
class HistoryViewModel(private var historyListHandle: SavedStateHandle) : ViewModel() {
fun getHistoryList(): LiveData<MutableList<HistoryObject>> {
return historyListHandle.getLiveData(HISTORY_LIST_KEY)
}
fun setHistoryList(newHistoryList: MutableList<HistoryObject>) {
historyListHandle.set(HISTORY_LIST_KEY, newHistoryList)
}
companion object {
const val HISTORY_LIST_KEY = "MY_HISTORY_LIST"
}
}
Activity
class MainActivity : AppCompatActivity() {
private val historyViewModel: HistoryViewModel by lazy {
ViewModelProvider(this).get(HistoryViewModel::class.java)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
historyViewModel.setHistoryList(mutableListOf())
}
}
Thanks in advance. If this question is too broad I can try again and decompose it.
You shouldn't create new adapter every time you get an update of your history list. Keep using the same adapter, just update the items and call notifyDataSetChanged() to update the state (of course you can use different methods to notify about the insertion/deletion/etc, but make it work with notifyDataSetChanged() first).
I'm pretty sure this will fix the issue.
Related
when i try to delete first row i get first row back and with duplicate second row
enter image description here
after delete any row from the list gives me duplicate data like this
enter image description here
This is my Adapter class. On my deleteItem function position is passed from fragment class and
it is supposed to delete an item from the given position and update the list but its rendering the duplicate data.
class MyListAdapter :ListAdapter<Article,MyListAdapter.MyViewHolder>(MyDiffUtil()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.recycler_item,parent,false)
return MyViewHolder(view)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val item = getItem(position)
holder.onBind(item)
// to click each item of list
holder.itemView.setOnClickListener {
onItemClickListener?.let {it(item) }
}
}
class MyViewHolder(itemView :View) : RecyclerView.ViewHolder(itemView)
{
fun onBind(article: Article) = with(itemView)
{
Glide.with(this)
.load(article.urlToImage)
.error(R.drawable.notfound)
.into(imageView)
webSource.text = article.source?.name
newsDate.text = article.publishedAt
newsTitle.text = article.title
newsDescription.text = article.description
}
}
// lamda function for handling web view
private var onItemClickListener : ((Article) -> Unit)? = null
fun setOnItemClickListener(listener : (Article) ->Unit)
{
onItemClickListener = listener
}
// implementing diffutil class
class MyDiffUtil : DiffUtil.ItemCallback<Article>()
{
override fun areItemsTheSame(oldItem: Article, newItem: Article): Boolean {
return oldItem.url == newItem.url
}
override fun areContentsTheSame(oldItem: Article, newItem: Article): Boolean {
return oldItem == newItem
}
}
fun deleteItem(pos : Int)
{
var myl = ArrayList<Article>()
val currentList= currentList.toMutableList()
currentList.removeAt(pos)
myl.addAll(currentList)
submitList(myl)
}
}
`
I tried to delete the saved news from the ListAdapter and update the recycler view with animation of DiffUtill class but its not updating the recycler view and
giving duplicate data . How can i delete data with diffutil animation as its normal way. Thanks in advance.
this is my fragment
package com.example.news.Fragments
class SavedNews : Fragment() {
lateinit var mymainViewModel: MainViewModel
lateinit var databaseObject: MyDataBase
lateinit var myAdapter: MyListAdapter
lateinit var convertedArticleList : ArrayList<Article>
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
myAdapter = MyListAdapter()
convertedArticleList = ArrayList()
return inflater.inflate(R.layout.fragment_saved_news, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
savedNewsRecyclerView.layoutManager = LinearLayoutManager(activity,LinearLayoutManager.VERTICAL,
false)
savedNewsRecyclerView.adapter = myAdapter
ItemTouchHelper(object :ItemTouchHelper.SimpleCallback(0,ItemTouchHelper.RIGHT){
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
// this method is called
// when the item is moved.
return true
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
// this method is called when we swipe our item to right direction.
// on below line we are getting the item at a particular position.
val deletedCourse: Article =
convertedArticleList.get(viewHolder.adapterPosition)
myAdapter.deleteItem(viewHolder.adapterPosition)
mymainViewModel.deleteSavedNews(deletedCourse.id!!)
// myAdapter.notifyItemRemoved(viewHolder.adapterPosition)
// myAdapter.submitList(myCurrentList)
// Snackbar.make(savedNewsRecyclerView,"Deleted" + deletedCourse.title,
// Snackbar.LENGTH_LONG).setAction(
// "Undo",
// View.OnClickListener {
//
// convertedArticleList.add(position,deletedCourse)
// myAdapter.notifyItemInserted(position)
// }
// ).show()
}
}).attachToRecyclerView(savedNewsRecyclerView)
}
override fun onResume() {
super.onResume()
Log.d("LIFE","ON Resume")
val myInterfaceObject = ApiInterface.MyObject.getInstance()
databaseObject = MyDataBase.MyObjectDB.getDBInstance(activity as MainActivity)
val myRepository = Repository(myInterfaceObject, databaseObject)
mymainViewModel = ViewModelProvider(
this,
MainViewModelFactory(myRepository)
).get(MainViewModel::class.java)
//listAdapter things
// show saved news in savednews fragment
lifecycleScope.launch(Dispatchers.Main) {
//abstract data from saved room database and converting likedartcile datacass object to
// Artticle data class article
mymainViewModel.abstractSavedNews().observe(viewLifecycleOwner, Observer {
it.forEach { eachLikedArticle ->
val obj = toArticle(eachLikedArticle)
convertedArticleList.add(obj)
}
myAdapter.submitList(convertedArticleList)
})
//clicking the item of save news
myAdapter.setOnItemClickListener {
val bundle = Bundle().apply {
putSerializable("article", it)
}
convertedArticleList.clear()
findNavController().navigate(R.id.action_savedNews_to_article, bundle)
}
}
}
private fun toArticle(rawObject: LikedArticle) = Article(
rawObject.author, rawObject.content,
rawObject.description, rawObject.publishedAt, rawObject.source, rawObject.title,
rawObject.url, rawObject.urlToImage, rawObject.id
)
}
There is not enough information to actually replicate how you're trying to use this in your Fragment/Activity but without changing your code too much, this works (note I used view binding):
class MyListAdapter :
ListAdapter<Article, MyViewHolder>(MyDiffUtil()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = MyViewHolder(
RecyclerItemBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val item = getItem(position)
holder.onBind(item)
}
fun deleteItem(pos: Int) {
var myl = ArrayList<Article>()
val currentList = currentList.toMutableList()
currentList.removeAt(pos)
myl.addAll(currentList)
submitList(myl)
}
}
class MyViewHolder(private val binding: RecyclerItemBinding) : RecyclerView.ViewHolder(binding.root) {
fun onBind(article: Article) = with(binding) {
textView.text = article.url
}
}
class MyDiffUtil : DiffUtil.ItemCallback<Article>() {
override fun areItemsTheSame(oldItem: Article, newItem: Article): Boolean {
return oldItem.url == newItem.url
}
override fun areContentsTheSame(oldItem: Article, newItem: Article): Boolean {
return oldItem == newItem
}
}
Overall this should work.
You can also refactor deleteItem to something more meaningful:
fun deleteItem(pos: Int) {
val oldList = currentList.toMutableList()
oldList.removeAt(pos)
val updatedList = oldList
submitList(updatedList)
}
The title says, I'm trying to load items into a recyclerview but the items doesn't displaying.
I'm getting the items from the api, using retrofit and mutablelivedata, I'm getting the items right, and the adapter gets the items (there are 3 items, and the adapter gets the 3 items), but the items doesn't display on the UI.
Here is my code:
Adapter.java
class EstablecimientosAdapter : ListAdapter<EstablecimientoModel, EstablecimientosViewHolder>(
DIFF_CALLBACK
) {
companion object {
val DIFF_CALLBACK: DiffUtil.ItemCallback<EstablecimientoModel> =
object : DiffUtil.ItemCallback<EstablecimientoModel>() {
override fun areItemsTheSame(
oldItem: EstablecimientoModel,
newItem: EstablecimientoModel
): Boolean {
return oldItem.hash == newItem.hash
}
override fun areContentsTheSame(
oldItem: EstablecimientoModel,
newItem: EstablecimientoModel
): Boolean {
return oldItem.nombre == newItem.nombre
}
}
}
private val mEstablecimientos: MutableList<EstablecimientoModel> = mutableListOf()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EstablecimientosViewHolder {
val binding = RowEstablecimientoBinding.inflate(
LayoutInflater.from(parent.context), parent, false
)
return EstablecimientosViewHolder(binding)
}
override fun onBindViewHolder(holder: EstablecimientosViewHolder, position: Int) {
val establecimiento = getItem(position)
holder.bindItem(establecimiento!!)
}
override fun getItemCount(): Int {
return mEstablecimientos.size
}
fun addMoreEstablecimientos(newEstablecimientos: List<EstablecimientoModel>) {
mEstablecimientos.addAll(newEstablecimientos)
submitList(mEstablecimientos)
}
class EstablecimientosViewHolder(val binding: RowEstablecimientoBinding) :
RecyclerView.ViewHolder(
binding.root
) {
fun bindItem(establecimiento: EstablecimientoModel) {
binding.setVariable(BR.establecimiento, establecimiento)
}
}
}
recycler_view.xml
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rvEstablecimientos"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="#layout/row_establecimiento" />
Fragment.java
val cvGoBackEstablecimientos = binding!!.cvGoBackEstablecimientos
val rvEstablecimientos = binding!!.rvEstablecimientos
val adapter = EstablecimientosAdapter()
rvEstablecimientos.setHasFixedSize(true)
rvEstablecimientos.adapter = adapter
cvGoBackEstablecimientos.setOnClickListener { requireActivity().onBackPressed() }
viewModel?.getNearFreeEstablecimientos(2.0, 2.0)
?.observe(viewLifecycleOwner) { t -> adapter.addMoreEstablecimientos(t!!) }
It seems that I had some problems with the layout, I removed a CoordinatorLayout and it works now.
i am making an app in which i have to insert data into reyclerview , the recyclerview is working fine but the problem is that when i scroll it up adapter reupdate the data , so to solve this issue the code looks fine but still getting this issue ....................................................
BaseClass
abstract class MultiViewModelBaseAdapter<M : Model, VDB : ViewDataBinding>(private var diffCallback: DiffUtil.ItemCallback<M>) : ListAdapter<M ,BaseViewHolder<VDB>>(diffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<VDB> {
val inflator = LayoutInflater.from(parent.context)
val binding = createBinding(viewType, inflator, parent)
return BaseViewHolder(binding)
}
abstract fun createBinding(viewType: Int, inflater: LayoutInflater, parent: ViewGroup) : VDB
override fun onBindViewHolder(holder: BaseViewHolder<VDB>, position: Int) {
bind(holder.mBinding, getItem(position), position)
holder.mBinding.executePendingBindings()
}
abstract fun bind(binding: VDB, item: M, position: Int)
abstract fun onDataChanged(values: Boolean)}
}
Adapter
class LanguageAdapter(
private val context: Context,
private val mViewModel: LanguageListViewModel,
private val onClickListener: OnItemClickListener<String>
) : MultiViewModelBaseAdapter<LanguageSupportModel, ViewDataBinding>(diffCallback) {
companion object {
private val ADS = 1
private val LANGUAGES = 2
val diffCallback = object : DiffUtil.ItemCallback<LanguageSupportModel>() {
override fun areItemsTheSame(
oldItem: LanguageSupportModel,
newItem: LanguageSupportModel
): Boolean = oldItem.dataId == newItem.dataId
/**
* Note that in kotlin, == checking on data classes compares all contents, but in Java,
* typically you'll implement Object#equals, and use it to compare object contents.
*/
override fun areContentsTheSame(
oldItem: LanguageSupportModel,
newItem: LanguageSupportModel
): Boolean = oldItem == newItem
}
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItemViewType(position: Int): Int {
return position
}
override fun createBinding(viewType: Int, inflater: LayoutInflater, parent: ViewGroup): ViewDataBinding {
return DataBindingUtil.inflate(inflater, R.layout.language_view, parent, false)
}
override fun bind(binding: ViewDataBinding, item: LanguageSupportModel, position: Int) {
binding as LanguageViewDataBinding
binding.apply {
language = item
//click
}
}
override fun onDataChanged(values: Boolean) {}
}
Fragment
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val languageAdapter = LanguageAdapter(requireContext(), mViewModel, this ,lifecycleScope)
languageAdapter.submitList(LanguageArray.arrayValues())
reyclerview.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
adapter = languageAdapter
}
If You will Use Paging concept in Scrolling then it will Solve.
In the JAVA or KOTLIN We can implement.. like..
import androidx.viewpager.widget.PagerAdapter;
Then extends it into Adapter Class.
public void addList(List<ClsList> list) {
this.mResources = list;
notifyDataSetChanged(); // also this main line
}
Problem Solve.
☻♥ Have Fun..
I am working on an Ecommerce app. I have come to the first problem I don't know how to tackle, I want to update Cart Value without having to reenter Cart Fragment so if somebody removes a product from the Cart, Cart Value should go down immediately straight away. I have tried several different approaches but none seem to be working.
Users add products to cart in Product Detail fragment -> User goes to cart and sees products in cart via Recycler View -> I have a field with Total Price that is not a part of a recycler. This field does not update when I remove products from cart and I know it cannot do it as of now, cannot figure out how to do it.
I'm using Firebase Cloud to get User and Product data.
Cart Fragment
class CartFragment : RootFragment(), OnProductClick {
private val cartViewModel by viewModels<CartFragmentViewModel>()
private lateinit var binding: FragmentCartBinding
private val adapter = CartAdapter(this)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = DataBindingUtil.inflate(
inflater,
R.layout.fragment_cart,
container,
false
)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.recyclerCart.layoutManager = LinearLayoutManager(requireContext())
binding.recyclerCart.adapter = adapter
binding.buttonToCheckout.setOnClickListener {
navigateToCheckout()
}
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
cartViewModel.userCart.observe(viewLifecycleOwner, { list ->
adapter.setCartProducts(list)
val cartQuantity = list.size
binding.textCartQuantityValue.text = cartQuantity.toString()
val cartValue = cartViewModel.calculateCartValue(list)
binding.textCartTotalValue.text = cartValue.toString()
})
}
// TODO
override fun onProductClick(product: Product, position: Int) {
cartViewModel.removeFromCart(product)
adapter.removeFromCart(product, position)
}
}
Cart View Model
class CartFragmentViewModel : ViewModel() {
private val repository = FirebaseCloud()
private val user = repository.getUserData()
val userCart = user.switchMap {
repository.getProductsFromCart(it.cart)
}
fun calculateCartValue(list: List<Product>): Long {
var cartValue = 0L
if (list.isNotEmpty()) {
for (product in list) {
cartValue += product.price!!
}
}
return cartValue
}
fun removeFromCart(product: Product) {
repository.removeFromCart(product)
}
}
Cart Adapter
class CartAdapter(private val listener: OnProductClick) : RecyclerView.Adapter<CartAdapter.CartViewHolder>() {
private val cartList = ArrayList<Product>()
fun setCartProducts(list: List<Product>) {
cartList.clear()
cartList.addAll(list)
notifyDataSetChanged()
}
fun removeFromCart(product: Product, position: Int) {
cartList.remove(product)
notifyItemRemoved(position)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CartViewHolder {
val inflater = LayoutInflater.from(parent.context)
val view = inflater.inflate(R.layout.list_row_cart, parent, false)
return CartViewHolder(view)
}
override fun onBindViewHolder(holder: CartViewHolder, position: Int) {
bindCartData(holder)
}
private fun bindCartData(holder: CartViewHolder) {
val name = holder.itemView.findViewById<TextView>(R.id.text_product_name_cart)
val price = holder.itemView.findViewById<TextView>(R.id.text_product_price_cart)
val image = holder.itemView.findViewById<ImageView>(R.id.image_product_image_cart)
name.text = cartList[holder.adapterPosition].name
price.text = cartList[holder.adapterPosition].price.toString()
Glide.with(holder.itemView)
.load(cartList[holder.adapterPosition].imageUrl)
.into(image)
}
override fun getItemCount(): Int {
return cartList.size
}
inner class CartViewHolder(view: View) : RecyclerView.ViewHolder(view) {
init {
view.findViewById<ImageView>(R.id.button_remove_from_cart)
.setOnClickListener{
listener.onProductClick(cartList[adapterPosition], adapterPosition)
}
}
}
}
I managed to make it work with not so elegant way and if someone has tips how to use the observer I already have observer in Cart Fragment it would be awesome.
What I've done is I updated onProductClick() in Cart Fragment to recalculate the value once again.
override fun onProductClick(product: Product, position: Int) {
cartViewModel.removeFromCart(product)
adapter.removeFromCart(product, position)
val productsInCart = adapter.cartList
val cartValue = cartViewModel.calculateCartValue(productsInCart)
binding.textCartTotalValue.text = cartValue.toString()
binding.textCartQuantityValue.text = productsInCart.size.toString()
}
I'm studying kotlin, and am stuck about recyclerview.
The task is simple: show data from recycler (inside activity) item clicked inside a fragment.
The Model:
data class MyModel (
val info1:String,
val info2:String,
val info3:String)
the recyclerView is implemented using the idea I saw in Antonio's book (kotlin for android developers) - no intarface is used:
class RecyclerAdapter(
val myList:List<MyModel>,
val listener:(MyModel)->Unit):RecyclerView.Adapter<RecyclerAdapter.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemViewholder = LayoutInflater.from(parent.context).inflate(R.layout.recycler_item,parent,false)
return MyViewHolder(itemViewholder)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.bind(myList[position],listener)
}
override fun getItemCount(): Int {
return myList.count()
}
class MyViewHolder(itemView:View):RecyclerView.ViewHolder(itemView){
fun bind(list:MyModel,itemListener: (MyModel) -> Unit) = with(itemView){
recycler_infor1.text = list.info1
recicler_infor2.text = list.info2
setOnClickListener { itemListener(list) }
}
}}
In Activity:
with(my_recyclerView){
layoutManager = LinearLayoutManager(this#MainActivity,RecyclerView.VERTICAL,false)
setHasFixedSize(true)
adapter = RecyclerAdapter(fakeItens()){
supportFragmentManager.commit {
replace(R.id.fragment_container,FragmentDetail()).addToBackStack(null)
}
}
}
When the app is run, the recyclerView shows in each item the first and second information as well.
Now, I need to show these informations and the third infor inside a Fragment that has three textView:
android:id="#+id/frag_infor1"
android:id="#+id/frag_infor2"
android:id="#+id/frag_infor3"
How can I do this?
Thank's to null_override, I found my solution:
1 - make MyModel Parcelable
data class MyModel(val info1:String?,
val info2:String?,
val info3:String?
):Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.readString(),
parcel.readString()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(info1)
parcel.writeString(info2)
parcel.writeString(info3)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<MyModel> {
override fun createFromParcel(parcel: Parcel): MyModel {
return MyModel(parcel)
}
override fun newArray(size: Int): Array<MyModel?> {
return arrayOfNulls(size)
}
}
}
2 - passing to bundle and set argument to Fragment using apply in both
with(my_recyclerView){
layoutManager = LinearLayoutManager(this#MainActivity,RecyclerView.VERTICAL,false)
setHasFixedSize(true)
adapter = RecyclerAdapter(fakeItens()){
val bundle = Bundle().apply { putParcelable("Key", it) }
supportFragmentManager.commit {
replace(R.id.fragment_container,FragmentDetail().apply { arguments = bundle }).addToBackStack(null)
}
}
}
3 - get data in Fragment
lateinit var data:MyModel
override fun onAttach(context: Context) {
super.onAttach(context)
arguments?.getParcelable<MyModel>("Key").let {
if (it != null) {
data = it
}
}
}
4 - bind views
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
frag_infor1.text = data.info1
frag_infor2.text = data.info2
frag_infor3.text = data.info3
}