I already find question-related to my problem but I still don't really get the idea. I want to get data images from the database URL in firebase storage using glide. but my logcat shows this line.
2023-02-14 10:02:36.417 25063-25063/com.isjieman.ocion W/ClassMapper: No setter/field for post_image found on class com.isjieman.ocion.model.Post
2023-02-14 10:02:36.436 25063-25063/com.isjieman.ocion W/ClassMapper: No setter/field for background_image found on class com.isjieman.ocion.model.User
2023-02-14 10:02:36.436 25063-25063/com.isjieman.ocion W/ClassMapper: No setter/field for profile_image found on class com.isjieman.ocion.model.User
2023-02-14 10:02:36.438 25063-25063/com.isjieman.ocion W/Glide: Load failed for with size [960x240]
class com.bumptech.glide.load.engine.GlideException: Failed to load resource
the problem is only for field image on the model. i already succeed on retrieve the other data from firebase except the image only. how do i solve this more technically? glad if someone wants to explain my problem
here's the database structure
{
"Posts": {
"-NNsor5WiX9wxTDf7qo5": {
"category": "Art",
"description": "tes 123",
"duration": "-",
"paymentMethods": "e-wallet",
"postId": "-NNsor5WiX9wxTDf7qo5",
"post_image": "https://firebasestorage.googleapis.com/v0/b/final-project-idn.appspot.com/o/Posts%20Pictures%2F1675990621049.jpg?alt=media&token=f7b747c0-1efe-4f43-9ff1-729c7d99c7c1",
"priceRange": "Rp 0 - 10.000",
"publisher": "6FzpJ2sQC9gewbUIGHB8hiNWK1z2",
"title": "tes"
}
},
"User": {
"6FzpJ2sQC9gewbUIGHB8hiNWK1z2": {
"background_image": "https://firebasestorage.googleapis.com/v0/b/final-project-idn.appspot.com/o/Default%20Images%2Fimg_background.png?alt=media&token=b51e7cf5-2015-4cc4-9583-159373d081e2",
"bio": "Member of NCT",
"email": "mark#gmail.com",
"link": "",
"profile_image": "https://firebasestorage.googleapis.com/v0/b/final-project-idn.appspot.com/o/Profile%20Pictures%2F6FzpJ2sQC9gewbUIGHB8hiNWK1z2.jpg?alt=media&token=d174fad9-2f8c-4964-83ec-549f18876587",
"uid": "6FzpJ2sQC9gewbUIGHB8hiNWK1z2",
"userName": "marklee"
}
}
}
here's my User model
class User {
private var uid: String = "0"
private var userName: String = ""
private var email: String = ""
private var bio: String? = null
private var link: String? = null
private var profile_image: String = ""
private var background_image: String = ""
constructor()
constructor(uid : String, userName : String, email : String, bio : String, link : String, profile_image : String, background_image : String){
this.uid = uid
this.userName = userName
this.email = email
this.bio = bio
this.link = link
this.profile_image = profile_image
this.background_image = background_image
}
//function UID
fun getUID(): String{
return uid
}
fun setUID(uid: String){
this.uid = uid
}
//function User Name
fun getUserName(): String{
return userName
}
fun setUserName(userName: String){
this.userName = userName
}
//function Email
fun getEmail(): String{
return email
}
fun setEmail(email: String){
this.email = email
}
//function bio
fun getBio(): String?{
return bio
}
fun setBio(bio: String?){
this.bio = bio
}
//function link
fun getLink(): String?{
return link
}
fun setLink(link: String?){
this.link = link
}
//function Profile Image
fun getProfileImage(): String{
return profile_image
}
fun setProfileImage(profile_image: String){
this.profile_image = profile_image
}
//function Background Image
fun getBackgroundImage(): String{
return background_image
}
fun setBackgroundImage(background_image: String){
this.background_image = background_image
}
}
here's Post model
class Post {
private var postId: String = ""
private var title: String = ""
private var post_image: String = ""
private var description: String = ""
private var category: String = ""
private var priceRange: String = ""
private var duration: String = ""
private var paymentMethods: String = ""
private var publisher: String = ""
constructor()
constructor(
postId: String,
title: String,
post_image: String,
description: String,
category: String,
priceRange: String,
duration: String,
paymentMethods: String,
publisher: String
) {
this.postId = postId
this.title = title
this.post_image = post_image
this.description = description
this.category = category
this.priceRange = priceRange
this.duration = duration
this.paymentMethods = paymentMethods
this.publisher = publisher
}
//Get
fun getPostId(): String{
return postId
}
fun getTitle(): String{
return title
}
fun getPostImage(): String{
return post_image
}
fun getDescription(): String{
return description
}
fun getCategory(): String{
return category
}
fun getPriceRange(): String{
return priceRange
}
fun getDuration(): String{
return duration
}
fun getPaymentMethods(): String{
return paymentMethods
}
fun getPublisher(): String{
return publisher
}
//Set
fun setPostId(postId: String){
this.postId = postId
}
fun setTitle(title: String){
this.title = title
}
fun setPostImage(post_image: String){
this.post_image = post_image
}
fun setDescription(description: String){
this.description = description
}
fun setCategory(category: String){
this.category = category
}
fun setPriceRange(priceRange: String){
this.priceRange = priceRange
}
fun setDuration(duration: String){
this.duration = duration
}
fun setPaymentMethods(paymentMethods: String){
this.paymentMethods = paymentMethods
}
fun setPublisher(publisher: String){
this.publisher = publisher
}
}
here's my PostAdapter.kt
class PostAdapter(private val mContext: Context,
private val mPost: List<Post>) : RecyclerView.Adapter<PostAdapter.ViewHolder>()
{
private var firebaseUser: FirebaseUser? = null
inner class ViewHolder(#NonNull itemView: View) : RecyclerView.ViewHolder(itemView){
var profileImage: CircleImageView
var tvUsername: TextView
var likeButton: ImageButton
var tvTitle: TextView
var tvPrice: TextView
var tvDescription: TextView
var tvSeeMore: TextView
var postImage: ImageView
init {
profileImage = itemView.findViewById(R.id.cvProfile)
tvUsername = itemView.findViewById(R.id.tvCvUsername)
likeButton = itemView.findViewById(R.id.cvFav)
tvTitle = itemView.findViewById(R.id.tvCvTitle)
tvPrice = itemView.findViewById(R.id.tvCvPrice)
tvDescription = itemView.findViewById(R.id.tvCvDesc)
tvSeeMore = itemView.findViewById(R.id.tvCvSeeMore)
postImage = itemView.findViewById(R.id.ivPostImage)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(mContext).inflate(R.layout.item_timeline, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
firebaseUser = FirebaseAuth.getInstance().currentUser
val post = mPost[position]
Glide.with(mContext.applicationContext).load(post.getPostImage()).into(holder.postImage)
holder.tvTitle.text = post.getTitle()
holder.tvDescription.text = post.getDescription()
holder.tvPrice.text = post.getPriceRange()
publisherInfo(holder.profileImage, holder.tvUsername, post.getPublisher())
}
private fun publisherInfo(
profileImage: CircleImageView,
tvUsername: TextView,
publisher: String
) {
val usersRef = FirebaseDatabase.getInstance().reference.child("User").child(publisher)
usersRef.addValueEventListener(object : ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists())
{
val user = snapshot.getValue(User::class.java)
Glide.with(mContext.applicationContext).load(user!!.getProfileImage()).into(profileImage)
tvUsername.text = user!!.getUserName()
}
}
override fun onCancelled(error: DatabaseError) {
Toast.makeText(mContext, error.message, Toast.LENGTH_LONG).show()
}
})
}
override fun getItemCount(): Int {
return mPost.size
}
}
any help i would really appreciate. thanks
You are getting the following warning:
No setter/field for post_image found on class com.isjieman.ocion.model.Post
Because in the Post class, you have an incorrect getter for the post_image field. The getter is defined as:
fun getPostImage(): String{
return post_image
}
While it should be defined as:
fun getPost_image(): String{
return post_image
}
You're getting the following warnings:
No setter/field for background_image found on class com.isjieman.ocion.model.User
No setter/field for profile_image found on class com.isjieman.ocion.model.User
Due to the exact same reason as above. You have these getters:
fun getBackgroundImage(): String{
return background_image
}
fun getProfileImage(): String{
return profile_image
}
Which should have been defined as:
fun getBackground_image(): String{
return background_image
}
fun getProfile_image(): String{
return profile_image
}
Bear in mind that Firebase Realtime Database serializes/deserializes any public fields and public properties that follow JavaBean naming conventions for getters and setters. That's the reason why you got those warnings.
Related
Database Structure
I have the database structure shown in the image,
and I am using the following reference to retrieve the child values.
private fun readNotificationComments() {
val notifRef = FirebaseDatabase.getInstance().reference
.child("Notifications")
.child(FirebaseAuth.getInstance().currentUser!!.uid)
.child("Comments")
.child(/*unknown child*/)
notifRef.addValueEventListener(object : ValueEventListener{
override fun onDataChange(dataSnapshot: DataSnapshot) {
if(dataSnapshot.exists()){
(notificationList as ArrayList<Notification>).clear()
for(snapshot in dataSnapshot.children)
{
val notification = snapshot.getValue(Notification::class.java)
(notificationList as ArrayList<Notification>).add(notification!!)
}
Collections.reverse(notificationList);
notificationAdapter!!.notifyDataSetChanged()
refresh = true
swipe_refresh_comments.isRefreshing = false
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
Now my problem is that the value "-MYxVs5l5bmRA-rf9PSt" is unknown and created randomly, how to make changes so that it the function looks for data past that unknown child value?
This is the model class
class Notification
{
private var userid: String = ""
private var text: String = ""
private var postid: String = ""
private var ispost: Boolean = false
constructor()
constructor(userid: String, text: String, postid: String, ispost: Boolean) {
this.userid = userid
this.text = text
this.postid = postid
this.ispost = ispost
}
fun getUserId(): String
{
return userid
}
fun setUserId(userid: String)
{
this.userid = userid
}
fun getPostId(): String
{
return postid
}
fun setPostId()
{
this.postid = postid
}
fun getText(): String
{
return text
}
fun setText(text: String)
{
this.text = text
}
fun getIsPost(): Boolean
{
return ispost
}
fun setIsPost(ispost: Boolean)
{
this.ispost = ispost
}
}
I have a Firestore database holding my data. Here is the structure
(database structure)
subclass database structure
So my booking is sub-collections of the user. Each booking contains its own restaurant as a sub-document.
Here is the activity file:
private lateinit var binding: ActivityMyBookingsBinding
//recyclerview for list
lateinit var recyclerView: RecyclerView
//Firestore
private var currentUser: FirebaseUser = FirebaseAuth.getInstance().currentUser!!
private var db: FirebaseFirestore = FirebaseFirestore.getInstance()
var query: CollectionReference = db
.collection("Users")
.document(currentUser.uid)
.collection("Bookings")
//adapter
lateinit var bookingAdapter: BookingItemAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMyBookingsBinding.inflate(layoutInflater)
val view = binding.root
setupUI()
setContentView(view)
setupRecyclerView()
}
private fun setupUI() {
recyclerView = binding.bookingList
}
private fun setupRecyclerView(){
val options: FirestoreRecyclerOptions<BookingItem> = FirestoreRecyclerOptions.Builder<BookingItem>()
.setQuery(query, BookingItem::class.java)
.build()
bookingAdapter = BookingItemAdapter(this, options)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = bookingAdapter
}
override fun onStart() {
super.onStart()
bookingAdapter.startListening()
}
override fun onStop() {
super.onStop()
bookingAdapter.stopListening()
}
Here is the adapter file
class BookingItemAdapter(
val context: Context,
val options: FirestoreRecyclerOptions<BookingItem>): FirestoreRecyclerAdapter<BookingItem, BookingItemAdapter.BookingViewHolder>(options) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BookingViewHolder {
return BookingViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.card_booking,
parent,
false,
),
)
}
#RequiresApi(Build.VERSION_CODES.N)
override fun onBindViewHolder(holder: BookingViewHolder, position: Int, model: BookingItem) {
holder.restaurantNameText.booking_restaurant_name.text = model.getRestaurantItem().getName()
holder.restaurantDistanceText.booking_distance.text = model.getRestaurantItem().getGeoHash()
holder.restaurantRatingBar.booking_ratingBar.rating = model.getRestaurantItem().getRating()?.toFloat()!!
holder.bookingDate.booking_date.text = "${model.getDay()}/${model.getMonth()}/${model.getYear()}"
holder.bookingTime.booking_time.text = "${model.getHour()}:${model.getMinute()}"
holder.numberGuests.number_guests.text = model.getGuestNumber()
val url = model.getRestaurantItem().getRestaurantImage()
Glide
.with(holder.restaurantImageItem)
.load(url)
.into(holder.restaurantImageItem.booking_restaurantImage)
holder.itemView.setOnClickListener {
val intent = Intent(context, RestaurantPageActivity::class.java)
intent.putExtra("model", model.getRestaurantItem())
context.startActivity(intent)
}
CompletableFuture.runAsync {
runCatching {
val url = model.getRestaurantItem().getRestaurantImage()
Glide
.with(holder.restaurantImageItem)
.load(url)
.into(holder.restaurantImageItem.booking_restaurantImage)
}
}
}
inner class BookingViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val restaurantNameText: TextView = itemView.findViewById(R.id.booking_restaurant_name)
val restaurantImageItem: ImageView = itemView.findViewById(R.id.booking_restaurantImage)
val restaurantRatingBar: RatingBar = itemView.findViewById(R.id.booking_ratingBar)
val restaurantDistanceText: TextView = itemView.findViewById(R.id.booking_distance)
val bookingTime: TextView = itemView.findViewById(R.id.booking_time)
val bookingDate: TextView = itemView.findViewById(R.id.booking_date)
val numberGuests: TextView = itemView.findViewById(R.id.number_guests)
}
Here is the bookingItem class:
class BookingItem(restaurantItem: RestaurantItem, guestNumber: String, day: String,
month: String, year: String, hour: String, minute: String) {
constructor(): this(RestaurantItem("", "", 0, 0,
"", "", "", "", false), "", "", "", "", "","")
private var restaurantItemName = restaurantItem.getName()
private var restaurantItemImage = restaurantItem.getRestaurantImage()
private var restaurantItemPrice = restaurantItem.getPrice()
private var restaurantItemRating = restaurantItem.getRating()
private var restaurantItemGeohash = restaurantItem.getGeoHash()
private var restaurantItemLongitude = restaurantItem.getLongitude()
private var restaurantItemLatitude = restaurantItem.getLatitude()
private var restaurantItemCuisine = restaurantItem.getCuisine()
private var restaurantItemDietary = restaurantItem.getDietaryFriendly()
private var restaurantItem: RestaurantItem = RestaurantItem(
restaurantItemName,
restaurantItemImage,
restaurantItemPrice,
restaurantItemRating,
restaurantItemGeohash,
restaurantItemLongitude,
restaurantItemLatitude,
restaurantItemCuisine,
restaurantItemDietary)
private var guestNumber: String = guestNumber
private var day: String = day
private var month: String = month
private var year: String = year
private var hour: String = hour
private var minute: String = minute
fun getRestaurantItem(): RestaurantItem{
this.restaurantItem.getName()
this.restaurantItem.getRestaurantImage()
this.restaurantItem.getPrice()
this.restaurantItem.getRating()
this.restaurantItem.getGeoHash()
this.restaurantItem.getLongitude()
this.restaurantItem.getLatitude()
this.restaurantItem.getCuisine()
this.restaurantItem.getDietaryFriendly()
return this.restaurantItem
}
fun getGuestNumber(): String {
return this.guestNumber
}
fun getDay(): String{
return this.day
}
fun getMonth(): String{
return this.month
}
fun getYear(): String{
return this.year
}
fun getHour(): String{
return this.hour
}
fun getMinute(): String{
return this.minute
}
}
Finally incase you need it, here is the sub entity - restaurantItem class:
class RestaurantItem(name: String, restaurantImage: String, price: Long, rating: Long, geoHash: String ,
longitude: String, latitude: String, cuisine: String, dietaryFriendly: Boolean): Parcelable{
constructor(): this ("", "", 0, 0,
"", "", "", "", false
)
private var name: String = name
private var restaurantImage: String = restaurantImage
private var price: Long = price
private var rating: Long = rating
private var geoHash: String = geoHash
private var longitude: String = longitude
private var latitude: String = latitude
private var cuisine: String = cuisine
private var dietaryFriendly: Boolean = dietaryFriendly
private constructor(parcel: Parcel) : this() {
name = parcel.readString().toString()
restaurantImage = parcel.readString().toString()
price = parcel.readLong()
rating = parcel.readLong()
geoHash = parcel.readString().toString()
longitude = parcel.readString().toString()
latitude = parcel.readString().toString()
cuisine = parcel.readString().toString()
dietaryFriendly = parcel.readByte() != 0.toByte()
}
fun getName(): String {
return this.name
}
fun getLatitude(): String {
return this.latitude
}
fun getLongitude(): String {
return this.longitude
}
fun getGeoHash(): String {
return this.geoHash
}
fun getPrice(): Long {
return this.price
}
fun getDietaryFriendly(): Boolean{
return this.dietaryFriendly
}
fun getRating(): Long {
return this.rating
}
fun getRestaurantImage(): String {
return this.restaurantImage
}
fun getCuisine(): String {
return this.cuisine
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(name)
parcel.writeString(restaurantImage)
parcel.writeLong(price)
parcel.writeLong(rating)
parcel.writeString(geoHash)
parcel.writeString(longitude)
parcel.writeString(latitude)
parcel.writeString(cuisine)
parcel.writeByte(if (dietaryFriendly) 1 else 0)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<RestaurantItem> {
override fun createFromParcel(parcel: Parcel): RestaurantItem {
return RestaurantItem(parcel)
}
override fun newArray(size: Int): Array<RestaurantItem?> {
return arrayOfNulls(size)
}
}
Now the data is coming in from firebase fine and the time, date, and a number of guests are being displayed correctly.
The restaurant class works because it is used elsewhere and displays correctly in other recycler views.
The issue seems to be that when the booking item is instanciated, all the data in the restaurantItem gets set to its null values.
I walked through with the debugger and I can see the data has made it from firebase.
This is the data when I debug in the bookingitem constructor and step through
This is where the data is lost and reset to null values:
Here is the line that the data is lost
You can access the code here https://github.com/KotaCanchela/RestaurantBookingSystem
I appreciate any help that can be provided, I've tried to give as much detail here as possible.
When you are debugging your code, all the properties of the "restaurantItem" object in the debugger are holding the default values because there is no match between the object of the class and the object in Firestore.
Your "BookingItem" class holds the property called "restaurantItem", while in the database the object is called only "restaurant", which is not correct. Both names must match. You either change the name of the property in the database to be "restaurantItem" and not just "restaurant", or you should use the following annotations:
#get:PropertyName("restaurant")
#set:PropertyName("restaurant")
#PropertyName("restaurant")
In front of your restaurantItem property in your "BookingItem" class.
Edit:
According to your comment:
do you mean in the BookingItem constructor?
Yes. The minimum implementation for your class might be:
data class BookingItem(
#get:PropertyName("restaurant")
#set:PropertyName("restaurant")
#PropertyName("restaurant")
var restaurantItem: RestaurantItem? = null,
var guestNumber: String? = null,
var day: String? = null,
var month: String? = null,
var year: String? = null,
var hour: String? = null,
var minute: String? = null
)
Where I have initialized those objects with a null value. Once you get the data from the database, you'll assign the values to your actual fields.
I got a problem and I can't see an error in my code, maybe You'll help me. I've got an application in Android Studio that uses connection with Firebase. I add products to the database by a button and in the activity that holds RecycleViever, it lists that product there. The problem is that RecycleViewer shows nothing, even though that my button adds product to the Firebase. That RecycleViewer should list products from Firebase. I add product with It's structure:
data class Product(var name: String, var price: Double, var quantity: Long, var bought: Boolean) {
var id: String = ""
companion object {
fun fromContentValues(values: ContentValues?): Product {
values?.let{
return Product(
values.getAsString("name"),
values.getAsDouble("price"),
values.getAsLong("amount"),
values.getAsBoolean("bought"))
} ?: throw IllegalArgumentException()
}
}
#Exclude
fun toMap(): Map<String, Any?> {
return mapOf(
"id" to id,
"name" to name,
"price" to price,
"quantity" to quantity,
"bought" to bought
)
}
}
Product Repository:
class ProductRepository(private val dbRef: DatabaseReference) {
fun insert(product: Product) {
val key = dbRef.push().key
if (key == null) {
Log.w("error", "Couldn't get push key for posts")
return
}
product.id = key
val productValues = product.toMap()
val childUpdates = hashMapOf<String, Any>(
key to productValues
)
dbRef.updateChildren(childUpdates)
}
fun update(product: Product){
val productValues = product.toMap()
val childUpdates = hashMapOf<String, Any>(
product.id to productValues
)
dbRef.updateChildren(childUpdates)
}
fun delete(key: String){
dbRef.child(key).removeValue()
}
}
Product ViewModel:
class ProductViewModel(app: Application) : AndroidViewModel(app) {
private val repo: ProductRepository
val allProducts: MutableList<Product>
init {
allProducts = arrayListOf()
val database = FirebaseDatabase.getInstance()
val reference : DatabaseReference = database.getReference("database/products")
var name: String
var price: Double
var amount: Long
var bought: Boolean
reference.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
for (product in snapshot.children) {
name = product.child("name").value as String
price = product.child("price").value as Double
amount = product.child("amount").value as Long
bought = product.child("bought").value as Boolean
val newProduct = Product(name, price, amount, bought)
allProducts.add(newProduct)
}
}
override fun onCancelled(error: DatabaseError) {
Log.w("error", "loadPost:onCancelled", error.toException())
}
})
repo = ProductRepository(reference)
}
fun insert(product: Product) {
repo.insert(product)
}
fun update(product: Product) {
repo.update(product)
}
fun delete(product: Product) {
repo.delete(product.id)
}
}
My Adapter:
class ProductsAdapter(val productViewModel: ProductViewModel) : RecyclerView.Adapter<ProductsAdapter.ViewHolder>() {
private var products = mutableListOf<Product>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductsAdapter.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val view = ListElementBinding.inflate(inflater)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ProductsAdapter.ViewHolder, position: Int) {
val currentProduct = products[position]
holder.binding.rvTv1.text = currentProduct.name
holder.binding.rvTv2.text = currentProduct.price.toString()
holder.binding.rvTv3.text = currentProduct.amount.toString()
holder.binding.rvCb1.isChecked = currentProduct.bought
holder.binding.bted.setOnClickListener {
currentProduct.name = holder.binding.rvTv1.text.toString()
currentProduct.price = holder.binding.rvTv2.text.toString().toDouble()
currentProduct.amount = holder.binding.rvTv3.text.toString().toLong()
currentProduct.bought = holder.binding.rvCb1.isChecked
productViewModel.update(currentProduct)
}
holder.binding.btdel.setOnClickListener {
productViewModel.delete(currentProduct)
products.remove(currentProduct)
notifyDataSetChanged()
}
}
override fun getItemCount(): Int = products.size
inner class ViewHolder(val binding: ListElementBinding) : RecyclerView.ViewHolder(binding.root)
fun setProducts() {
this.products = productViewModel.allProducts
notifyDataSetChanged()
}
fun addProduct(product: Product) {
productViewModel.insert(product)
notifyDataSetChanged()
}
}
And finally activity that Lists it all:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityListBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.rv1.layoutManager = LinearLayoutManager(baseContext)
binding.rv1.addItemDecoration(DividerItemDecoration(baseContext, DividerItemDecoration.VERTICAL))
val productViewModel = ProductViewModel(this.application)
binding.rv1.adapter = ProductsAdapter(productViewModel)
(binding.rv1.adapter as ProductsAdapter).setProducts()
binding.bt5.setOnClickListener() {
val name = et1.text.toString()
val price = et3.text.toString().toDouble()
val amount = et2.text.toString().toLong()
val bought = false
val product = Product(name, price, amount, bought)
(binding.rv1.adapter as ProductsAdapter).addProduct(product)
et1.text.clear()
et2.text.clear()
et3.text.clear()
}
binding.rv1.adapter = ProductsAdapter(productViewModel)
}
}
I literally have no idea, why it's not showing anything. Maybe You can help me.
I tried to retrieve data from Firebase using the childeventlistener. I have seen all the methods available on stackoverflow to resolve the difficulty but nothing worked.Code is given below
ViewModel
class AccepyReqViewModel : ViewModel() {
companion object {
const val TAG = "AcceptViewModel"
}
private val _userdetail = MutableLiveData<User>()
val userdetail: LiveData<User>
get() = _userdetail
private val userid = FirebaseAuth.getInstance().currentUser?.uid
private val chatrequest = "CHATREQ"
private val db_chat = FirebaseDatabase.getInstance().getReference(chatrequest)
private val company_info = "User_Info"
private val db_company = FirebaseDatabase.getInstance().getReference(company_info)
private val reqchildeventlister = object : ChildEventListener {
override fun onCancelled(error: DatabaseError) {}
override fun onChildMoved(snapshot: DataSnapshot, p1: String?) {
}
override fun onChildChanged(snapshot: DataSnapshot, p1: String?) {
}
override fun onChildAdded(snapshot: DataSnapshot, p1: String?) {
val getid = snapshot.getValue(Request::class.java)
val id = getid!!.id
val requesttype = getid.requesttype
Log.d(TAG, "Second function to be called")
Log.d(TAG, "$requesttype request type")
id?.let { getDetails(it) }
Log.d(TAG, "$id ID passed")
}
override fun onChildRemoved(snapshot: DataSnapshot) {
}
}
fun getRequest() {
Log.d(TAG, "getRequest method called 1st fun")
db_chat.child(userid!!).addChildEventListener(reqchildeventlister)
}
fun getDetails(id: String) {
Log.d(TAG, "Second function called")
db_company.child(id).addChildEventListener(datachildeventlistener)
}
private val datachildeventlistener = object : ChildEventListener {
override fun onCancelled(error: DatabaseError) {
}
override fun onChildMoved(snapshot: DataSnapshot, p1: String?) {
}
override fun onChildChanged(snapshot: DataSnapshot, p1: String?) {
Log.d(TAG, "onChildChanged")
val data = snapshot.getValue(User::class.java)
data?.id = snapshot.key
_userdetail.value = data
}
override fun onChildAdded(snapshot: DataSnapshot, p1: String?) {
val data = snapshot.getValue(User::class.java)
data?.id = snapshot.key
_userdetail.value = data
}
override fun onChildRemoved(snapshot: DataSnapshot) {
}
}
}
The Model Class is as follows
import com.google.firebase.database.Exclude
data class User(
#get:Exclude
var id: String? = null,
var isAdmin: Boolean? = true,
var name: String? = null,
var position: String? = null,
var contact: String? = null,
var comname: String? = null,
var address: String? = null,
var email: String? = null,
var website: String? = null
) {
constructor() : this("", true, "", "", "", "", "", "", "")
}
Firebase Realtime Database looks as follows
CHATREQ
8EFvXhAKTfWuIavGhXlz344bgMD2
c2HUyNV6sYQImIFqVNMfIaFDTKT2
id: "c2HUyNV6sYQImIFqVNMfIaFDTKT2"
request_type: "sent"
c2HUyNV6sYQImIFqVNMfIaFDTKT2
8EFvXhAKTfWuIavGhXlz344bgMD2
id: "8EFvXhAKTfWuIavGhXlz344bgMD2"
request_type: "received"
Company_Info
-M6Ez9RiFRpm8_cn35Pp
User_Info
8EFvXhAKTfWuIavGhXlz344bgMD2
admin: false
contact: "484615674"
name: "Chetan"
position: "c"
c2HUyNV6sYQImIFqVNMfIaFDTKT2
address: "add"
admin: true
comname: "Palekar"
contact: "549874561"
email: "add#gmail.com"
name: "Kp"
position: "adfa"
website: "www.add.com"
The stacktrace said that "cant convert object of string to the user Model class"
Hope Someone help me out with this .
Thank-You for your help.
Instead of using childEventListener, you need to use valueEventListener:
private val company_info = "User_Info"
private val db_company = FirebaseDatabase.getInstance().getReference(company_info)
private val reqEventlister = object : ValueEventListener {
override fun onCancelled(error: FirebaseError?) {
println(error!!.message)
}
override fun onDataChange(snapshot: DataSnapshot?) {
val getid = snapshot.getValue(Request::class.java)
val id = getid!!.id
val requesttype = getid.requesttype
Log.d(TAG, "Second function to be called")
Log.d(TAG, "$requesttype request type")
id?.let { getDetails(it) }
Log.d(TAG, "$id ID passed")
}
})
fun getRequest() {
Log.d(TAG, "getRequest method called 1st fun")
db_chat.child(userid!!).addValueEventListener(reqEventlister)
}
When using childEventListener, you are directly retrieving the children under the 8EFvXhAKTfWuIavGhXlz344bgMD2 thus retrieving values of type String. Instead you need to use ValueEventListener which will map your Request class to the data retrieved.
This is my class DatabaseHelper:
object DatabaseHelper : OrmLiteSqliteOpenHelper(App.instance, "test.db", null, 1) {
override fun onCreate(database: SQLiteDatabase?, connectionSource: ConnectionSource?) {
TableUtils.createTableIfNotExists(connectionSource, Table::class.java)
TableUtils.createTableIfNotExists(connectionSource, M_User::class.java)
TableUtils.createTableIfNotExists(connectionSource, M_Data::class.java)
}
override fun onUpgrade(database: SQLiteDatabase?, connectionSource: ConnectionSource?, oldVersion: Int, newVersion: Int) {
TableUtils.dropTable<Table, Any>(connectionSource, Table::class.java, true)
TableUtils.dropTable<M_User, Any>(connectionSource, M_User::class.java, true)
TableUtils.dropTable<M_Data, Any>(connectionSource, M_Data::class.java, true)
onCreate(database, connectionSource)
}
}
This is my class Table:
#DatabaseTable(tableName = "table")
data class Table(
#DatabaseField(generatedId = true)
var id: Int? = null,
#DatabaseField
var category: String = "",
#DatabaseField
var content: String = ""
)
class TableDao {
companion object {
lateinit var dao: Dao<Table, Int>
}
init {
dao = DatabaseHelper.getDao(Table::class.java)
}
fun add(table: Table) = dao.createOrUpdate(table)
fun update(table: Table) = dao.update(table)
fun delete(table: Table) = dao.delete(table)
fun queryForAll() = dao.queryForAll()
fun removeAll() {
for (table in queryForAll()) {
dao.delete(table)
}
}
}
This is my class M_User:
#DatabaseTable(tableName = "m_user")
data class M_User(
#DatabaseField(generatedId = true)
var id: Int? = null,
#DatabaseField
var username: String = "",
#DatabaseField
var password: String = ""
)
class M_UserDao
{
companion object {
lateinit var dao: Dao<M_User, Int>
}
init {
dao = DatabaseHelper.getDao(M_User::class.java)
}
fun add(table: M_User) = dao.createOrUpdate(table)
fun update(table: M_User) = dao.update(table)
fun delete(table: M_User) = dao.delete(table)
fun queryForAll() = dao.queryForAll()
fun removeAll() {
for (table in queryForAll()) {
dao.delete(table)
}
}
}
This is my class M_Data:
#DatabaseTable(tableName = "m_data")
data class M_Data(
#DatabaseField(generatedId = true)
var id: Int? = null,
#DatabaseField
var username: String,
#DatabaseField
var insert_date: String = ""
)
class M_DataDao
{
companion object {
lateinit var dao: Dao<M_Data, Int>
}
init {
dao = DatabaseHelper.getDao(M_Data::class.java)
}
fun add(table: M_Data) = dao.createOrUpdate(table)
fun update(table: M_Data) = dao.update(table)
fun delete(table: M_Data) = dao.delete(table)
fun queryForAll() = dao.queryForAll()
fun removeAll() {
for (table in queryForAll()) {
dao.delete(table)
}
}
fun getListUserAddData(username:String):List<Array<String>>
{
val sql="select b.username,b.insert_date from M_User a join M_Data b on a.username=b.username where a.username ='"+username +"'"
val rawResults = dao.queryRaw(sql)
val results = rawResults.getResults()
return results
}
}
This my code add data to 3 tables:
btnAdd.setOnClickListener(View.OnClickListener {
try {
val dao = TableDao()
dao.add(Table(null, "1", "a1"))
val usr= M_UserDao()
usr.add(M_User(null,txtUserName.text.toString(),txtPassword.text.toString()))
val data= M_DataDao()
data.add(M_Data(null, txtUserName.text.toString(), Utilities.dateTimeNow))
} catch (e: Exception) {
print(e.message)
}
})
But it occur Exception:
Can't find a no-arg constructor for class com.example.son.kotlinandroiddemo.db.dao.M_Data
Your var username: String is not initialised, therefore compiler can't create a default constructor for your class, which seems to be the requirement for the library you are using.