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()
}
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)
}
hello I have an activity that has a navigation bar and fragments inside, in one of my fragments I save data in firebase, I want to get those data and display it in other fragment with recycler view. I watched a tutorial on youtube to do it cuz my teacher didn't teach us anything, the issue is the fragment that was supposed the display the data shows nothing, it's blank but I didn't understand why cuz I'm really new to this, if someone can take a look at my code and help me I would really appreciate it
This is my data class
data class Event(var eventName: String, var eventTime:String?=null)
This is ViewModel
class EventViewModel :ViewModel() {
private val repository : EventRepository
private val _allEvents = MutableLiveData<List<Event>>()
val allEvents : LiveData<List<Event>> = _allEvents
init {
repository= EventRepository().getInstance()
repository.loadEvents(_allEvents)
}
}
This is Repository
class EventRepository {
private val databaseReference: DatabaseReference= FirebaseDatabase.getInstance().getReference("PetEvents")
#Volatile private var INSTANCE : EventRepository ?=null
fun getInstance() : EventRepository{
return INSTANCE ?: synchronized(this) {
val instance = EventRepository()
INSTANCE=instance
instance
}
}
fun loadEvents(eventList : MutableLiveData<List<Event>>){
databaseReference.addValueEventListener(object:ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
try {
val _eventList : List<Event> = snapshot.children.map { dataSnapshot ->
dataSnapshot.getValue(Event::class.java)!!
}
eventList.postValue(_eventList)
}
catch (e: Exception){
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
}
This is Adapter
class EventAdapter : RecyclerView.Adapter<EventAdapter.MyViewHolder>() {
private var eventList =ArrayList<Event>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(
R.layout.event_item_cell,
parent, false
)
return MyViewHolder(itemView)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = eventList[position]
holder.eventName.text =currentItem.eventName
holder.eventTime.text =currentItem.eventTime
}
override fun getItemCount(): Int {
return eventList.size
}
fun updateEventList(eventList: List<Event>){
this.eventList.clear()
this.eventList.addAll(eventList)
notifyDataSetChanged()
}
class MyViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
val eventName :TextView = itemView.findViewById(R.id.txEventName)
val eventTime :TextView = itemView.findViewById(R.id.txEventTime)
}
}
And this is the fragment I wish to display the data
private lateinit var viewModel : EventViewModel
private lateinit var eventRecyclerView: RecyclerView
lateinit var adapter: EventAdapter
class MainFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_main, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
eventRecyclerView=view.findViewById(R.id.recyclerView)
eventRecyclerView.layoutManager= LinearLayoutManager(context)
eventRecyclerView.setHasFixedSize(true)
adapter = EventAdapter()
eventRecyclerView.adapter= adapter
viewModel = ViewModelProvider(this).get(EventViewModel::class.java)
viewModel.allEvents.observe(viewLifecycleOwner, Observer {
adapter.updateEventList(it)
})
}
}
In my fragment xml I put a recycler view, there's no issue about that
And my item cell is a cardview idk if it has anything to with the problem I'm getting tho
I have this fragment in which I store my 'favorite items' and I can delete them when I click on a button if I want to. The implementation works well until I get to the last item and it doesn't disappear unless I go to another fragment and then come back (as in, the item is deleted but the recycler view still shows it unless I update the fragment myself).
How can I make the last item disappear right away? Setting notifyDataSetChanged() after the deleteHandler in the adapter does not seem to work.
This is the fragment where I have the items:
class FavoritesFragment : Fragment() {
private val mfavoriteViewModel by viewModels<FavoriteViewModel>()
private lateinit var binding: FragmentFavoritesBinding
private val deleteHandler: (Favorites) -> Unit = {
mfavoriteViewModel.deleteFavorite(it)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
binding = FragmentFavoritesBinding.inflate(layoutInflater)
//recyclerview
val adapter = FavoritesAdapter(deleteHandler)
binding.rvFavList.layoutManager = LinearLayoutManager(context)
binding.rvFavList.adapter = adapter
//favoriteViewModel
mfavoriteViewModel.readAllData.observe(viewLifecycleOwner, { favorite ->
if (favorite.isEmpty()) {
binding.emptyState.text = getString(R.string.emptyState)
binding.emptyState.visibility = View.VISIBLE
} else {
adapter.setData(favorite)
binding.emptyState.visibility = View.GONE
}
})
return binding.root
}
}
The adapter:
class FavoritesAdapter(val deleteHandler: (Favorites) -> Unit) :
RecyclerView.Adapter<FavoritesAdapter.ViewHolder>() {
private var favoriteList = emptyList<Favorites>()
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val binding = FavItemBinding.bind(itemView)
val favTitle: TextView = binding.tvFavsTitle
val favItem: ImageButton = binding.btnFavs
val favImg: ImageView = binding.ivFavs
fun bind(favorites: Favorites) {
Picasso.get().load(favorites.image).into(favImg)
favTitle.text = favorites.title
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.fav_item, parent, false)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(favoriteList[position])
//delete favorite item
holder.favItem.setOnClickListener {
deleteHandler(favoriteList[position])
}
}
override fun getItemCount(): Int {
return favoriteList.size
}
fun setData(favorite: List<Favorites>) {
this.favoriteList = favorite
notifyDataSetChanged()
}
}
This is the favorite's viewmodel:
class FavoriteViewModel(application: Application) : AndroidViewModel(application) {
val readAllData: LiveData<List<Favorites>>
private val repository: FavoritesRepository
init {
val favoriteDao = FavoriteDatabase.getDatabase(application).favoriteDao()
repository = FavoritesRepository(favoriteDao)
readAllData = repository.readAllData
}
fun addFavorite(favorite: Favorites) {
viewModelScope.launch(Dispatchers.IO) {
repository.addFavorite(favorite)
}
}
fun deleteFavorite(favorite: Favorites) {
viewModelScope.launch(Dispatchers.IO) {
repository.deleteFavorite(favorite)
}
}
fun deleteAllFavorites() {
viewModelScope.launch(Dispatchers.IO) {
repository.deleteAllFavorites()
}
}
}
Here in your observer:
mfavoriteViewModel.readAllData.observe(viewLifecycleOwner, { favorite ->
if (favorite.isEmpty()) {
binding.emptyState.text = getString(R.string.emptyState)
binding.emptyState.visibility = View.VISIBLE
} else {
adapter.setData(favorite)
binding.emptyState.visibility = View.GONE
}
})
When the list goes from one item to zero items, in the if block you show an empty message, but you fail to update the adapter data or hide the RecyclerView so it will continue to show what it did before. You should move the adapter.setData(favorite) outside the if/else.
Clear your favourites list before setting the new items in it. You can do this in your setData() function. Like this,
fun setData(favorite: List<Favorites>) {
if (favouriteList.isNotEmpty()) {
favouriteList.clear()
}
this.favoriteList = favorite
notifyDataSetChanged()
}
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.
i have recyclerview item which has 4 edittexts. Also i have add new item button which add new item and new edittexts(they need to be populated from the use) i`m trying to retrieve all data from the fields when user click save button. Here is my code:
class SectionsRecyclerAdapter(private val educationList: MutableList<Any>) :
RecyclerView.Adapter<SectionsRecyclerAdapter.ViewHolder>() {
class ViewHolder(val item: View) : RecyclerView.ViewHolder(item)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_new_section, parent, false)
return ViewHolder(view)
}
override fun getItemCount() = educationList.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
if (holder != null) {
holder.item.deleteBtn.visibility = if (position != 0) View.VISIBLE else View.GONE
holder.item.deleteBtn.setOnClickListener {
educationList.removeAt(position)
notifyItemRemoved(position)
notifyItemRangeRemoved(position, educationList.size)
}
}
}
fun addItem() {
educationList.add(EducationModel())
notifyItemInserted(educationList.size)
}
}
Education Fragment :
class EducationFragment : Fragment(), ValidationInterface {
private var educationList: MutableList<Any> = mutableListOf()
private lateinit var sectionAdapter : SectionsRecyclerAdapter
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_education, container, false)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
educationList.add(EducationModel())
sectionAdapter = SectionsRecyclerAdapter(educationList)
educationRv.apply {
layoutManager = LinearLayoutManager(activity)
adapter = ScaleInAnimationAdapter(sectionAdapter)
itemAnimator = LandingAnimator()
}
addSectionBtn.setOnClickListener {
sectionAdapter.addItem()
educationRv.smoothScrollToPosition(educationList.size)
}
}
companion object {
val instance = EducationFragment()
}
override fun validateAndSave(): Boolean {
//Here i want to get data from every child and then parse it to my model EducationModel
val model = educationRv.getChildAt(0)
list.add(model)
CreateResumeActivity.modelInstance.educationList.addAll(list)
return true
}
Of course if there are better solution i will be glad, but for now i`m stuck with this... My main goal is when user click save i need to retrieve value from the edittext ( University, StartDate, EndDate, Summary) and put it in EducationModels
Inside a recycler view each view holder can recycle his views. For that reason you have to keep all edittext values in a public list inside your adapter and access it from component which hold that adapter. Here is an proof of concept:
class MyAdapter: RecyclerView.Adapter(private val educationList: MutableList<Any>) {
val holderList = educationList.map { EditTextValues(...) };
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
//fill edit text just in case that it is recycled
holder.editText.text = holderList[position].editTextValue
holder.editText.onTextChangeLister { holderList[position] = EditTextValues(holder.editText.text) }
}
}
class MyAndroidComponent : Fragment {
val adapter: MyAdapter = ...
fun onCreate() {
saveButton.setOnClickListener {
// you can access your edit texts values here
adapter.holderList
}
}
}