I'm getting this error when trying to get a child node trainer_profile from Firebase that contains a list my_pokemon.
W/ClassMapper: No setter/field for my_pokemon found on class com.tapmaxalf.poketest.model.TrainerProfile
My Firebase DB:
My valueEventListener looks like this:
private fun getTrainerProfile(userId: String) {
firebaseDatabase.child("trainer_profile").child(userId)
.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
snapshot.getValue(TrainerProfile::class.java).let { trainerProfile ->
if (trainerProfile != null) {
viewModelScope.launch (Dispatchers.IO){
_state.value = state.value.copy(trainerProfile = trainerProfile)
userDao.updateTrainerProfile(trainerProfile, userId)
canProfileBeAdded(trainerProfile.timeSentToDatabase)
addProfileCountdown(trainerProfile.timeSentToDatabase)
}
}
}
}
override fun onCancelled(error: DatabaseError) {
updateError(AuthErrors.GenericError.messageResource)
}
})
}
And my TrainerProfile
data class TrainerProfile(
val trainerName: String = "",
val location: String = "",
val trainerLevel: String = "",
val trainerCode: String = "",
val profileImage: String = "",
val gifts: Boolean = false,
val trade: Boolean = false,
val raid: Boolean = false,
val timeSentToDatabase: Long = 0,
val myPokemon: List<MyPokemon> = emptyList()
)
You are getting the following warning:
W/ClassMapper: No setter/field for my_pokemon found on class com.tapmaxalf.poketest.model.TrainerProfile
Because the list in your database is called my_pokemon, while in the database is called myPokemon, which is not correct. Both names must match. The simplest solution to this problem would be to use an annotations before your field like this:
#get:PropertyName("my_pokemon")
#set:PropertyName("my_pokemon")
#PropertyName("my_pokemon")
val myPokemon: List<MyPokemon> = emptyList()
Related
i tried to split a string to two variable, one is string and one is Long. it work, when i Log it i can see it and i can insert it to Room Database, but i don't know why "sometime" i get this error.
the string like this
m8fw5sMdAcaX4Ezv7vzImeRAjkq2_1635234951781
java.lang.NumberFormatException: For input string: "m8fw5sMdAcaX4Ezv7vzImeRAjkq2"
at java.lang.Long.parseLong(Long.java:594)
at java.lang.Long.parseLong(Long.java:636)
at com.animals.snowy.MainActivity$insertMessage$1$messageListener$1.onChildAdded(MainActivity.kt:88)
my Model
#IgnoreExtraProperties
#Entity(tableName = "message_table")
data class MessageModel(
#NonNull
#PrimaryKey
var messageId: String = "",
var messageType: String? = null,
var messageTimestamp: Long? = null,
var messageData: String? = null,
var messageSenderId: String? = null,
var roomId: String = "",
var isSeen: Boolean = false,
var uploadSuccess : Boolean = false
) : Serializable {
}
and this is my code , i want to get new message of friends, so i get list friend from Room Database and use for loop to get roomId(name of child container message of me and my friend).
private fun insertMessage() {
viewModel.readRoomIdFriendsDAO().observe(this, { listRoomId ->
if (listRoomId != null && listRoomId.isNotEmpty()) {
for (item in listRoomId) {
val messageListener = object : ChildEventListener {
override fun onChildAdded(snapshot:DataSnapshot,previousChildName: String?) {
val messageModel: MessageModel? =
snapshot.getValue(MessageModel::class.java)
if (messageModel != null) {
messageModel.messageId = snapshot.key.toString().trim()
messageModel.roomId = item
messageModel.uploadSuccess = true
val listTemp = messageModel.messageId.split("_")
messageModel.messageSenderId = listTemp[0]
messageModel.messageTimestamp = listTemp[1].trim().toLong()
Log.e(TAG,"senderId: ${messageModel.messageSenderId}")
Log.e(TAG,"timestamp: ${messageModel.messageTimestamp}")
// messageViewModel.insertMessageDAO(messageModel)
}
}
override fun onChildChanged(
snapshot: DataSnapshot,
previousChildName: String?
) {
}
override fun onChildRemoved(snapshot: DataSnapshot) {
}
override fun onChildMoved(
snapshot: DataSnapshot,
previousChildName: String?
) {
TODO("Not yet implemented")
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
}
messageRef
.child(item)
.addChildEventListener(messageListener)
}
}
})
}
java.lang.NumberFormatException is thrown whenever the compiler tries to type cast an invalid input to number.
For example:
String validInputToCast = "123456789";
Long validInputToCast = validInputToCast.toLong(); // this casting will succeed.
String invalidInputToCast = "abce124";
Long invalidCastedInput = inputToCast.toLong(); // compiler will throw number exception on this line.
Try debugging the line below and hopefully you will find the error.
messageModel.messageTimestamp = listTemp[1].trim().toLong()
I am trying to observe Item data changes in a List using LiveData. But for some reason it is not working as expected.
ViewModel
#HiltViewModel
class TestScreenViewModel #Inject constructor(private val repository: TestRepository) :
ViewModel() {
val _orderItems: LiveData<List<OrderItem>> = repository.getAllTestOrder().asLiveData()
val orderItems: LiveData<List<OrderItem>> = _orderItems
fun addOrderItem() {
val item = OrderItem(name = "Order 1", price = 50, qty = 2)
viewModelScope.launch {
repository.addOrder(item)
}
}
fun deleteAll() = viewModelScope.launch { repository.deleteAll() }
fun changeValueOfItem() {
_orderItems.value!![0].addQty()
}
}
OrderItem
#Entity(tableName = "orders")
data class OrderItem constructor(
#PrimaryKey(autoGenerate = true)
#NonNull
val id: Int=0,
var name: String = "",
var price: Int = 0,
var imageUrl: String = "",
var qty: Int = 0
) {
fun addQty() {
qty++
}
fun removeQty() {
qty--
}
fun updateQty(q: Int) {
qty = q
}
}
During fun changeValueOfItem() call I just updated the qty by 1.
I already have a observable for orderItems in my Fragment but the changes are not detected.
What I am doing wrong here? Or Is there any other way to implement this scenario?
Faced similar behavior some time ago.
For it to work properly you need to actually return LiveData from your database like this:
//your DAO
#Query(select * from smth)
fun getAllTestOrder(): LiveData<List<OrderItems>>
And also remove .asLiveData() in your ViewModel and instead do something like this
val _orderItems = repository.getAllTestOrder()
val orderItems: LiveData<List<OrderItem>> = _orderItems
I have two tables in my Room DB - Events and Notes. For each event I have displayed in the RecycleView - I have a link to launch a note for that event. On first click - Note is created. On the second time the note is clicked, I would like to retrieve the previous note and then edit. Also, I am using the same activity to already edit/create new notes by passing on appropriate values, which works but uses parcelized note.
For editing an existing event Note - I am sending across the event ID (which is also stored in the Note table - not as a Foreign key) using the putExtra method. DB structure below (assocId refers to eventId)
ViewModel
fun setNotesByAssocEventId(assocEventId: String): Note {
return dao.getByAssocEventId(assocEventId)
}
DAO
#Query("SELECT * FROM notes WHERE assocEventId = :assocEventId")
fun getByAssocEventId(assocEventId: String): Note
NoteEntity
#Entity(tableName = "notes")
#Parcelize
data class Note(
//PrimaryKey annotation to declare primary key with auto increment value
//ColumnInfo annotation to specify the column's name
#PrimaryKey(autoGenerate = true) #ColumnInfo(name = "id") var id: Int = 0,
#ColumnInfo(name = "assocEventId") var assocEventId: String = "",
#ColumnInfo(name = "title") var title: String = "",
#ColumnInfo(name = "label") var label: String = "",
#ColumnInfo(name = "date") var date: String = "",
#ColumnInfo(name = "time") var time: String = "",
#ColumnInfo(name = "updatedDate") var updatedDate: String = "",
#ColumnInfo(name = "updatedTime") var updatedTime: String = "",
#ColumnInfo(name = "body") var body: String = ""
) : Parcelable
I am using the below code to edit/create new notes. While I am able to create/Edit notes. I am unable to retrieve a node for a particular event using the eventId. One of the errors I am getting is Note object has not been initialized when I am assigning the note object returned from the ViewModel. What could be the issue?
assocID is the event ID obtained using putExtra and the corresponding event note is to be retrieved...
private lateinit var binding: ActivityEditNoteBinding
private lateinit var notesViewModel: NotesViewModel
private lateinit var note: Note
private var assocId: String? = ""
private var isUpdate = false
private val dateChange = DateChange()
var refUsers: DatabaseReference? = null
var firebaseUser: FirebaseUser? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityEditNoteBinding.inflate(layoutInflater)
setContentView(binding.root)
assocId = intent.getStringExtra("eventId").toString()
initView()
initListener()
}
private fun initView() {
firebaseUser = FirebaseAuth.getInstance().currentUser
initViewModel()
if (assocId != null) {
findViewById<TextView>(R.id.editNote).text = "Edit Event Note"
Toast.makeText(this, "EvetnId received", Toast.LENGTH_SHORT).show()
isUpdate = true
binding.editNoteDelete.visibility = View.VISIBLE
notesViewModel.getNotes()
note = notesViewModel.setNotesByAssocEventId("%${assocId}%")
binding.editTextTitle.setText(note.title)
binding.editTextBody.setText(note.body)
binding.editTextTitle.setSelection(note.title.length)
//set spinner position
val compareValue = note.label
val adapter = ArrayAdapter.createFromResource(
this, R.array.NoteSpinnerVals,
android.R.layout.simple_spinner_item
)
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
binding.spLabel.adapter = adapter
val spinnerPosition = adapter.getPosition(compareValue)
binding.spLabel.setSelection(spinnerPosition)
}
}
private fun initViewModel() {
notesViewModel = ViewModelProvider(this).get(NotesViewModel::class.java)
}
private fun initListener() {
// binding.editNoteBack.setOnClickListener(this)
binding.editNoteSave.setOnClickListener(this)
binding.editNoteDelete.setOnClickListener(this)
}
private fun deleteNote(note: Note) {
notesViewModel.deleteNote(note)
Toast.makeText(this#EditNote, "Note removed", Toast.LENGTH_SHORT).show()
}
private fun showDialog() {
AwesomeDialog.build(this)
.position(AwesomeDialog.POSITIONS.CENTER)
.title("Delete the note?")
.icon(R.drawable.ic_delete_black)
.background(R.drawable.background_dialog)
.onPositive(
"Yes, delete",
buttonBackgroundColor = R.drawable.button_bg,
textColor = ContextCompat.getColor(this, R.color.white)
) {
deleteNote(note)
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
finish()
}
.onNegative(
"Cancel",
buttonBackgroundColor = R.drawable.button_bg,
textColor = ContextCompat.getColor(this, R.color.white)
) {
}
}
Code of the ViewModel
class NotesViewModel(application: Application) : AndroidViewModel(application) {
private val context = getApplication<Application>().applicationContext
private val listNotes = MutableLiveData<ArrayList<Note>>()
private var dao: NoteDao
init {
val database = AppDatabase.getDatabase(context)
dao = database.getNoteDao()
}
fun setNotes() {
val listItems = arrayListOf<Note>()
listItems.addAll(dao.getAll())
listNotes.postValue(listItems)
}
fun setNotesByType(label: String) {
val listItems = arrayListOf<Note>()
listItems.addAll(dao.getByLabel(label))
listNotes.postValue(listItems)
}
fun setNotesByTitle(title: String) {
val listItems = arrayListOf<Note>()
listItems.addAll(dao.getByTitle(title))
listNotes.postValue(listItems)
}
fun setNotesByAssocEventId(assocEventId: String): Note {
return dao.getByAssocEventId(assocEventId)
}
fun insertNote(note: Note) {
dao.insert(note)
}
fun updateNote(note: Note) {
dao.update(note)
}
fun deleteNote(note: Note) {
dao.delete(note)
}
fun getNotes(): LiveData<ArrayList<Note>> {
return listNotes
}
}
The method in the DAO need to be changed a little
#Query("SELECT * FROM notes WHERE assocEventId = :assocEventId")
fun getByAssocEventId(assocEventId: String): Note
should be
#Query("SELECT * FROM notes WHERE assocEventId LIKE :assocEventId")
fun getByAssocEventId(assocEventId: String): LiveData<List<Note>>
In order to support wild character search, "%${assocId}%", LIKE keyword.
To get one Note only
#Query("SELECT * FROM notes WHERE assocEventId LIKE :assocEventId LIMIT 1")
fun getByAssocEventId(assocEventId: String): LiveData<Note>
in view model
fun setNotesByAssocEventId(assocEventId: String): LiveData<Note>{
return dao.getByAssocEventId(assocEventId)
}
in the activity
notesViewModel.setNotesByAssocEventId("%${assocId}%").observe(this, {
if(it!=null){
//if you using for single note only
}
//if(it.isNotEmpty()){
//if you using for list
//}
})
I am trying to display the current username from the Realtime Database but whenever I am running my code it gives me null. Here is my code:
val reference =FirebaseDatabase.getInstance().reference
currentUserUid = auth?.currentUser?.uid
reference.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
val username =
dataSnapshot.child(auth!!.currentUser!!.uid).child("Users")
.child("username")
.getValue(String::class.java)
if (username == null)
fragmentView?.name?.setText("Hello, Anonymous")
else
fragmentView?.name?.setText("Hello, $username")
}
override fun onCancelled(databaseError: DatabaseError) {}
})
This is my content to code
package com.example.videoapp.Model
data class ContentDTO(var explain : String? = null,
var imageUrl : String? = null,
var uid : String? = null,
var userId : String? = null,
var username : String? = null,
var timestamp : Long? = null,
var favoriteCount : Int = 0,
var favorites : MutableMap<String,Boolean> = HashMap()){
data class Comment(var uid : String? = null,
var userId : String? = null,
var comment : String? = null,
var timestamp : Long? = null)
}
This is my code where I can upload the pics. I have taken a little bit of help from the internet to do that. I am trying to display the name here but it's returning nothing
val storageRef = storage?.reference?.child("images")?.child(imageFileName)
storageRef?.putFile(photoUri!!)?.continueWithTask { task: com.google.android.gms.tasks.Task<com.google.firebase.storage.UploadTask.TaskSnapshot> ->
return#continueWithTask storageRef.downloadUrl
}?.addOnSuccessListener { uri ->
val contentDTO = com.example.videoapp.Model.ContentDTO()
//Insert downloadUrl of image
contentDTO.imageUrl = uri.toString()
//Insert uid of user
contentDTO.uid = auth?.currentUser?.uid
//Insert userId
contentDTO.userId = auth?.currentUser?.email
contentDTO.username = auth?.currentUser?.displayName
//Insert explain of content
contentDTO.explain = addphoto_edit_explain2.text.toString()
//Insert timestamp
contentDTO.timestamp = System.currentTimeMillis()
firestore?.collection("images")?.document()?.set(contentDTO)
setResult(android.app.Activity.RESULT_OK)
finish()
}
As I see in your database, the key of all User objects that are stored within Users node, are not added using the UID that comes from the authentication process, those key as generated with the push() method, because all of them start with -.
The most appropriate solution might be to change those keys and get then the data accordingly. To add a User object, you should some lines of code that looks like this:
val uid = FirebaseAuth.getInstance().currentUser!!.uid
val rootRef = FirebaseDatabase.getInstance().reference
val usersRef = rootRef.child("Users")
usersRef.child(uid).setValue(user)
To display the name of the logged-in users, simply use the following lines of code:
val valueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
val name = dataSnapshot.child("name").getValue(String::class.java)
Log.d("TAG", name)
//Do what you need to do with the value of name
}
override fun onCancelled(databaseError: DatabaseError) {
Log.d("TAG", databaseError.getMessage()) //Don't ignore errors!
}
}
usersRef.child(uid).addListenerForSingleValueEvent(valueEventListener)
Try this code instead :
val reference = FirebaseDatabase.getInstance().getReference("Users").child(auth?.currentUser?.uid)
reference.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for(snapshot in dataSnapShot.children){
val username =
snapshot.child("username").value.toString()
if (username == null)
fragmentView?.name?.setText("Hello, Anonymous")
else
fragmentView?.name?.setText("Hello, $username")
}
}
override fun onCancelled(databaseError: DatabaseError) {}
})
I am new to kotlin. And so I need help. Thank. I have a date class Users ().
data class Users(
var ID: String = "",
var Email: String = "")
Date class I fill through initUser
lateinit var AUTH: FirebaseAuth
lateinit var UID:String
lateinit var REF_DATABASE_ROOT: DatabaseReference
lateinit var USER:Users
const val NODE_USERS = "User"
const val CHILD_ID = "ID"
const val CHILD_EMAIL = "Email"
fun initFirebase() {
AUTH = FirebaseAuth.getInstance()
REF_DATABASE_ROOT = FirebaseDatabase.getInstance().reference
UID = AUTH.currentUser?.uid.toString()
USER = Users()
}
fun initUser() {
REF_DATABASE_ROOT.child(NODE_USERS).child(UID)
.addValueEventListener(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {}
override fun onDataChange(p0: DataSnapshot) {
USER = p0.getValue(Users::class.java) ?:Users()
}
})
}
But when I want to display the user's email from the database via text. I get the void
initFirebase()
initUser()
textViewMain.text = USER.Email.toString()
Here is new JSON:
{
"User" : {
"ZDLM84F7zYWobbhUBxsQfekrPvI3" : {
"Email" : "evgeniy1900#gmail.com",
"ID" : "ZDLM84F7zYWobbhUBxsQfekrPvI3"
}
}
}
But again I get nothing in text
UPDATE:
Ok, I wrote it all over again. And now I have:
Data class User
import com.google.firebase.database.PropertyName
data class User (
#PropertyName("id")
var id: String = "",
#PropertyName("email")
var email: String = ""
)
initUser looks like that
lateinit var AUTH: FirebaseAuth
lateinit var UID:String
lateinit var REF_DATABASE_ROOT: DatabaseReference
lateinit var USER:User
const val NODE_USERS = "users"
const val CHILD_ID = "id"
const val CHILD_EMAIL = "email"
fun initFirebase() {
AUTH = FirebaseAuth.getInstance()
REF_DATABASE_ROOT = FirebaseDatabase.getInstance().reference
UID = AUTH.currentUser?.uid.toString()
USER = User()
}
fun initUser() {
REF_DATABASE_ROOT.child(NODE_USERS).child(UID)
.addListenerForSingleValueEvent(AppValueEventListener{
USER = it.getValue(User::class.java) ?:User()
})
}
and also I decided to shorten the code using AppValueEventListener
here he is
class AppValueEventListener (val onSuccess:(DataSnapshot) -> Unit) :ValueEventListener{
override fun onCancelled(p0: DatabaseError) {}
override fun onDataChange(p0: DataSnapshot) { onSuccess(p0) }
}
and this is json
{
"users" : {
"ZDLM84F7zYWobbhUBxsQfekrPvI3" : {
"email" : "evgeniy1900#gmail.com",
"id" : "ZDLM84F7zYWobbhUBxsQfekrPvI3"
}
}
}
As you can see, I added #PropertyName ("email"). But at the same time, I still do not get anything on the screen.
enter image description here
Update again:
I used a breakpoint in order to understand if I am getting something from the database or not. As you can see in the screenshots, there is a receipt, but there is no record in the User model. Help me please.
Your JSON contains this property for a user:
"EMAIL" : "evgeniy1900#gmail.com",
Which you likely want to map to this in your code:
var Email: String = ""
But Firebase uses JavaBean naming conventions when mapping, which means that your JSON actually maps to a property in Kotlin as:
var eMAIL: String = ""
If you want to maintain both the name on JSON and in Kotlin, you can use a PropertyName annotation:
#PropertyName("EMAIL")
var Email: String = ""
Also see: Firebase #PropertyName doesn't work and probably others from this search.