Can we use an observer in an observer? - android

Hello everyone I am faced with the following problem. I have a database Room, I have 2 tables POST_TABLE and SELL_TABLE.
Now I need to get data from two tables and add to the arraylist.
I use the observer to track when the sell items are loaded and then add it to the arraylist and same I do to the post items
I do this to show two different view types objects in recycler view.
In ViewModel everything is simple, I get access to the database, receive sell and post DAO and initialize repository.
It seems to me I'm doing wrong to make the observer in the observer in home fragment.
In the best practice I did not find a suitable answer. Maybe somebody knows how to reach data from room correctly?
From HomeFragment
private fun initObserver() {
viewModel.sellList.observe(viewLifecycleOwner, {
viewModel.addSellItemsToArray()
viewModel.postList.observe(viewLifecycleOwner, {
viewModel.addPostItemToArray()
initRecyclerView(viewModel.homeArrayList)
})
})
}
From ViewModel
private val sellRepository: SellRepository
private val postRepository: PostRepository
var sellList: LiveData<List<Sell>>
var postList: LiveData<List<Post>>
private var _homeItem = MutableLiveData<ArrayList<HomeItem>>().apply {
value = arrayListOf()
}
val homeItem get() = _homeItem
val homeArrayList = arrayListOf<HomeItem>()
init {
val sellDao = MainDatabase.getDatabase(application).sellDao()
val postDao = MainDatabase.getDatabase(application).postDao()
sellRepository = SellRepository(sellDao)
postRepository = PostRepository(postDao)
sellList = sellRepository.getAllSellList()
postList = postRepository.getPostList()
}
fun addSellItemsToArray() {
for (sell in sellList.value!!) {
val homeItem = HomeItem()
homeItem.userName = sell.userName
homeItem.userImage = sell.userImage
homeItem.imagesArray = sell.imagesArray
homeItem.desc = sell.desc
homeItem.itemForSell = sell.itemForSell
homeItem.price = sell.price
homeItem.country = sell.country
homeItem.city = sell.city
homeItem.address = sell.address
homeArrayList.add(homeItem)
}
}
fun addPostItemToArray() {
for (post in postList.value!!) {
val homeItem = HomeItem()
homeItem.userName = post.postedUserName
homeItem.userImage = post.userUrl
homeItem.imagesArray = arrayListOf(post.postUrl)
homeItem.desc = post.commit
homeItem.likesCount = post.likesCount
homeArrayList.add(homeItem)
}
}

It seems to me I'm doing wrong to make the observer in the observer in home fragment.
Yes, there are better ways to handle this scenario.
One of this is the one below:
class YourViewModel() : ViewModel() {
private val tempHomeList = mutableListOf<HomeItem>()
private val _homeList = MutableLiveData<HomeItem>()
val homeList: LiveData<HomeItem> = _homeList
private lateinit var sellRepository: SellRepository
private lateinit var postRepository: PostRepository
init {
val sellDao = MainDatabase.getDatabase(application).sellDao()
val postDao = MainDatabase.getDatabase(application).postDao()
sellRepository = SellRepository(sellDao)
postRepository = PostRepository(postDao)
}
fun initList() {
addSellItemsToArray()
addPostItemToArray()
_homeList.value = tempHomeList
}
private fun addSellItemsToArray() {
val sellList = sellRepository.getAllSellList()
for (sell in sellList.value!!) {
val homeItem = HomeItem()
homeItem.userName = sell.userName
homeItem.userImage = sell.userImage
homeItem.imagesArray = sell.imagesArray
homeItem.desc = sell.desc
homeItem.itemForSell = sell.itemForSell
homeItem.price = sell.price
homeItem.country = sell.country
homeItem.city = sell.city
homeItem.address = sell.address
tempHomeList.add(homeItem)
}
}
private fun addPostItemToArray() {
val postList = postRepository.getPostList()
for (post in postList.value!!) {
val homeItem = HomeItem()
homeItem.userName = post.postedUserName
homeItem.userImage = post.userUrl
homeItem.imagesArray = arrayListOf(post.postUrl)
homeItem.desc = post.commit
homeItem.likesCount = post.likesCount
tempHomeList.add(homeItem)
}
}
}
Then in your Fragment do something like:
class YourFragment : Fragment {
private val recyclerAdapter = YourRecyclerAdapter()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
//init your views, view model and your recycler view adapter
//...
recyclerView.adapter = recyclerAdapter
}
//...
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.homeList.observe(viewLifecycleOwner, { list ->
recyclerViewAdapter.updateList(list)
})
//start observing other liveData or do anything else here
//....
viewModel.initList()
}
}
And a sample of your Adapter...
class YourRecyclerAdapter : RecyclerView.Adapter<HomeItemAdapter.ViewHolder> {
private val homeList = mutableListOf<HomeItem>()
fun updateList(list: List<HomeItem>) {
homeList.clear()
homeList.addAll(list)
notifyDataSetChanged()
}
//.... the rest of your adapter and viewholder
}

Related

How to split viewmodel or build master viewmodel with small viewmodels?

I have one pretty big complicated ViewModel and I want to split it or build it with few smaller ViewModels.
Below I want to show how I make my ViewModels in general (please do not laugh, this is my first Android ViewModel). I'm not using DataBinding, just ViewBinding.
class AssignUserTagToInventoryItemViewModel() : ViewModel() {
private val UserTag = "MyApp" + this.javaClass.simpleName
init {
Log.d(UserTag, "Class init called")
loadInventoryItems()
loadRandomUserTags() // todo: replace with real implementation
}
private var allItems = ArrayList<InventoryItemDto?>()
//<editor-fold desc="FilterByName">
private val _filterByName = MutableLiveData<String>("")
val filterByName: LiveData<String> get() = _filterByName
fun setFilterByName(t : String) { _filterByName.value = t; applyFilters();}
//</editor-fold>
//<editor-fold desc="FilterByAssignedToMe">
private val _filterByAssignedToMe = MutableLiveData<Boolean>(false)
val filterByAssignedToMe: LiveData<Boolean> get() = _filterByAssignedToMe
fun setFilterByAssignedToMe(t : Boolean) { _filterByAssignedToMe.value = t; applyFilters(); }
//</editor-fold>
//<editor-fold desc="SelectedInventoryItem">
private val _selectedInventoryItem = MutableLiveData<InventoryItemDto?>(null)
fun getSelectedInventoryItem() : LiveData<InventoryItemDto?> = _selectedInventoryItem
fun setSelectedInventoryItem(itemDto: InventoryItemDto?) {
_selectedInventoryItem.value = itemDto
selectedItemOrUserTagChanged()
}
//</editor-fold>
// <editor-fold desc="FilteredItems">
val _displayedItems = MutableLiveData<ArrayList<InventoryItemDto?>>(ArrayList())
val displayedItems: LiveData<ArrayList<InventoryItemDto?>> get() = _displayedItems
// </editor-fold>
// <editor-fold desc="ItemsListError">
val _itemsListError = MutableLiveData<String>("")
val itemsListError :LiveData<String> get() = _itemsListError
fun setItemsListError(s : String) { _itemsListError.value = s }
// </editor-fold>
//<editor-fold desc="UserTag list">
val _UserTags = MutableLiveData<ArrayList<UserTag>>(ArrayList())
val UserTags : LiveData<ArrayList<UserTag>> get() = _UserTags
fun setUserTags(a : ArrayList<UserTag>) { _UserTags.value = a }
//</editor-fold>
//<editor-fold desc="SelectedUserTagItem">
private val _selectedUserTag = MutableLiveData<UserTag?>(null)
fun getSelectedUserTag() : LiveData<UserTag?> = _selectedUserTag
fun setSelectedUserTag(UserTag : UserTag?) {
_selectedUserTag.value = UserTag
selectedItemOrUserTagChanged()
}
//</editor-fold>
//<editor-fold desc="CanSubmit">
private val _canSubmit = MutableLiveData<Boolean>(false)
val canSubmit: LiveData<Boolean> get() = _canSubmit
//</editor-fold>
private fun selectedItemOrUserTagChanged() {
_canSubmit.value = true
}
private fun loadInventoryItems(){
Log.d(UserTag, "Loading inventory items...")
viewModelScope.launch {
try {
val apiResponse = ApiResponse(ApiAdapter.apiClient.findAllInventoryItems())
if (apiResponse.code == 200 && apiResponse.body != null) {
allItems = apiResponse.body
applyFilters()
Log.d(UserTag, "Loading inventory items done.")
}
else {
setItemsListError(apiResponse.code.toString())
Log.d(UserTag, "Loading inventory items error.")
}
} catch (t : Throwable) {
setItemsListError(t.message.toString())
}
}
}
private fun applyFilters(){
Log.d(UserTag, "ViewModel apply filters called. Current name filter: ${filterByName.value}")
val tempResults = ArrayList<InventoryItemDto?>()
val nameFilterLowercase = filterByName.value.toString().lowercase()
if (!filterByName.value.isNullOrEmpty()) {
for (item in allItems) {
val itemNameLowercase = item?.name?.lowercase()?:""
if (itemNameLowercase.contains(nameFilterLowercase))
tempResults.add(item)
}
_displayedItems.value = tempResults
} else {
_displayedItems.value = allItems
}
}
private fun loadRandomUserTags(){
val temp = ArrayList<UserTag>()
for (i in 1..50){
val epc = getRandomHexString(24).uppercase()
val UserTag = UserTag(epc, 0, "0")
temp.add(UserTag)
}
viewModelScope.launch {
delay(100)
_UserTags.value = temp
}
}
private fun getRandomHexString(numchars: Int): String {
val r = Random()
val sb = StringBuffer()
while (sb.length < numchars) {
sb.append(Integer.toHexString(r.nextInt()))
}
return sb.toString().substring(0, numchars)
}
}
Simply create multiple view models according to the task they are performing.
There are several problems here :
Your ViewModel name is too long
You can create an object of the getRandomHexString and this way you can use it inside any other classes or ViewModels you may need in future. It also saves space inside ViewModel.
Learn about the clean architecture and follow its practices. Here, you can create a separate view model or helper class for filtering your results. If you create another view model, you can simply retrieve results from your current view model to the activity and call filter view model inside your activity. This way you can separate code blocks according to the role they play or the function they perform.

Retrieve Firebase data using Coroutines

I'm trying to rewrite my program and start using Kotlin Coroutines.
That is my function to retrieve a list of products for a given group. After debugging it looks like everything is correct.
class FirebaseRepository {
private val db = FirebaseFirestore.getInstance()
private val auth = FirebaseAuth.getInstance()
fun getCurrentUserId(): String{
return auth.currentUser!!.uid
}
suspend fun getLista(): MutableLiveData<List<Produkt>> {
val result = MutableLiveData<List<Produkt>>()
val lista = mutableListOf<Produkt>()
db.collection(Constants.GROUP)
.document("xGRWy21hwQ7yuBGIJtnA")
.collection("Przedmioty")
.orderBy("dataDodaniaProduktu", Query.Direction.DESCENDING)
.get().await().forEach {
val singleProdukt = it.toObject(Produkt::class.java)
singleProdukt.produktId = it.id
lista.add(singleProdukt)
result.postValue(lista)
}
return result
}
That is my ViewModel class:
class ListaViewModel: ViewModel() {
private val repository = FirebaseRepository()
var _produkty = MutableLiveData<List<Produkt>>()
val produkty : LiveData<List<Produkt>> = _produkty
init {
viewModelScope.launch {
_produkty = repository.getLista()
}
}
And finally in my fragment I'm trying to observe live data but looks like nothing is being passed to my adapter. What am I doing wrong?
class ListaFragment : Fragment(), ListaAdapter.OnItemClickListener {
private var _binding: FragmentListaBinding? = null
private val binding get() = _binding!!
private lateinit var recyclerView : RecyclerView
private lateinit var listAdapter : ListaAdapter
private val listaViewModel by viewModels<ListaViewModel>()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = FragmentListaBinding.inflate(inflater, container, false)
recyclerView = binding.recyclerView
listAdapter = ListaAdapter(emptyList(), this)
recyclerView.adapter = listAdapter // Zapobiega "No adapter attached; skipping layout"
recyclerView.layoutManager = LinearLayoutManager(requireActivity())
recyclerView.setHasFixedSize(true)
listaViewModel.produkty.observe(viewLifecycleOwner, Observer {
listAdapter = ListaAdapter(it, this)
}
return binding.root
}
Try replacing this:
val produkty : LiveData<List<Produkt>> = _produkty
with this
val produkty : LiveData<List<Produkt>> get() = _produkty
This way you'll have "getter" rather than "initializer". Initializer will compute its value once (to the empty live data) and after you reassign that var it won't change the value of your val.
The problem in your code lies in the fact that you're creating a new instance of your ListaAdapter class inside the observe() method, without notifying the adapter about the changes. That's the reason why you're getting no results in the adapter. To solve this, simply create a method inside your adapter class:
fun setProduktList(produktList: List<Produkt>) {
this.produktList = produktList
notifyDataSetChanged()
}
Then inside your observe() method, use the following line of code:
listaViewModel.produkty.observe(viewLifecycleOwner, Observer {
//listAdapter = ListaAdapter(it, this) //Removed
listAdapter.setProduktList(it) 👈
}

How can I observe the change in the database in Room?

I save the users I brought from the database in the room first. And their favorite status in the database is false. Then when I favorite it, I change its status. Every time I do this the adapter reloads. I used DiffUtil for this.
In addition, I expect the status of the adapter to remain the same after favorites on the Detail page, and if favorites are made on the detail page, it should be reflected on the adapter.
Because of the function I called from viewmodel in UserListFragment, all data is reloaded when fragment occurs.
Fragment
#AndroidEntryPoint
class UserListFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val args: UserListFragmentArgs by navArgs()
val binding = FragmentUserListBinding.inflate(inflater, container, false)
val viewModel = ViewModelProvider(this).get(UserListViewModel::class.java)
(this.activity as AppCompatActivity).supportActionBar?.title = "Github Users"
binding.lifecycleOwner = viewLifecycleOwner
binding.viewModel = viewModel
viewModel.userSearch(args.term) //!!!
binding.userListRecyclerView.adapter = UserListAdapter(UserListAdapter.OnClickListener {
val action = it.login.let { login ->
UserListFragmentDirections.actionUserListFragmentToUserDetailFragment(
login!!
)
}
findNavController().navigate(action)
},viewModel)
viewModel.users.observe(viewLifecycleOwner) {
bindRecyclerView(binding.userListRecyclerView, it)
}
return binding.root
}
}
ViewModel
#HiltViewModel
class UserListViewModel #Inject constructor(
private val repository: RoomRepository,
private val firestoreRepository: FirestoreRepository,
private val githubApiService: GithubApiService,
) :
ViewModel() {
private val _users = MutableLiveData<List<UserEntity>?>()
val users: LiveData<List<UserEntity>?>
get() = _users
private val userEntities: MutableList<UserEntity> = mutableListOf()
private val mutableMap: MutableMap<String?, Any?> = mutableMapOf()
fun userSearch(term: String) {
loadFromCache(term)
viewModelScope.launch {
val getPropertiesDeferred = githubApiService.searchUser(term)
try {
val result = getPropertiesDeferred.body()
result?.users?.forEach {
userEntities.add(
UserEntity(
term = term,
login = it.login,
avatar_url = it.avatar_url,
favorite = "no"
)
)
mutableMap.put(term,userEntities)
}
updateSearchResults(userEntities, term)
firestoreRepository.saveSearchResults(mutableMap,term)
} catch (e: Exception) {
Log.e("userListErr", e.message.toString())
}
}
}
fun favorite(login: String){
viewModelScope.launch {
val list = repository.getUserFavoriteStatus(login)
if (list.isNotEmpty()){
if (list[0].favorite == "no"){
repository.addFavorite(login)
}else{
repository.removeFavorite(login)
}
loadFromCache(list[0].term.toString())
}
}
}
private fun updateSearchResults(userEntities: List<UserEntity>, term: String) {
viewModelScope.launch(Dispatchers.IO) {
val favs = repository.getFavorites(term)
repository.insertSearchResults(userEntities)
if (favs.isNotEmpty()){
favs.forEach {
favorite(it.login.toString())
}
}
loadFromCache(term)
}
}
private fun loadFromCache(term: String) {
viewModelScope.launch() {
val list = repository.getSearchResults(term)
if (list.isNotEmpty()){
_users.value = list
}else{
Log.e("boş","boş dürüm")
}
}
}
}

RecyclerView only displaying correct data when using breakpoints

I am trying to make my RecylerView display data from a database, however the recyclerView displays nothing, unless i walk through the code with breakpoints, in which case it displays as expected. In the EssayPlanDialogFragment i inisialised an empty arrayList to store the essay lists which then has essayParagrpahs added to it either if the dialogFragemnt is called from the previous essayFragment, in which case the fillIn() function is called to turn database data into paragraphs or if the add paragraph is pressed to add a new empty paragraph. The breakpoint that seem to make it work is on the var paragraphList = ArrayList() and triggers 8 times before displaying the data
RecyclerView Adapter
class EssayPlanAdapter(): RecyclerView.Adapter<EssayPlanAdapter.ViewHolder>() {
var paragraphList = ArrayList<essayParagraph>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
var view = LayoutInflater.from(parent.context).inflate(R.layout.essay_paragraph_layout, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
///code
}
override fun getItemCount(): Int {
return paragraphList.size
}
fun setData(paragraph: ArrayList<essayParagraph>) {
this.paragraphList = paragraph
notifyDataSetChanged()
}
//more code ViewHolder Class and code help with adding essayPlan to databse
}
EssayPlanDialogFragment
class essayPlayDialogFragment(questionId:Int,fromEssay:Int): DialogFragment() {
var paragraphs = ArrayList<essayParagraph>()
var fromEssay = fromEssay
lateinit var introduction: LinearLayout
lateinit var title:EditText
var questionId = questionId
override fun onCreateView(){
//code
}
override fun onViewCreated(view: View, #Nullable savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val adapter = EssayPlanAdapter()
title = view.findViewById(R.id.essayTitle)
introduction = view.findViewById(R.id.introduction)
val viewModle = ViewModelProvider(this).get(essayViewModle::class.java)
val paragraphRecycler: RecyclerView = view.findViewById(R.id.essayPlanRecycler)
val closeBtn: ImageButton = view.findViewById(R.id.closeButton)
val finishBtn:ImageButton = view.findViewById(R.id.finnishButton)
//if Dialog fragment opened from previousEssays prafment fromEssay == 1, if from makeNewEssayPragment == 0
if (fromEssay == 1){
val essay = viewModle.checkId(questionId) //returns essay with aprriate essayId
paragraphRecycler.adapter = adapter
paragraphRecycler.layoutManager = LinearLayoutManager(requireContext())
var tempEssays = fillIn(essay,introduction)
adapter.setData(tempEssay)
}
else{
paragraphRecycler.adapter = adapter
paragraphRecycler.layoutManager = LinearLayoutManager(requireContext())
adapter.setData(paragraphs)
}
val button: Button = view.findViewById(R.id.addParagraph)
button.setOnClickListener(){
paragraphs.add(essayParagraph("","","",""))
adapter.setData(paragraphs)
}
finishBtn.setOnClickListener {
//add essay to database
}
fun constructEssayPlanData(adapter: EssayPlanAdapter,intro:LinearLayout,ID:Int):EssayPlan{
//make essayPlan to be added to database
}
fun fillIn(essay:EssayPlan,intro: LinearLayout): ArrayList<essayParagraph>{
intro.lineOfThought.setText(essay.LOT.toString())
intro.relaventPlot.setText(essay.intro.toString())
title.setText("TestTest")
var topicSentences = essay.topicSentences.split("+").toMutableList()
topicSentences.removeAt(0)
var firstQuotes = essay.firstQuotes.split("+").toMutableList()
firstQuotes.removeAt(0)
var secondQuotes = essay.SecondQuotes.split("+").toMutableList()
secondQuotes.removeAt(0)
var thirdQuotes = essay.ThirdQuotes.split("+").toMutableList()
thirdQuotes.removeAt(0)
for(i in 0..(essay.numParagraph -1)){
var essayTemp = essayParagraph(topicSentences[i],firstQuotes[i],secondQuotes[i],thirdQuotes[i])
paragraphs.add(essayTemp)
}
return paragraphs
}
}
ViewModel
fun checkId(id:Int):EssayPlan{
var essay = EssayPlan(id,"","","","","","","",0)
viewModelScope.launch(Dispatchers.IO) {
essay = repository.check(id)
}
return essay
}
repository
fun check(id:Int):EssayPlan{
var essayPlans: EssayPlan = essayPlanDao.checkExist(id)
return essayPlans
}
DAO
#Query("SELECT * FROM plans WHERE id == :id LIMIT 1")
fun checkExist(id:Int):EssayPlan

Room Data doesn't show in the RecyclerList

It's first time using Room Data while also using MVVM pattern. The aim is that I want my data to appeard on the RecyclerList but it's doesn't shut down nor shows me any error it's just appears empty.
Here is my Database class:
#Database(entities = [Plant::class, Plant_Category::class], version = 1)
abstract class PlantDatabase:RoomDatabase() {
abstract fun plantDao(): PlantOperations
abstract fun plantCategoryDao(): PlantCategoryOperations
companion object {
private var INSTANCE: PlantDatabase? = null
fun getDatabase(context: Context): PlantDatabase {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(
context.applicationContext,
PlantDatabase::class.java, DB_NAME // contains directory of sqlite database
)
.fallbackToDestructiveMigration()
.build()
}
return INSTANCE!!
}
}
}
My dao class:
#Dao
interface PlantOperations {
#Query("SELECT * FROM Plant")
fun getAll(): Flow<List<Plant>>
#Insert
fun insertPlant( plant: Plant)
#Delete
fun delete(plant:Plant)
#Update
fun updatePlant(plant:Plant)}
This is my repository class:
class PlantRepository(application:Application){
private var allPlants = MutableLiveData<List<Plant>>()
private val plantDAO = PlantDatabase.getDatabase(application).plantDao()
init {
CoroutineScope(Dispatchers.IO).launch {
val plantData = plantDAO.getAll()
plantData.collect{
allPlants.postValue(it)
}
}
}
fun getAllPlants(): MutableLiveData<List<Plant>> {
return allPlants
}
}
My Viewmodel class:
class PlantViewModel(
application: Application
): AndroidViewModel(application) {
private var repository = PlantRepository(application)
private var _allPlants = repository.getAllPlants()
val allPlants: MutableLiveData<List<Plant>>
get() = _allPlants
}
My Recycler in Fragment:
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?, savedInstanceState: Bundle?): View? {
lateinit var photoAdapter: Photo_Adapter
lateinit var plantViewModel: PlantViewModel
val view: View = inflater.inflate(R.layout.fragment_edit__form, container, false)
val fab = view.findViewById(R.id.floatingActionButton) as FloatingActionButton
val recyclerView = view.findViewById(R.id.recyclerView) as RecyclerView
recyclerView.layoutManager = GridLayoutManager(context, 2)
photoAdapter = Photo_Adapter(context)
recyclerView.adapter = photoAdapter
plantViewModel = ViewModelProvider(this).get(PlantViewModel::class.java)
plantViewModel.allPlants.observe(viewLifecycleOwner, androidx.lifecycle.Observer {
photoAdapter.setDataList(it)
})
// photoAdapter.setDataList(dataList)
//Floating button that opens the Form in order to add plant
fab?.setOnClickListener {
val intent = Intent(view.context, Edit_Form::class.java)
startActivity(intent);
}
return view
}
This is my adapter class:
class Photo_Adapter(var context: Context?) : RecyclerView.Adapter<Photo_Adapter.ViewHolder>() {
var dataList = emptyList<Plant>()
internal fun setDataList(dataList: List<Plant>) {
this.dataList = dataList
notifyDataSetChanged()
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
// Get the data model based on position
var data = dataList[position]
holder.title.text = data.name
holder.desc.text = data.type.toString()
holder.image.setImageResource(data.image)
holder.relativeLayout.setOnClickListener { view -> //Toast.makeText(view.getContext(),"click on item: "+model.getTitle(),Toast.LENGTH_LONG).show();
val intent = Intent(view.context, PlantDetails::class.java)
intent.putExtra("plant_name", data.name)
intent.putExtra("plant_image",data.image)
intent.putExtra("plant_type", data.type.type)
intent.putExtra("plant_water", data.type.water_time)
intent.putExtra("plant_details", data.type.details)
view.context.startActivity(intent)
}
}
// Provide a direct reference to each of the views with data items
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var image: ImageView
var title: TextView
var desc: TextView
var relativeLayout: CardView
init {
image = itemView.findViewById(R.id.image)
title = itemView.findViewById(R.id.title)
desc = itemView.findViewById(R.id.desc)
relativeLayout = itemView.findViewById<View>(R.id.relativeLayout) as CardView
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Photo_Adapter.ViewHolder {
// Inflate the custom layout
var view = LayoutInflater.from(parent.context).inflate(R.layout.photo_layout, parent, false)
return ViewHolder(view)
}
// total count of items in the list
override fun getItemCount() = dataList.size
}
Perhaps I forgot to add something? In Anyway I will be grateful for your help.
You should not observe data on your repository, your activity/view should observe this data. Take a look at this:
First, add this dependency to your gradle:
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1"
Then in your repository
class PlantRepository(application:Application){
private val plantDAO = PlantDatabase.getDatabase(application).plantDao()
fun getAllPlants(): Flow<List<Plant>> = plantDAO.getAll()
}
In your view model:
class PlantViewModel(
application: Application
): AndroidViewModel(application) {
private var repository = PlantRepository(application)
val allPlants = repository.getAllPlants()
.flowOn(Dispatchers.IO)
.asLiveData()
}
And your activity is fine, but check your adapter, make sure that you're notifing your adapter that your list has changed.
You can also work (collect) flows on your view, but this depends on you

Categories

Resources