KOTLIN / FIREBASE : Image disapear inside RecyclerView - android

I'm using Kotlin for my app.
I have a problem I can't resolve.
I'm using a RecyclerView inside a fragment that show a Grid with 2 items per row.
Inside each item there are text and image loaded from Firebase.
Everything works perfectly. But, I don't know why, randomly, the images disapear and return a white element. The text doesn't changes, only the image changes.
There is two screens, just few seconds appart. In the first one everything is ok, it shows 4 éléments. Then I restart the app and 3 of the 4 images disapear (second screen). Only the last load to and from Firebase stays.
Inside the code, I'm using a data class named DataClassArticle, an adapter named ArticleAdapter and the fragment named Flux.
1 - First screen
2 - Second sceen
3 - Firebase
4 - Data Class
5 - Adapter
6 - Fragment
1 - FIRST SCREEN (EVERYTHING WORK) :
2- SECOND SCREEN (3 OF THE 4 IMAGES DISAPEAR) :
3 - FIREBASE (RETURNING : DESCRIPTION, PRIXVENTE, TITREVENTE, ZONE, PHOTO)
4- DATA CLASS
data class DataClassArticle(
var titrevente: String? = null,
var prixvente: String? = null,
var zone: String? = null,
var photo: String? = null
)
5- ADAPTER
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.givenaskv1.R
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.database.ValueEventListener
import com.squareup.picasso.Picasso
class ArticleAdapter(private var articleList: ArrayList<DataClassArticle>) : RecyclerView.Adapter<ArticleAdapter.ViewHolder>() {
val TAG = "TAG"
var dataList = emptyList<DataClassArticle>()
internal fun setDataList(dataList : List<DataClassArticle>) {
this.dataList = dataList
notifyDataSetChanged()
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var articleImage : ImageView
var articleTitle : TextView
var articlePrice : TextView
var articleLocalisation : TextView
init {
articleImage = itemView.findViewById(R.id.articleImage)
articleTitle = itemView.findViewById(R.id.titreArticle)
articlePrice = itemView.findViewById(R.id.prixArticle)
articleLocalisation = itemView.findViewById(R.id.nomVilleArticle)
val myId = FirebaseAuth.getInstance().uid
com.example.givenaskv1.Map.dbref = FirebaseDatabase.getInstance().getReference("Vente")
com.example.givenaskv1.Map.dbref.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
for (missionSnapshot in snapshot.children) {
// if (missionSnapshot.child("uid").value.toString() == myId) {
val test = missionSnapshot.child("uid").value.toString()
Log.d(TAG, "Ceci est l'UID : ${test}.")
// }
}
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context)
.inflate(R.layout.post_vente, parent, false)
return ViewHolder(v)
}
override fun onBindViewHolder(holder: ArticleAdapter.ViewHolder, position: Int) {
val data = articleList[position]
holder.articleTitle.text = data.titrevente
holder.articlePrice.text = data.prixvente
holder.articleLocalisation.text = data.zone
Picasso.get().load(data.photo).into(holder.articleImage)
}
override fun getItemCount() : Int {
return articleList.size
}
}
6- FRAGMENT
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.GenericTransitionOptions.with
import com.bumptech.glide.Glide.with
import com.bumptech.glide.load.resource.bitmap.BitmapTransitionOptions.with
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.with
import com.example.givenaskv1.R
import com.google.firebase.database.*
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.fragment_flux.*
import kotlinx.android.synthetic.main.fragment_notification.*
import kotlinx.android.synthetic.main.post_vente.*
private const val TAG = "TAG"
class Flux : Fragment() {
private var layoutManager: RecyclerView.LayoutManager? = null
private var adapter: RecyclerView.Adapter<ArticleAdapter.ViewHolder>? = null
private lateinit var dbref : DatabaseReference
private lateinit var userRecyclerview : RecyclerView
private lateinit var userArrayList : ArrayList<DataClassArticle>
private lateinit var articleAdapter: ArticleAdapter
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_flux, container, false)
}
override fun onViewCreated(itemView: View, savedInstanceState: Bundle?) {
super.onViewCreated(itemView, savedInstanceState)
// RvPosts = le recyclerview
btnPublierVente.setOnClickListener {
val bottomSheet = BottomsheetVentes()
bottomSheet.show(fragmentManager!!, "BottomSheet")
}
rvPosts.apply {
userRecyclerview = findViewById(R.id.rvPosts)
userRecyclerview.setHasFixedSize(true)
userArrayList = arrayListOf<DataClassArticle>()
layoutManager = LinearLayoutManager(activity)
rvPosts.setLayoutManager(GridLayoutManager(this.context, 2))
getUserData()
}
}
private fun getUserData() {
dbref = FirebaseDatabase.getInstance().getReference("Vente")
dbref.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
for (userSnapshot in snapshot.children){
val user = userSnapshot.getValue(DataClassArticle::class.java)
userArrayList.add(user!!)
userRecyclerview.adapter = ArticleAdapter(userArrayList)
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
}
Thank you guys for your help.
Have a good day !

Related

lateinit property recview has not been initialized

I have fragment which showing weather for 10 days with getting geolocation city and show exactly weather for this city for 10 days.
I have problem initialization with RecyclerView and Viewmodel.
Also I use Hilt to provide dependencies.
My goal is showing weather by location (already have permission) for 10 days.
import androidx.lifecycle.LiveData
import dagger.hilt.android.lifecycle.HiltViewModel
import db.entities.WeatherData
#HiltViewModel
interface ForecastViewmodel {
val dataforecast:LiveData<List<WeatherData>>
val city : LiveData<String>
val isRefreshing:LiveData<Boolean>
fun onRefresh()
}
#HiltViewModel
class ForecastViewmodelImpl(private val repository: ForecastRepository,
private val day: Day
) : ForecastViewmodel,
ViewModel(){
override val dataforecast = MutableLiveData<List<WeatherData>>()
override val city = MutableLiveData(day.city)
override val isRefreshing = MutableLiveData(true)
init {
loadForecast()
}
private fun loadForecast() {
isRefreshing.value = true
viewModelScope.launch {
try {
val data = repository.getForecast(day.days)
Timber.d("size is ${data}")
}catch (e:Exception){
Timber.e(e)
}
isRefreshing.value = false
}
}
override fun onRefresh() = loadForecast()
private fun Forecastday.toWeatherData() = WeatherData(
date = date,
temp = "${temp.roundToInt()}℃"
)
}
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.testtaskweatherappkevychsol.R
import db.entities.WeatherData
class WeatherRecView:RecyclerView.Adapter<WeatherRecView.WeatherHolder>() {
var listweather = emptyList<WeatherData>()
class WeatherHolder(view:View):RecyclerView.ViewHolder(view)
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): WeatherHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.daily_weather_layout,
parent,false)
return WeatherHolder(view)
}
override fun onBindViewHolder(
holder: WeatherHolder,
position: Int
) {
holder.itemView.findViewById<TextView>(R.id.Dateitem).text = listweather[position].date
holder.itemView.findViewById<TextView>(R.id.tempitem).text = listweather[position]
.temp.toString()
}
override fun getItemCount(): Int {
return listweather.size
}
fun addlistintoUI(list: List<WeatherData>){
listweather = list
}
}
data class WeatherData(
val temp:String,
val date:String
)
import RecyclerView.WeatherRecView
import Viewmodel.ForecastViewmodel
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.testtaskweatherappkevychsol.R
import com.example.testtaskweatherappkevychsol.databinding.FragmentWeatherBinding
import dagger.hilt.android.AndroidEntryPoint
#AndroidEntryPoint
class WeatherAtTheLifeMomentFragment : Fragment(R.layout.fragment_weather){
lateinit var recview:WeatherRecView
private var binding : FragmentWeatherBinding? = null
lateinit var viewmodel:ForecastViewmodel
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val binding = FragmentWeatherBinding.inflate(inflater,container,false)
this.binding = binding
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
with(binding){
this!!.refreshbt.setOnClickListener { viewmodel.isRefreshing }
containerlistweather.adapter = recview
containerlistweather.addItemDecoration(DividerItemDecoration(containerlistweather.context,
(containerlistweather
.layoutManager as LinearLayoutManager).orientation))
with(viewmodel){
dataforecast.observe(viewLifecycleOwner) { recview.listweather = it }
City.text = city.toString()
}
}
}
override fun onDestroyView() {
super.onDestroyView()
binding = null
}
}
lateinit property recview has not been initialized
you are getting this issue as you are trying to access lateinit property recview without initialising it
in WeatherAtTheLifeMomentFragment
From
containerlistweather.adapter = recview
To
recview = WeatherRecView() // initialise recview variable by creating instance of your adapter
containerlistweather.layoutManager = LinearLayoutManager(context) // not sure you have set layout manager in your xml so just adding it in your code as it is necessary to use
containerlistweather.adapter = recview
Also you have create method addlistintoUI in WeatherRecView class so use it and make below mentioned changes to load your data
in WeatherAtTheLifeMomentFragment class
From
dataforecast.observe(viewLifecycleOwner) { recview.listweather = it }
To
dataforecast.observe(viewLifecycleOwner) { recview.addlistintoUI(it) }
in WeatherRecView class
From
fun addlistintoUI(list: List<WeatherData>){
listweather = list
}
To
fun addlistintoUI(list: List<WeatherData>){
listweather.addAll(list)
notifyDataSetChanged()
}
```

Glide won't load pictures Android Kotlin

I need images from firebase storage to be loaded into my application and displayed in recycle view
For this I decided to use a glide
But when I run the application, nothing is displayed, just a blank screen, and there are no errors
I rewrote the code several times, as for me this is the working one, but it still does not work :)
What could be causing it not to work?
NumberFragment
package com.example.hotel2.number
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.hotel2.UserModule
import com.example.hotel2.databinding.FragmentNumberBinding
import com.example.hotel2.utilits.showToast
import com.google.firebase.firestore.FirebaseFirestore
class NumberFragment : Fragment() {
private var _binding: FragmentNumberBinding? = null
private val binding get() = _binding!!
private lateinit var recyclerView: RecyclerView
private lateinit var adapter: NumberAdapter
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentNumberBinding.inflate(inflater, container, false)
val view = binding.root
return view
}
override fun onStart() {
super.onStart()
binding.recycleView.apply {
layoutManager = LinearLayoutManager(activity)
}
fetchData()
}
fun fetchData(){
FirebaseFirestore.getInstance().collection("number/")
.get()
.addOnSuccessListener { documents ->
for (document in documents){
val user = documents.toObjects(UserModule::class.java)
binding.recycleView.adapter = NumberAdapter(context!!, user)
}
}
.addOnFailureListener {
showToast("Error")
}
}
}
NumberAdapter
package com.example.hotel2.number
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.example.hotel2.R
import com.example.hotel2.UserModule
class NumberAdapter(private val context: Context, private val users: List<UserModule>): RecyclerView.Adapter<NumberViewHolder>() {
override fun getItemCount(): Int {
return users.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NumberViewHolder {
return NumberViewHolder(LayoutInflater.from(parent.context)
.inflate(R.layout.recyclerview_item,parent,false))
}
override fun onBindViewHolder(holder: NumberViewHolder, position: Int) {
val user = users[position]
holder.userName.text = user.UserName
Glide.with(context)
.load(user.UserImage)
.into(holder.userImage)
}
}
class NumberViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
val userName: TextView = itemView.findViewById(R.id.textView6)
val userImage: ImageView = itemView.findViewById(R.id.image)
}
UserModule
package com.example.hotel2
data class UserModule(
val UserName: String,
val UserImage: String
){
constructor():this("","")
}

Android Kotlin - Navigate between fragments using textView in recyclerView

I would like to navigate between fragments using a textView inside a recyclerview.
Currently I am successfully navigating between fragments using the item, but I would like to go further and navigate using the individual textViews within an item.
The recyclerview is inflated from a local room database.
Below is my adapter
package com.benb.inventory
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.Toast
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.benb.inventory.data.Item
import com.benb.inventory.data.getFormattedPrice
import com.benb.inventory.databinding.ItemListItemBinding
class ItemListAdapter(private val onItemClicked: (Item) -> Unit) :
ListAdapter<Item, ItemListAdapter.ItemViewHolder>(DiffCallback) {
class ItemViewHolder(internal var binding: ItemListItemBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(item: Item) {
binding.apply {
itemName.text = item.itemName
itemPrice.text = item.getFormattedPrice()
itemShop.text = item.shop.toString()
itemShop.setOnClickListener{
val shopName = itemShop.text.toString()
Toast.makeText(root.context, "Clicked: ${item.shop}", Toast.LENGTH_SHORT ).show()
}
}
}
}
companion object {
private val DiffCallback = object : DiffUtil.ItemCallback<Item>() {
override fun areItemsTheSame(oldItem: Item, newItem: Item): Boolean {
return oldItem == newItem
}
override fun areContentsTheSame(oldItem: Item, newItem: Item): Boolean {
return oldItem.itemName == newItem.itemName
}
}
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): ItemListAdapter.ItemViewHolder {
return ItemViewHolder(ItemListItemBinding.inflate(LayoutInflater.from(parent.context)))
}
override fun onBindViewHolder(holder: ItemListAdapter.ItemViewHolder, position: Int) {
val current = getItem(position)
holder.itemView.setOnClickListener {
onItemClicked(current)
}
holder.binding.itemShop.setOnClickListener {
onItemClicked(current)
val shopName = current.shop
fun showShopList(shopName: String) {
val shopName = holder.binding.itemShop.text.toString()
val action = ItemListFragmentDirections.actionItemListFragmentToShopItemFragment(shopName)
}
}
holder.bind(current)
}
}
This is the fragment that contains the list
package com.benb.inventory
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.benb.inventory.databinding.ItemListFragmentBinding
import kotlinx.coroutines.InternalCoroutinesApi
#InternalCoroutinesApi
class ItemListFragment : Fragment() {
#InternalCoroutinesApi
private val viewModel: InventoryViewModel by activityViewModels {
InventoryViewModelFactory(
(activity?.application as InventoryApplication).database.itemDao()
)
}
private var _binding: ItemListFragmentBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = ItemListFragmentBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val adapter = ItemListAdapter {
val action = ItemListFragmentDirections.actionItemListFragmentToItemDetailFragment(it.id)
this.findNavController().navigate(action)
}
binding.recyclerView.adapter = adapter
viewModel.allItems.observe(this.viewLifecycleOwner) {items ->
items.let {
adapter.submitList(it)
}
}
binding.itemShop.setOnClickListener{
val shop = binding.itemShop.text.toString()
val action = ItemListFragmentDirections.actionItemListFragmentToShopItemFragment(shop)
viewModel.retrieveShopItems(shop)
this.findNavController().navigate(action)
}
binding.recyclerView.layoutManager = LinearLayoutManager(this.context)
binding.floatingActionButton.setOnClickListener {
val action = ItemListFragmentDirections.actionItemListFragmentToAddItemFragment(
getString(R.string.add_fragment_title)
)
this.findNavController().navigate(action)
}
}
}
For clarity this is what the inflated recyclerview looks like, it can contain many items, I have only added one.
At the moment if I click anywhere on the item it takes you to a screen with more detail about the fragment.
[A screenshot of the recycler view][1]
I would like to be able to navigate to a specific fragment depending on the textView clicked.
For example one fragment that only contains other products from the same shop.
As you may notice, I have been able to add an onClickListener in the ViewHolder class, it creates a Toast.
I have not had success in using the same onClickListener to navigate.
Thank you very much.
P.S. Any other advice is welcome, particularly if anyone knows what the #internalcoroutinesAPI thing is about please tell me!
[1]: https://i.stack.imgur.com/k6Td3.png

How to add RecyclerView in a Fragment?

Currently, I am trying to implement RecyclerView inside of Fragment but I cannot find a way to display it.
Here is my MainActivity:
package com.example
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import com.example.projectdrivemark.R
import com.example.projectdrivemark.databinding.ActivityMainBinding
import com.example.recyclerView.MockDatabase.Companion.createMockData
import com.example.recyclerView.PostAdapter
import com.example.recyclerView.RecyclerViewFragment
import com.example.tempConverter.TempConverterFragment
import com.example.uploaderView.UploaderFragment
class MainActivity : AppCompatActivity(), PostAdapter.OnPostClickListener {
private lateinit var binding: ActivityMainBinding
val dummyList = createMockData()
val adapter = PostAdapter(dummyList, this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
title = "First Kotlin App"
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val recyclerView = RecyclerViewFragment()
val tempConverterView = TempConverterFragment()
// recyclerView.layoutManager = LinearLayoutManager(this)
val uploaderView = UploaderFragment(this)
setFragmentView(recyclerView)
binding.bottomNavBar.setOnNavigationItemSelectedListener {
when(it.itemId){
R.id.listView -> setFragmentView(recyclerView)
R.id.tempConverterView -> setFragmentView(tempConverterView)
R.id.videoUploaderView -> setFragmentView(uploaderView)
}
true
}
}
private fun setFragmentView(fragment: Fragment){
supportFragmentManager.beginTransaction().apply {
replace(R.id.main_fragment_view, fragment)
//Will return to previous page when tap "Back Button" on the phone
addToBackStack(null)
commit()
}
}
override fun onEditPost(position: Int){
val clickedPost = dummyList[position]
clickedPost.title = "Updated title"
clickedPost.body = "Updated body"
adapter.notifyItemChanged(position)
}
override fun onDeletePost(position: Int) {
dummyList.removeAt(position)
adapter.notifyItemRemoved(position)
}
fun celsiusFunction(view: View) {
val tempConverter = TempConverterFragment()
tempConverter.celsiusFunction(view)
}
fun farenheitFunction(view: View){
val fahrenheitConverter = TempConverterFragment()
fahrenheitConverter.farenheitFunction(view)
}
}
Here is my RecyclerFragment:
package com.example.recyclerView
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.MainActivity
import com.example.projectdrivemark.R
class RecyclerViewFragment: Fragment() {
var adapter: RecyclerView.Adapter<PostAdapter.PostViewHolder>? = null
var layoutManager: RecyclerView.LayoutManager? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
super.onCreate(savedInstanceState)
val binding = inflater.inflate(R.layout.fragment_list, container, false)
return binding
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.apply{
layoutManager = LinearLayoutManager(activity)
adapter = PostAdapter(dummyData = ArrayList<Post>(), MainActivity())
}
}
}
Here is my PostAdapter code:
package com.example.recyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.MainActivity
import com.example.projectdrivemark.R
class PostAdapter(val dummyData: ArrayList<Post>, val myListener: MainActivity) : RecyclerView.Adapter<PostAdapter.PostViewHolder>() {
inner class PostViewHolder(postView: View) : RecyclerView.ViewHolder(postView), View.OnClickListener{
val iconImage: ImageView = postView.findViewById(R.id.icon_image_view)
val title: TextView = postView.findViewById(R.id.title)
val body: TextView = postView.findViewById(R.id.body)
val deleteIcon: ImageView = postView.findViewById(R.id.delete_post_image)
val editIcon: ImageView = postView.findViewById(R.id.edit_post_image)
init {
deleteIcon.setOnClickListener(this)
editIcon.setOnClickListener(this)
}
override fun onClick(v: View?){
val position = adapterPosition
if(v?.id == editIcon.id){
myListener.onEditPost(position)
}else{
myListener.onDeletePost(position)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PostViewHolder {
val postView = LayoutInflater.from(parent.context).inflate(R.layout.post, parent, false)
return PostViewHolder(postView)
}
override fun onBindViewHolder(holder: PostViewHolder, position: Int) {
val currentPost = dummyData[position]
holder.iconImage.setImageResource(currentPost.image)
holder.title.text = currentPost.title
holder.body.text = currentPost.body
}
override fun getItemCount(): Int {
return dummyData.size
}
interface OnPostClickListener{
fun onEditPost(position: Int)
fun onDeletePost(position: Int)
}
}
If anyone saw something I miss, please do tell me because I am stuck at how to display the RecyclerView. Any help would be appreciate.
Edit:
Here is my MockDatabase:
package com.example.recyclerView
import com.example.projectdrivemark.R
class MockDatabase {
companion object{
fun createMockData(): ArrayList<Post>{
val list = ArrayList<Post>()
for(i in 0 until 20){
val imageToSelect = when (i % 3){
0 -> R.drawable.ic_baseline_account_balance
1 -> R.drawable.ic_baseline_account_circle
2 ->R.drawable.ic_baseline_ac_unit
else -> R.drawable.ic_baseline_access_alarms
}
list.add(
Post(
imageToSelect,
title = "Title post of $i",
body = "Title post of $i"
)
)
}
return list
}
}
}
Here is my Layout_list xml file:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycleViewMain"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
tools:listitem="#layout/recycler_view_item" />
</androidx.constraintlayout.widget.ConstraintLayout>
You need to cast view to RecyclerView to access RecyclerView properties inside apply, also you cannot create instances of Activity by yourself,
MainActivity() is wrong and won't work, instead use requireActivity() which will provide context of Activity to which Fragment is attached to
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.findViewbyId<RecyclerView>(R.id.recycleViewMain).apply{
layoutManager = LinearLayoutManager(requireActivity())
adapter = PostAdapter(dummyData = ArrayList<Post>(), requireActivity() as OnPostClickListener)
}
}
Also, as #Necronet mentioned, add some mock data to see if it is actually rendering.
UPDATE
Instead of passing MainActivity to Adapter, pass OnPostClickListener
adapter = PostAdapter(dummyData = ArrayList<Post>(), requireActivity() as OnPostClickListener)
Adapter
class PostAdapter(val dummyData: ArrayList<Post>, val myListener: OnPostClickListener) : RecyclerView.Adapter<PostAdapter.PostViewHolder>(){
// you can use myListener to call methods
}
It's simple you are passing empty dummyData try using createMockData() instead. Also as a rule of thumb in Android, never ever instatiate an Activity yourself, if you need the reference from within a fragment you can use getActivity() method. So this:
adapter = PostAdapter(dummyData = ArrayList<Post>(), MainActivity())
Should be:
adapter = PostAdapter(dummyData = createMockData(), getActivity() as MainActivity)

The recycler view in my fragment is causing the animations to look choppy

My app is a dictionary app. I am using a room database to save the recent queries in my app. I am showing all the contents of the room database inside my recycler view. When the user searches for a word, the user is taken to the result fragment and the query is added to the room database behind the scenes. It also plays a slide in from right animation when the new fragment is getting added. On pressing the back or the up button, it should take you back with an animation the top level fragment, the main fragment. But the problem I am facing is that something with the recycler view makes that animation look very choppy.
This is how it should look: https://i.imgur.com/vdOtA2Y.mp4
This is how it looks: https://i.imgur.com/OKpDj7G.mp4
I am pasting the fragment with the recycler view, viewmodel and the recycler view adapter here and I am also pasting a link to the whole app's github repo https://github.com/sbeve72/JADA
package com.sbeve.jada.fragments.main
import android.os.Bundle
import android.view.View
import android.view.animation.AlphaAnimation
import android.view.animation.Animation
import android.view.inputmethod.InputMethodManager
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SearchView
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.navigation.NavController
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.sbeve.jada.R
import com.sbeve.jada.activities.MainActivity
import com.sbeve.jada.databinding.FragmentMainBinding
import com.sbeve.jada.recyclerview_utils.RecentQueriesAdapter
import com.sbeve.jada.retrofit_utils.RetrofitInit
class MainFragment : Fragment(R.layout.fragment_main), RecentQueriesAdapter.OnItemClickListener {
private val navController: NavController by lazy {
this.findNavController()
}
//the currently running instance of the activity
private val mainActivityContext: MainActivity by lazy {
activity as MainActivity
}
private val stayInPlaceAnimation: Animation? by lazy {
val anim: Animation = AlphaAnimation(1.0F, 1.0F)
anim.duration = 150
anim
}
private val viewModel: MainViewModel by viewModels()
private lateinit var fragmentMainBinding: FragmentMainBinding
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
fragmentMainBinding = FragmentMainBinding.bind(view)
fragmentMainBinding.queriesRecyclerView.layoutManager = LinearLayoutManager(mainActivityContext)
fragmentMainBinding.currentLanguage.text = RetrofitInit.supportedLanguages.first[mainActivityContext.savedLanguageIndex]
fragmentMainBinding.changeLanguageGearIcon.setOnClickListener {
createChangeLanguageDialog().show()
}
fragmentMainBinding.searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
//work
viewModel.addQuery(mainActivityContext.savedLanguageIndex, query)
navController.navigate(MainFragmentDirections.actionMainFragmentToResultFragment(query))
hideSoftKeyboard()
return true
}
override fun onQueryTextChange(newText: String?) = false
})
setAdapter()
}
override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int) = stayInPlaceAnimation
private fun createChangeLanguageDialog() =
MaterialAlertDialogBuilder(mainActivityContext)
.setTitle(getString(R.string.choose_a_language))
.setSingleChoiceItems(RetrofitInit.supportedLanguages.first, mainActivityContext.savedLanguageIndex)
{ dialogInterface, i ->
fragmentMainBinding.currentLanguage.text = RetrofitInit.supportedLanguages.first[i]
mainActivityContext.applicationSharedPreferences
.edit()
.putInt(getString(R.string.language_setting_key), i)
.apply()
dialogInterface.dismiss()
}
.create()
//hides the keyboard
private fun hideSoftKeyboard() {
val imm: InputMethodManager = mainActivityContext.getSystemService(AppCompatActivity.INPUT_METHOD_SERVICE) as InputMethodManager
//Find the currently focused view, so we can grab the correct window token from it.
var view = mainActivityContext.currentFocus
//If no view currently has focus, create a new one, just so we can grab a window token from it
if (view == null) {
view = View(activity)
}
imm.hideSoftInputFromWindow(view.windowToken, 0)
}
private fun setAdapter() {
viewModel.allQueries.observe(viewLifecycleOwner) {
val adapter = RecentQueriesAdapter(it, this)
fragmentMainBinding.queriesRecyclerView.adapter = adapter
}
}
override fun onItemClick(position: Int) {
val queryText = viewModel.allQueries.value!![position].queryText
navController.navigate(MainFragmentDirections.actionMainFragmentToResultFragment(queryText))
}
}
package com.sbeve.jada.fragments.main
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.sbeve.jada.myApplication
import com.sbeve.jada.retrofit_utils.RetrofitInit
import com.sbeve.jada.room_utils.DictionaryDatabase
import com.sbeve.jada.room_utils.DictionaryDatabaseDAO
import com.sbeve.jada.room_utils.RecentQuery
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class MainViewModel : ViewModel() {
private var roomDatabase = DictionaryDatabase.getInstance(myApplication.getInstance())
private val databaseDao: DictionaryDatabaseDAO = roomDatabase.getDao()
val allQueries = databaseDao.getAllQueries()
fun addQuery(languageIndex: Int, query: String) {
viewModelScope.launch {
withContext(IO) {
val recentQuery = RecentQuery(0, query, RetrofitInit.supportedLanguages.first[languageIndex], System.currentTimeMillis())
databaseDao.addQuery(recentQuery)
}
}
}
}
package com.sbeve.jada.recyclerview_utils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.text.HtmlCompat
import androidx.recyclerview.widget.RecyclerView
import com.sbeve.jada.databinding.QueryLayoutBinding
import com.sbeve.jada.room_utils.RecentQuery
import java.text.SimpleDateFormat
import java.util.*
class RecentQueriesAdapter(private val dataSet: List<RecentQuery>, private val onItemClickListener: OnItemClickListener) :
RecyclerView.Adapter<RecentQueriesAdapter.ViewHolder>() {
class ViewHolder(myItemView: QueryLayoutBinding, private val onItemClickListener: OnItemClickListener) :
RecyclerView.ViewHolder(myItemView.root), View.OnClickListener {
init {
myItemView.root.setOnClickListener(this)
}
private val queryText = myItemView.queryText
fun setQueryText(queryValue: String) {
queryText.text = HtmlCompat.fromHtml(queryValue, HtmlCompat.FROM_HTML_MODE_LEGACY)
}
private val time = myItemView.time
fun setTimeText(timeValue: Long) {
time.text = SimpleDateFormat.getDateTimeInstance().format(Date(timeValue))
}
override fun onClick(v: View?) {
onItemClickListener.onItemClick(adapterPosition)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = QueryLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding, onItemClickListener)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val currentItem = dataSet[position]
holder.setQueryText(currentItem.queryText)
holder.setTimeText(currentItem.timeDate)
}
override fun getItemCount() = dataSet.size
interface OnItemClickListener {
fun onItemClick(position: Int)
}
}

Categories

Resources