my connecter:
interface SettingsVMRepConnector {
fun getUserEmail(email: String)
}
in my viewmodel:
class MyViewModel: ViewModel(), SettingsVMRepConnector
{
private val repository= SettingsRepository(this)
private var inputUserEmail= MutableLiveData<String?>()
fun getInputUserEmail(): LiveData<String?> {return inputUserEmail}
...
init{
repository.findUserEmail()
}
override fun getUserEmail(email:String) {
inputUserEmail.value = email
println(inputUserEmail.value.toString()+"...")
}
}
in my fragment:
val email : String = viewModel.getInputUserEmail().value.toString()
println("here: "+email)
emailInput.setText(email)
and in repository:
class SettingsRepository(val connector: SettingsVMRepConnector){
private val userID= Hawk.get<String>(Constants.LOGGEDIN_USERID)
private val usersRef: DatabaseReference = FirebaseDatabase.getInstance().getReference().child("Users")
fun findUserEmail(){
usersRef.child(userID).addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
var email = snapshot.child(Constants.R_USEREMAIL).value.toString()
connector.getUserEmail(email)
return
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
}
output is:
here: null
james#gmail.com...
I want to see this email in fragment. Why is returns null? And how can I see this e mail in my fragment?
Related
EDIT
i changed my code and got a result but it breaks the data into separate values. it reads all the data from the database for each child. i have 2 childs but it only retrieves the last childs data and display its values separately. it stores its value from the variable eta_text
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
clear_all = view.findViewById(R.id.clear_all)
notificationView = view.findViewById(R.id.notificationList)
notificationArray = arrayListOf()
getNotifData()
var linearLayoutManager = LinearLayoutManager(context)
notificationView.layoutManager = linearLayoutManager
notificationView.setHasFixedSize(true)
}
private fun getNotifData() {
val user = FirebaseAuth.getInstance().currentUser
val useremail = user!!.email
dbref = FirebaseDatabase.getInstance().reference
dbref.child("Students").orderByChild("email").equalTo(useremail.toString()).addValueEventListener(object : ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
for (ds in snapshot.children) {
val idNumber: String? = ds.key
dbref.child("Notification").child(idNumber.toString()).addValueEventListener(object : ValueEventListener{
override fun onDataChange(dsnapshot: DataSnapshot) {
for (dsd in dsnapshot.children) {
val key: String? = dsd.key
dbref.child("Notification").child(idNumber.toString()).child(key.toString()).addValueEventListener(object : ValueEventListener{
override fun onDataChange(dsnap: DataSnapshot) {
notificationArray.clear()
if (dsnap.exists()){
for (queueSnapshot in dsnap.children){
notificationArray.add(Notification(queueSnapshot.value.toString()))
}
notifadapter = MyAdapter_Notification(notificationArray)
notificationView.adapter = notifadapter
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
My data class
package com.example.sqms
data class Notification(var eta_text : String ?= null,
var office_name : String ?= null,
var time_text : String ?= null)
My Adapter
class MyAdapter_Notification (private val notificationList : ArrayList<Notification>)
: RecyclerView.Adapter<MyAdapter_Notification.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val notificationView = LayoutInflater.from(parent.context).inflate(R.layout.notification_view,parent,false)
return MyViewHolder(notificationView)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = notificationList[position]
holder.eta_text.text = currentItem.eta_text
holder.office_name.text = currentItem.office_name
holder.time_text.text = currentItem.time_text
}
override fun getItemCount(): Int {
return notificationList.size
}
inner class MyViewHolder(notificationView : View) : RecyclerView.ViewHolder(notificationView){
val eta_text : TextView = itemView.findViewById(R.id.eta_text)
val office_name : TextView = itemView.findViewById(R.id.office_name)
val time_text : TextView = itemView.findViewById(R.id.time_text)
}
}
picture below is the values from database
database
picture below is the data that is displayed separately
notification recycler view
i just solved it. i just removed the 3rd nested databasereference and changed the data writing
private fun getNotifData() {
val user = FirebaseAuth.getInstance().currentUser
val useremail = user!!.email
dbref = FirebaseDatabase.getInstance().reference
dbref.child("Students").orderByChild("email").equalTo(useremail.toString()).addValueEventListener(object : ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
for (ds in snapshot.children) {
val idNumber: String? = ds.key
dbref.child("Notification").child(idNumber.toString()).addValueEventListener(object : ValueEventListener{
override fun onDataChange(dsnapshot: DataSnapshot) {
notificationArray.clear()
if (dsnapshot.exists()){
for (queueSnapshot in dsnapshot.children){
val notif = queueSnapshot.getValue(Notification::class.java)
if (notif != null) {
notificationArray.add(notif)
}
}
notifadapter = MyAdapter_Notification(notificationArray)
notificationView.adapter = notifadapter
}
if (notifadapter.itemCount==0) {
notificationView.visibility = View.GONE;
new_notif.visibility = View.VISIBLE;
}
else {
notificationView.visibility = View.VISIBLE;
new_notif.visibility = View.GONE;
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
This question already has answers here:
getContactsFromFirebase() method return an empty list
(1 answer)
Setting Singleton property value in Firebase Listener
(3 answers)
Why does my function that calls an API or launches a coroutine return an empty or null value?
(4 answers)
Closed 1 year ago.
I receive null snapshot in only this two method
private fun getUserName() {
databaseReference=FirebaseDatabase.getInstance("https://tailoring-e7e0c-default-rtdb.asia-southeast1.firebasedatabase.app/").getReference("Users")
databaseReference.child(uAuth.currentUser?.uid.toString()).addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
var userList :User
userList = snapshot.getValue(User::class.java)!!
userName=userList?.cid.toString()
Toast.makeText(this#ProductDetail,"Username detected",Toast.LENGTH_LONG).show()
}
override fun onCancelled(error: DatabaseError) {
}
})
}
private fun getProductPic(prodImageURL:String) {
storageReference= FirebaseStorage.getInstance().reference.child(prodImageURL)
val localFile = File.createTempFile("tempImage","jpg")
storageReference.getFile(localFile).addOnSuccessListener {
val bitMap= BitmapFactory.decodeFile(localFile.absolutePath)
viewBinding.picViewProd.setImageBitmap(bitMap)
}
}
class ProductDetail : AppCompatActivity() {
private lateinit var databaseReference: DatabaseReference
private lateinit var uAuth:FirebaseAuth
private lateinit var storageReference: StorageReference
private lateinit var viewBinding:ActivityProductDetailBinding
private lateinit var adapter:commentAdapter
private lateinit var tc:String
private lateinit var commentList:ArrayList<commentContain>
private lateinit var thisProductID:String
private lateinit var dateTage :String
private var userName :String=""
private var tailorUID :String=""
private var tailorName :String=""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewBinding = ActivityProductDetailBinding.inflate(layoutInflater)
val view = viewBinding.root
setContentView(view)
tc=getIntent().getStringExtra("tc").toString()
thisProductID = getIntent().getStringExtra("prodNo").toString()
uAuth = FirebaseAuth.getInstance()
//Comment adapter and recycler view code
commentList= ArrayList()
getTailorName()
getComment()
adapter= commentAdapter(this,commentList)
viewBinding.commentList.layoutManager=LinearLayoutManager(this)
viewBinding.commentList.adapter=adapter
getTimeTag()
val currentUser = uAuth.currentUser?.uid
val currentUserURL = "Users/$currentUser.jpg"
getProductData()
if(tc=="tailor"){
viewBinding.btnOrderProduct.isVisible=false
}
viewBinding.btnOrderProduct.setOnClickListener {
addOrder()
}
viewBinding.picViewTailor.setOnClickListener {
val intent = Intent(this, TailorProfile::class.java)
intent.putExtra("tc",tc)
intent.putExtra("tuid",tailorUID)
startActivity(intent)
}
viewBinding.sendButton.setOnClickListener{
getUserName()
val comment = viewBinding.messageBox.text.toString()
addComment(thisProductID,userName,comment,dateTage,currentUserURL)
}
}
private fun getUserName() {
databaseReference=FirebaseDatabase.getInstance("https://tailoring-e7e0c-default-rtdb.asia-southeast1.firebasedatabase.app/").getReference("Users")
databaseReference.child(uAuth.currentUser?.uid.toString()).addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
var userList :User
userList = snapshot.getValue(User::class.java)!!
userName=userList?.cid.toString()
Toast.makeText(this#ProductDetail,"Username detected",Toast.LENGTH_LONG).show()
}
override fun onCancelled(error: DatabaseError) {
}
})
}
private fun getProductData() {
databaseReference=FirebaseDatabase.getInstance("https://tailoring-e7e0c-default-rtdb.asia-southeast1.firebasedatabase.app/").reference
databaseReference.child("Product").child(thisProductID).addValueEventListener(object: ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val productData = snapshot.getValue<Product>()
viewBinding.tvViewPrice.setText(productData?.price.toString())
viewBinding.tvViewClothspants.setText(productData?.clothsPants.toString())
viewBinding.tvViewFabric.setText(productData?.fabric.toString())
viewBinding.tvViewHeight.setText(productData?.height.toString())
viewBinding.tvViewHipBust.setText(productData?.hipBust.toString())
viewBinding.tvViewSleeve.setText(productData?.sleeve.toString())
viewBinding.tvViewStyleName.setText(productData?.styleName.toString())
viewBinding.tvViewWaist.setText(productData?.waist.toString())
tailorUID = productData?.tailorID.toString()
getTailorPic(productData?.tailorID.toString())
getProductPic(productData?.imageURL.toString())
}
override fun onCancelled(error: DatabaseError) {
Toast.makeText(this#ProductDetail,"Some Things wrong in the database", Toast.LENGTH_SHORT).show()
}
}
)
}
private fun getProductPic(prodImageURL:String) {
storageReference= FirebaseStorage.getInstance().reference.child(prodImageURL)
val localFile = File.createTempFile("tempImage","jpg")
storageReference.getFile(localFile).addOnSuccessListener {
val bitMap= BitmapFactory.decodeFile(localFile.absolutePath)
viewBinding.picViewProd.setImageBitmap(bitMap)
}
}
private fun getTailorName() {
databaseReference=FirebaseDatabase.getInstance("https://tailoring-e7e0c-default-rtdb.asia-southeast1.firebasedatabase.app/").getReference("Users")
databaseReference.child(tailorUID).addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val userList = snapshot.getValue(User::class.java)!!
tailorName=userList.cid.toString()
viewBinding.tvPViewTailorName.setText(tailorName)
Toast.makeText(this#ProductDetail,"Username detected",Toast.LENGTH_LONG).show()
}
override fun onCancelled(error: DatabaseError) {
}
})
}
private fun getTailorPic(tailorUID:String){
storageReference= FirebaseStorage.getInstance().reference.child("Users/$tailorUID.jpg")
val localFile = File.createTempFile("tempImage","jpg")
storageReference.getFile(localFile).addOnSuccessListener {
val bitMap= BitmapFactory.decodeFile(localFile.absolutePath)
viewBinding.picViewTailor.setImageBitmap(bitMap)
}
}
private fun getComment() {
databaseReference=FirebaseDatabase.getInstance().getReference()
databaseReference.child("Comment").addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
commentList.clear()
for(postSnapshot in snapshot.children){
val currentComment = postSnapshot.getValue(commentContain::class.java)
if(currentComment?.productID==thisProductID){
commentList.add(currentComment!!)
}
}
adapter.notifyDataSetChanged()
}
override fun onCancelled(error: DatabaseError) {
}
})
}
private fun addOrder() {
val intent = Intent(this, NewCustomOrder::class.java)
intent.putExtra("tc",tc)
intent.putExtra("prodNo",thisProductID)
startActivity(intent)
}
private fun addComment(productID:String,senderID:String?,comment:String,dateTage:String,currentUserURL:String){
val newComment = commentContain(uAuth.currentUser?.uid,senderID,comment,dateTage,currentUserURL,productID)
databaseReference=FirebaseDatabase.getInstance().reference
databaseReference.child("Comment").child(commentList.size.toString()).setValue(newComment).addOnFailureListener{
Toast.makeText(this,"Some thing wrong for real time database", Toast.LENGTH_SHORT).show()
}.addOnSuccessListener {
Toast.makeText(this,"Comment is added", Toast.LENGTH_SHORT).show()
}
}
private fun getTimeTag() {
val formatter = SimpleDateFormat("yyyy_MM_dd", Locale.getDefault())
val now = Date()
dateTage=formatter.format(now).toString()
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
super.onCreateOptionsMenu(menu)
getMenuInflater().inflate(R.menu.all_menu,menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
super.onOptionsItemSelected(item)
if(item.itemId==R.id.toProfile){
val intent = Intent(this, TailorProfile::class.java)
intent.putExtra("tc",tc)
intent.putExtra("tuid",uAuth.currentUser?.uid)
finish()
startActivity(intent)
}
else if(item.itemId == R.id.toHome){
val intent = Intent(this, ProductList::class.java)
intent.putExtra("tc",tc)
finish()
startActivity(intent)
}else if(item.itemId == R.id.logout){
val intent = Intent(this, Ground::class.java)
uAuth.signOut()
finish()
startActivity(intent)
}
return true
}
}
The only problem is the getUserName and getTailorName return null at all,which is cause by the snapshot return a null value. I have tried all the method of get data from firebase realtime database, but all of them meets same problem. The weird thing is only the two function meet that problem. Any one can help me please?
below is the picture output
enter image description here
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.
I am creating a new user with authentication, and setting the User Key in the database as the User UID.
private fun writeNewUser(name: String, email: String?) {
val user = User(name, email)
mDatabase.child("Users").child(mAuth.currentUser!!.uid).setValue(user)
}
This works fine and produces the following result:
I'm now trying to login and read that user's information.
I'm trying to set the UID as the database reference (after having successfully logged in).*My Login process is working.
I'm getting an error on MainActivity where I'm trying to display the data:
Error:
None of the following functions can be called with the arguments supplied:
Line:
key?.let { getValue(mAuth.uid) }
Here's my MainActivity code where I'm trying to read and display the data.
class MainActivity : AppCompatActivity() {
private lateinit var mUser: User
private lateinit var mAuth : FirebaseAuth
private lateinit var mDatabase: DatabaseReference
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mAuth = FirebaseAuth.getInstance()
mDatabase = FirebaseDatabase.getInstance().reference
fun currentUserReference(): DatabaseReference =
mDatabase.child("users").child(mAuth.currentUser!!.uid)
currentUserReference().addListenerForSingleValueEvent(
ValueListenerAdapter{
mUser = it.asUser()!!
tv_main_name.setText(mUser.name)
tv_main_email.setText(mUser.email)
}
)
}
fun DataSnapshot.asUser(): User? =
//error on this line ↓
key?.let { getValue(mAuth.uid) }
}
Edit 1
Existing ValueListenerAdapter.kt
class ValueListenerAdapter(val handler: (DataSnapshot) -> Unit): ValueEventListener {
private val TAG = "ValueListenerAdapter"
override fun onDataChange(data: DataSnapshot) {
handler(data)
}
override fun onCancelled(error: DatabaseError) {
Log.e("onCancelled", TAG, error.toException())
}
}
Edit 2
class MainActivity : AppCompatActivity() {
private lateinit var mUser: User
private lateinit var mAuth : FirebaseAuth
private lateinit var mDatabase: DatabaseReference
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mAuth = FirebaseAuth.getInstance()
mDatabase = FirebaseDatabase.getInstance().reference
mDatabase.child("Users").child(mAuth.currentUser!!.uid)
.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
TODO("Not yet implemented")
}
override fun onDataChange(p0: DataSnapshot) {
//Declare mUser as chosen DB User
tv_main_name.setText(mUser.name)
tv_main_email.setText(mUser.email)
}
})
}
}
Edit 3
override fun onDataChange(p0: DataSnapshot) {
if (p0.hasChildren()) {
//Declare mUser as chosen DB User
tv_main_name.setText(mUser.name)
tv_main_email.setText(mUser.email)
}
}
mDatabase.child("users").child(mAuth.currentUser!!.uid).addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
//handle error
}
override fun onDataChange(p0: DataSnapshot) {
if (p0.hasChildren()) {
//If you have model for your user data object then do it like this.
val user = p0.getValue(YourModel::class.java)
}
})
That's all you need to do to get current logged in user data from users node
Working Solution
class MainActivity : AppCompatActivity() {
private lateinit var mUser: User
private lateinit var mAuth : FirebaseAuth
private lateinit var mDatabase: DatabaseReference
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mAuth = FirebaseAuth.getInstance()
mDatabase = FirebaseDatabase.getInstance().reference
mDatabase.child("Users").child(mAuth.currentUser!!.uid)
.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
TODO("Not yet implemented")
}
override fun onDataChange(p0: DataSnapshot) {
if (p0.hasChildren()) {
val user = p0.getValue(User::class.java)
tv_main_name.text = user?.name
tv_main_email.text = user!!.email
}
}
})
}
}
How i can optimize my code?
In every function i created valueEventListener.
Here is all code:
class TargetsPresenter(private val contract: SelectTargetViewContract) {
var firebaseUser: FirebaseUser? = null
var targetList: ArrayList<Goal> = ArrayList()
private var databaseReference: DatabaseReference? = null
private var targetsRef: DatabaseReference? = null
private var uid: String? = null
fun setInitialData() {
firebaseUser = FirebaseAuth.getInstance().currentUser
databaseReference = FirebaseDatabase.getInstance().reference
uid = firebaseUser?.uid
targetsRef = databaseReference?.child("targets")
?.child("users")?.child(uid.toString())
?.child("targets")
}
fun getTargetsFromDb() {
val valueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
targetList.clear()
dataSnapshot.children
.mapNotNull { it.getValue(Goal::class.java) }
.toCollection(targetList)
contract.updateViewContent()
}
override fun onCancelled(databaseError: DatabaseError) {
Log.d("some", "Error trying to get targets for ${databaseError.message}")
}
}
targetsRef?.addListenerForSingleValueEvent(valueEventListener)
}
fun getTargetsByPriority() {
val valueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
targetList.clear()
dataSnapshot.children
.mapNotNull { it.getValue(Goal::class.java) }
.sortedBy { it.priority }
.toCollection(targetList)
contract.updateViewContent()
}
override fun onCancelled(databaseError: DatabaseError) {
Log.d("some", "Error trying to get targets for ${databaseError.message}")
}
}
targetsRef?.addListenerForSingleValueEvent(valueEventListener)
}
fun getTargetsByDeadline() {
val valueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
targetList.clear()
dataSnapshot.children
.mapNotNull { it.getValue(Goal::class.java) }
.sortedBy { it.deadline }
.toCollection(targetList)
contract.updateViewContent()
}
override fun onCancelled(databaseError: DatabaseError) {
Log.d("some", "Error trying to get targets for ${databaseError.message}")
}
}
targetsRef?.addListenerForSingleValueEvent(valueEventListener)
}
}
Optimization is the wrong word to describe the issue. The issue is repeating identical code (violating the DRY principle), which can be a problem because it invites error if you need to change something, and it's less readable.
In this case, it's not extreme, but I guess it could be improved somewhat. You can declare a class implementation of the listener that takes a parameter for how to sort the list.
class TargetsPresenter(private val contract: SelectTargetViewContract) {
//...
fun getTargetsFromDb() {
targetsRef?.addListenerForSingleValueEvent(MyValueEventListener<String>())
}
fun getTargetsByPriority() {
targetsRef?.addListenerForSingleValueEvent(MyValueEventListener(Goal::priority))
}
fun getTargetsByDeadline() {
targetsRef?.addListenerForSingleValueEvent(MyValueEventListener(Goal::deadline))
}
private inner class MyValueEventListener<R: Comparable<R>>(
private val sortCriteria: (Goal) -> R? = { null }
) : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
targetList.clear()
dataSnapshot.children
.mapNotNull { it.getValue(Goal::class.java) }
.sortedBy(sortCriteria)
.toCollection(targetList)
contract.updateViewContent()
}
override fun onCancelled(databaseError: DatabaseError) {
Log.d("some", "Error trying to get targets for ${databaseError.message}")
}
}
}