I have a problem whit my code, but I get no errors. The problem arise when I try change my variables ”artistName” and ”trackName” to my object ”SoundTrack”. If I use my variables ”artistName” and ”trackName” it works fine, I can upload, delete and display data etc. But when I try o use my object nothing is happend, It’s like it doesn’t connect to my database.
My class:
class SoundTrack (val name : String, val track : String)
Here is my MainActivity:
class MainActivity : AppCompatActivity(), View.OnClickListener {
val collection = "song"
//val artistName = "name"
//val trackName = "track"
var docId =""
lateinit var newTrack : SoundTrack
lateinit var db : FirebaseFirestore
lateinit var alSongs : ArrayList<HashMap<String,Any>>
lateinit var adapter: SimpleAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
alSongs = ArrayList()
addData.setOnClickListener(this)
updateInfo.setOnClickListener(this)
deleteInfo.setOnClickListener(this)
IsData.setOnItemClickListener(itemClick)
}
override fun onStart() {
super.onStart()
db = FirebaseFirestore.getInstance()
db.collection(collection).addSnapshotListener { querySnapshot, e ->
if(e != null) Log.d("fireStore", e.message)
showData()
}
}
//add new data by input
override fun onClick(v: View?) {
when(v?.id){
R.id.addData ->{
println("hej")
if(::newTrack.isInitialized){
val hm = HashMap<String, Any>()
hm.set(newTrack.name,artistNametxt.text.toString())
hm.set(newTrack.track,trackNametxt.text.toString())
db.collection(collection).document(artistNametxt.text.toString()).set(hm).
addOnSuccessListener {
Toast.makeText(this, "Data Successfully added", Toast.LENGTH_SHORT)
.show()
}.addOnFailureListener { e ->
Toast.makeText(this, "Data unSuccessfully added : ${e.message}", Toast.LENGTH_SHORT)
.show()
}
}
}
//Update input
R.id.updateInfo -> {
if(::newTrack.isInitialized){
val hm = HashMap<String, Any>()
hm.set(newTrack.name,artistNametxt.text.toString())
hm.set(newTrack.track,trackNametxt.text.toString())
db.collection(collection).document(docId).update(hm)
.addOnSuccessListener { Toast.makeText(this, "Data Successfully updated", Toast.LENGTH_SHORT)
.show() }
.addOnFailureListener { e ->
Toast.makeText(this, "Data unSuccessfully updated : ${e.message}", Toast.LENGTH_SHORT)
.show()
}
}
}
//delete Input
R.id.deleteInfo -> {
if(::newTrack.isInitialized){
db.collection(collection).whereEqualTo(newTrack.name,docId).get().addOnSuccessListener {
results ->
for(doc in results){
db.collection(collection).document(doc.id).delete()
.addOnSuccessListener {
Toast.makeText(this, "Data Successfully updated", Toast.LENGTH_SHORT)
.show()
}.addOnFailureListener { e ->
Toast.makeText(this, "Data unSuccessfully updated : ${e.message}", Toast.LENGTH_SHORT)
.show()
}
}
}.addOnFailureListener { e ->
Toast.makeText(this, "Cant get data reference: ${e.message}", Toast.LENGTH_SHORT)
.show()
}
}
}
}
}
val itemClick = AdapterView.OnItemClickListener { parent, view, position, id ->
val hm = alSongs.get(position)
docId = hm.get(newTrack.name).toString()
artistNametxt.setText(hm.get(newTrack.name).toString())
trackNametxt.setText(hm.get(newTrack.name).toString())
}
//Show input data
fun showData(){
if(::newTrack.isInitialized){
db.collection(collection).get().addOnSuccessListener { result ->
alSongs.clear()
for(doc in result){
val hm = HashMap<String,Any>()
hm.set(newTrack.name,doc.get(newTrack.name).toString())
hm.set(newTrack.track,doc.get(newTrack.track).toString())
alSongs.add(hm)
}
}
adapter = SimpleAdapter(this,alSongs,R.layout.row_data,
arrayOf(newTrack.name,newTrack.track),
intArrayOf(R.id.txName, R.id.TxTrack))
IsData.adapter = adapter
}
}
}
Try this
fun getSongs(): LiveData<MutableList<SongTrack>> {
firestoreInstance.collection(SONG_COLLECTION)
.addSnapshotListener { querySnapshot,
firebaseFirestoreException ->
song.clear()
querySnapshot?.documents?.forEach {document ->
val songTrack = document.toObject(SongTrack::class.java)
songTrack?.let {
song.add(it)
}
}
}
songList.postValue(song)
return songList
}
First i would change
class SoundTrack (val name : String, val track : String)
to
data class SoundTrack(val name : String ="",val track : String ="")
and delete
lateinit var newTrack : SoundTrack
so you don't need to do this anymore
if(::newTrack.isInitialized)
delete
lateinit var db : FirebaseFirestore
and create Object class
object FirestoreUtil {
private val firestoreInstance: FirebaseFirestore by lazy {
FirebaseFirestore.getInstance()
}
}
or better yet
class MainActivity : AppCompatActivity() {
lateinit var adapter: SimpleAdapter
val itemClick = AdapterView.OnItemClickListener { parent, view, position, id ->
val selectedSong = FirestoreUtils.songList.value?.get(position)
selectedSong?.let {
artistNametxt.setText(it.name.toString())
trackNametxt.setText(it.track.toString())
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
FirestoreUtils.getSongs().observe(this, Observer { songList ->
adapter = SimpleAdapter(
this, songList, R.layout.row_data,
arrayOf(SongTrack().name, SongTrack().track),
intArrayOf(R.id.txName, R.id.TxTrack)
)
IsData.adapter = adapter
})
addData.setOnClickListener {
FirestoreUtils.addSong(
SongTrack(
artistNametxt.text.toString(),
trackNametxt.text.toString()
)
) { message -> Toast.makeText(this, message, Toast.LENGTH_SHORT).show() }
}
updateInfo.setOnClickListener {
FirestoreUtils.updateSong(
SongTrack(
artistNametxt.text.toString(),
trackNametxt.text.toString()
)
) { message ->
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
}
deleteInfo.setOnClickListener(FirestoreUtils.deleteSong(artistNametxt.text.toString()) { message ->
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
})
IsData.setOnItemClickListener {
itemClick
}
}
}
const val SONG_COLLECTION = "song"
data class SongTrack(val name: String = "", val track: String = "")
object FirestoreUtils {
private val firestoreInstance: FirebaseFirestore by lazy {
FirebaseFirestore.getInstance()
}
private val songCollection = firestoreInstance.collection(SONG_COLLECTION)
private val song = mutableListOf<SongTrack>()
val songList: MutableLiveData<MutableList<SongTrack>> = MutableLiveData()
fun getSongs(): LiveData<MutableList<SongTrack>> {
firestoreInstance.collection(SONG_COLLECTION)
.addSnapshotListener { querySnapshot,
firebaseFirestoreException ->
song.clear()
querySnapshot?.documents?.forEach {
it.toObject<SongTrack>()?.let { songTrack ->
song.add(songTrack)
}
}
}
songList.postValue(song)
return songList
}
fun addSong(songTrack: SongTrack, onComplete: (String) -> Unit) {
songCollection.document(songTrack.name)
.set(songTrack)
.addOnSuccessListener { onComplete("Data Successfully added") }
.addOnFailureListener { onComplete("Data unSuccessfully added : ${it.message}") }
}
fun updateSong(songTrack: SongTrack, onComplete: (String) -> Unit) {
songCollection.document(songTrack.name)
.set(songTrack)
.addOnSuccessListener { onComplete("Data Successfully updated") }
.addOnFailureListener { onComplete("Data unSuccessfully updated : ${it.message}") }
}
fun deleteSong(songTrack: SongTrack, onComplete: (String) -> Unit) {
val deleteSong = songTrack.name
songCollection.document(songTrack.name).delete()
.addOnSuccessListener { onComplete("Song $deleteSong deleted") }
.addOnFailureListener { onComplete("Not found the song id : ${songTrack.name}") }
}
}
I just edit from your code, Did not test yet!!!
Enjoy.
Related
I am trying to write a unit tests to my kotlin class that writes and reads values from Firebase. I tried in different ways of writing the tests but always got errors with firebase.
This is my Repository Class:
package mainPackage.model
import com.google.firebase.firestore.FirebaseFirestore
import android.util.Log
import com.google.firebase.firestore.FirebaseFirestoreException
import mainPackage.utils.Checks
const val TAG = "FIRESTORE"
class RepositoryMockup {
//--------------------------------
//Firebase functions
fun writeNewUser(pass: String, email: String, isATeacher: Boolean?) {
val database = FirebaseFirestore.getInstance()
val myRef = database.collection("Users").document(email)
val newUser = hashMapOf(
"is_a_teacher" to isATeacher,
"pass" to pass
)
myRef.set(newUser)
.addOnSuccessListener { Log.d(TAG, "User successfully added") }
.addOnFailureListener { e -> Log.w(TAG, "Error writing user", e) }
}
//CHECKED AND FIXED
fun userLogin(user: User, callback: (Checks) -> Unit) {
val database = FirebaseFirestore.getInstance()
val myRef = database.collection("Users").document(user.email.toString())
myRef.get()
.addOnSuccessListener { document ->
if (document != null && document.exists()) {
val pass = document.get("pass") as String
if (pass == user.password) {
callback(Checks.PASSED)
} else {
callback(Checks.FAILED_CHECK)
}
Log.d(TAG, "Pass successfully checked")
} else {
callback(Checks.NEW_USER_CREATED)
Log.d(TAG, "Is empty")
writeNewUser(user.password.toString(), user.email.toString(), user.isATeacher)
}
}
.addOnFailureListener { exception ->
if (exception is FirebaseFirestoreException) {
Log.e(TAG, "Error getting document: ", exception)
}
callback(Checks.FAILED_CHECK)
}
}
fun userLoginTest(user: UserTest, callback: (Checks) -> Unit) {
val database = FirebaseFirestore.getInstance()
val myRef = database.collection("Users").document(user.email.toString())
myRef.get()
.addOnSuccessListener { document ->
if (document != null && document.exists()) {
val pass = document.get("pass") as String
if (pass == user.pass) {
callback(Checks.PASSED)
} else {
callback(Checks.FAILED_CHECK)
}
Log.d(TAG, "Pass successfully checked")
} else {
callback(Checks.NEW_USER_CREATED)
Log.d(TAG, "Is empty")
writeNewUser(user.pass.toString(), user.email.toString(), user.isATeacher)
}
}
.addOnFailureListener { exception ->
if (exception is FirebaseFirestoreException) {
Log.e(TAG, "Error getting document: ", exception)
}
callback(Checks.FAILED_CHECK)
}
}
//CHECKED AND FIXED
fun readNameSurnameByEmail(email: String, callback: (String) -> Unit){
val database = FirebaseFirestore.getInstance()
val myRef = database.collection("Users").document(email)
myRef.get()
.addOnSuccessListener { document ->
if (document != null) {
val fieldValue = document.get("name_surname") as String
callback(fieldValue)
Log.d(TAG, "Name and surname successfully read")
} else {
Log.d(TAG, "Is empty")
}
}
.addOnFailureListener { exception ->
if (exception is FirebaseFirestoreException) {
Log.e(TAG, "Error getting document: ", exception)
}
}
}
//CHECKED
fun readIsATeacherByEmail(email: String): Boolean {
val database = FirebaseFirestore.getInstance()
val myRef = database.collection("Users").document(email)
var fieldValue = false
myRef.get()
.addOnSuccessListener { document ->
if (document != null) {
fieldValue = document.get("is_a_teacher") as Boolean
Log.d(TAG, "Name and surname successfully read")
} else {
Log.d(TAG, "Is empty")
}
}
.addOnFailureListener { exception ->
if (exception is FirebaseFirestoreException) {
Log.e(TAG, "Error getting document: ", exception)
}
}
return fieldValue
}
//CHECKED
fun writeOfficeHoursInstance(email: String, timeFrom: String, timeTo: String) {
val database = FirebaseFirestore.getInstance()
var id = ""
val myRef = database.collection("OfficeHoursInstance").document()
id = myRef.id
val newInstance = hashMapOf(
"email" to email,
"time_from" to timeFrom,
"time_to" to timeTo,
"id" to id
)
myRef.set(newInstance)
.addOnSuccessListener { Log.d(TAG, "Instance successfully added") }
.addOnFailureListener { e -> Log.w(TAG, "Error writing Instance", e) }
}
//CHECKED AND FIXED
fun readOfficeHoursInstanceTeacher(email: String, callback: (MutableList<OfficeHoursInstance>) -> Unit){
var timeFrom = ""
var timeTo = ""
var userEmail = ""
var code = ""
var list = mutableListOf<OfficeHoursInstance>()
val database = FirebaseFirestore.getInstance()
val ref = database.collection("OfficeHoursInstance")
.whereEqualTo("email", email)
ref.get()
.addOnSuccessListener { documents ->
for (document in documents) {
timeFrom = document.get("time_from") as String
timeTo = document.get("time_to") as String
userEmail = document.get("email") as String
code = document.get("id") as String
list.add(OfficeHoursInstance(userEmail, timeFrom, timeTo, code))
Log.d(TAG, " Time instance successfully read")
}
callback(list)
}
.addOnFailureListener { exception ->
if (exception is FirebaseFirestoreException) {
Log.e(TAG, "Error getting document: ", exception)
}
}
}
fun updateUserOfficeHoursList(email: String, code: String){
val database = FirebaseFirestore.getInstance()
val ref = database.collection("Users").document(email)
var list = ""
ref.get()
.addOnSuccessListener { document ->
if (document != null) {
list = document.get("office_hours_list") as String
Log.d(TAG, "office_hours_list successfully read")
} else {
Log.d(TAG, "Is empty")
}
}
.addOnFailureListener { exception ->
if (exception is FirebaseFirestoreException) {
Log.e(TAG, "Error getting document: ", exception)
}
}
if (list.isEmpty()){
list = code
}
else {
list + ", " + code
}
ref.update("office_hours_list", list)
}
}
Can you give me a clue how to write a unit test for my db methods?
Or show me the structure?
Here is what I have but it is not working:
package mainPackage.tests
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.DocumentSnapshot
import com.google.firebase.firestore.FirebaseFirestoreException
import mainPackage.model.RepositoryMockup
import mainPackage.model.UserTest
import mainPackage.utils.Checks
import org.junit.Assert.*
import org.junit.Before
import org.junit.Test
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
class RepositoryMockupTest {
private lateinit var repositoryMockup: RepositoryMockup
#Mock
private lateinit var firebaseFirestore: FirebaseFirestore
#Mock
private lateinit var documentSnapshot: DocumentSnapshot
#Before
fun setUp() {
MockitoAnnotations.initMocks(this)
repositoryMockup = RepositoryMockup()
}
#Test
fun testWriteNewUser() {
repositoryMockup.writeNewUser("password", "email", true)
Mockito.verify(firebaseFirestore).collection("Users").document("email")
}
#Test
fun testUserLogin_Passed() {
val user = UserTest("man.man#pwr.edu.pl", "password123", true)
Mockito.`when`(firebaseFirestore.collection("Users").document("email").get())
.thenReturn(documentSnapshot)
Mockito.`when`(documentSnapshot.exists()).thenReturn(true)
Mockito.`when`(documentSnapshot.get("pass")).thenReturn("password")
var check = Checks.FAILED_CHECK
repositoryMockup.userLoginTest(user) {
check = it
}
assertEquals(Checks.PASSED, check)
}
#Test
fun testUserLogin_FailedCheck() {
val user = UserTest("man.man#pwr.edu.pl", "wrong_password", true)
Mockito.`when`(firebaseFirestore.collection("Users").document("user.email").get())
.thenReturn(documentSnapshot)
Mockito.`when`(documentSnapshot.exists()).thenReturn(true)
Mockito.`when`(documentSnapshot.get("pass")).thenReturn("password")
var check = Checks.PASSED
repositoryMockup.userLoginTest(user) {
check = it
}
assertEquals(Checks.FAILED_CHECK, check)
}
// #Test
// fun testUserLogin_NewUserCreated() {
// val user = UserTest("email", "password", true)
// Mockito.`when`(firebaseFirestore.collection("Users").document("user.email").get())
// .thenReturn(documentSnapshot)
// Mockito.`when`(documentSnapshot.exists()).thenReturn(false)
// var check = Checks.PASSED
// repositoryMockup.userLoginTest(user) {
// check = it
// }
// assertEquals(Checks.NEW_USER_CREATED, check)
// }
}
private fun Any.thenReturn(documentSnapshot: DocumentSnapshot) {
}
I am using Firebase PhoneAuth for user registration with my app. Users are verified successfully and started using the app without any issues. But, It happened to me a couple of times that user details vanished from Firestore database, not all users details have gone though. When I check the collection users in the Firestore, the document does exist for the user but some data was gone, in fact, it's overwritten the old data as if this is new user registration (However, the User UID under the Authentication is remain same). For example, the default value is user_type = "customer", as you can see in the fun signInWithPhoneAuthCredential(credential: PhoneAuthCredential). Later I change this value accordingly to my need and when this issue happens the changes I made to this field and other fields are changed back to the default values.
Following is the code in my SignInWithPhone which will be called from the SplashScreen
class SigninWithPhoneActivity: BaseActivity() {
private lateinit var binding: ActivitySignInWithPhoneBinding
private lateinit var mAuth: FirebaseAuth
var code = ""
var number = ""
var phoneNumber = ""
var storedOtpID = ""
private lateinit var resendToken: PhoneAuthProvider.ForceResendingToken
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySignInWithPhoneBinding.inflate(layoutInflater)
setContentView(binding.root)
}
mAuth = FirebaseAuth.getInstance()
binding.btnGetOtp.setOnClickListener {
code = binding.etCountryCode.text.toString().trim()
number = binding.etMobileNumber.text.toString().trim()
phoneNumber = code + number
if (number.isNotEmpty()) {
binding.etMobileNumber.isEnabled = false
binding.flOtp.visibility = View.VISIBLE
binding.btnGetOtp.visibility = View.GONE
binding.btnSignIn.visibility = View.VISIBLE
sendVerificationCode(phoneNumber)
} else {
Toast.makeText(this, "Please enter a valid mobile number", Toast.LENGTH_LONG).show()
}
}
binding.btnSignIn.setOnClickListener {
val otp = binding.etOtp.text.toString().trim()
if (otp.isNotEmpty() || otp.length != 6) {
verifyVerificationCode(otp)
} else {
Toast.makeText(this, "Please enter the OTP received through SMS", Toast.LENGTH_LONG)
.show()
}
}
}
private val mCallBack: PhoneAuthProvider.OnVerificationStateChangedCallbacks =
object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
val code = credential.smsCode
if (code != null) {
binding.etOtp.setText(code)
binding.pbOtp.visibility = View.GONE
}
}
override fun onVerificationFailed(p0: FirebaseException) {
binding.etMobileNumber.isEnabled = true
binding.flOtp.visibility = View.GONE
binding.btnGetOtp.visibility = View.VISIBLE
binding.btnSignIn.visibility = View.GONE
Toast.makeText(this#SigninWithPhoneActivity, "Login Failed", Toast.LENGTH_LONG)
.show()
}
override fun onCodeSent(otpID: String, token: PhoneAuthProvider.ForceResendingToken) {
super.onCodeSent(otpID, token)
Toast.makeText(
this#SigninWithPhoneActivity,
"OTP is send to your number",
Toast.LENGTH_LONG
).show()
storedOtpID = otpID
resendToken = token
}
}
private fun sendVerificationCode(phoneNumber: String) {
binding.pbOtp.visibility = View.VISIBLE
Toast.makeText(this#SigninWithPhoneActivity, "Sending OTP", Toast.LENGTH_LONG).show()
val options = PhoneAuthOptions.newBuilder(mAuth!!)
.setPhoneNumber(phoneNumber)
.setTimeout(60L, TimeUnit.SECONDS)
.setActivity(this)
.setCallbacks(mCallBack)
.build()
PhoneAuthProvider.verifyPhoneNumber(options)
}
private fun verifyVerificationCode(code: String) {
Toast.makeText(
this#SigninWithPhoneActivity,
"Verifying credentials",
Toast.LENGTH_LONG
).show()
val credential = PhoneAuthProvider.getCredential(storedOtpID, code)
signInWithPhoneAuthCredential(credential)
}
private fun signInWithPhoneAuthCredential(credential: PhoneAuthCredential) {
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
val firebaseUser: FirebaseUser = task.result!!.user!!
val userPreliminaryDetails = User(
firebaseUser.uid,
user_type = "customer",
mobile = binding.etMobileNumber.text.toString()
)
FirestoreClass().checkIfUserAlreadyExist(
this#SigninWithPhoneActivity,
firebaseUser.uid,
userPreliminaryDetails
)
} else {
showErrorSnackBar(task.exception!!.message.toString(), true)
if (task.exception is FirebaseAuthInvalidCredentialsException) {
binding.etMobileNumber.isEnabled = true
binding.flOtp.visibility = View.GONE
binding.etOtp.text?.clear()
binding.btnGetOtp.visibility = View.VISIBLE
binding.btnGetOtp.text = "Resend OTP"
binding.btnSignIn.visibility = View.GONE
Toast.makeText(this, "OTP entered is wrong", Toast.LENGTH_LONG).show()
}
}
}
}
fun userRegistrationSuccess() {
finish()
startActivity(Intent(this, ServiceAreaActivity::class.java))
Toast.makeText(this, "Signed Up successful", Toast.LENGTH_LONG).show()
}
fun userSignInSuccess() {
finish()
startActivity(Intent(this, ServiceAreaActivity::class.java))
Toast.makeText(this, "Signed in successfully", Toast.LENGTH_LONG).show()
}
}
EDIT:
The following function is called to check if the user already exists and accordingly sign in or register a new user.
fun checkIfUserAlreadyExist(
activity: SigninWithPhoneActivity, userId: String, userDetails: User
) {
mFireStore.collection("users")
.whereEqualTo(Constants.USER_ID, userId)
.get()
.addOnSuccessListener { document ->
if (document.documents.size > 0) {
activity.userSignInSuccess()
} else {
FirestoreClass().registerUser(activity, userDetails)
}
}
.addOnFailureListener { e ->
}
}
private fun registerUser(activity: SigninWithPhoneActivity, userInfo: User) {
mFireStore.collection(Constants.USERS)
.document(userInfo.user_id)
.set(userInfo, SetOptions.merge())
.addOnSuccessListener {
activity.userRegistrationSuccess()
}
.addOnFailureListener { e ->
activity.hideProgressDialog()
}
}
My view model looks like this:
class BlogListActivityViewModel #ViewModelInject constructor(
private val blogRepository: BlogRepository,
private val context: Application,
#IoDispatcher private val ioDispatcher: CoroutineDispatcher
) : AndroidViewModel(context) {
var blogDeleteLiveData = MutableLiveData<Resource<DeleteResponse>>()
fun deleteBlog(itemId: Int) {
viewModelScope.launch(ioDispatcher) {
blogDeleteLiveData.postValue(Resource.loading())
try {
val deleteResponse = async { blogRepository.deleteBlog(itemId) }
blogDeleteLiveData.postValue(Resource.success(deleteResponse.await()))
} catch (e: Exception) {
blogDeleteLiveData.postValue(Resource.error(message = context.getString(R.string.unable_to_load_blog)))
}
}
}
}
Calling activity looks like this:
blogListActivityViewModel.blogDeleteLiveData.observe(this, Observer { resource ->
val sweetDialog = SweetAlertDialog(this, SweetAlertDialog.PROGRESS_TYPE)
sweetDialog.titleText = "Deleting"
sweetDialog.setCancelable(false)
resource?.let { resource ->
when (resource.status) {
Resource.Status.SUCCESS -> {
blogListAdapter.deleteBlog(deletedBlog)
sweetDialog.changeAlertType(SweetAlertDialog.SUCCESS_TYPE)
sweetDialog.contentText = "Successfully deleted !!"
sweetDialog.titleText = "Congratulation"
}
Resource.Status.ERROR -> {
sweetDialog.changeAlertType(SweetAlertDialog.ERROR_TYPE)
sweetDialog.contentText = resource.message
sweetDialog.titleText = "Oops Something Wrong"
}
Resource.Status.LOADING -> {
deleteDialog.dismissWithAnimation()
sweetDialog.changeAlertType(SweetAlertDialog.PROGRESS_TYPE)
sweetDialog.contentText = "Please wait while deleting..."
sweetDialog.show()
}
}
}
})
blogListActivityViewModel.deleteBlog(blog.id)
But I m keep getting
FATAL EXCEPTION: DefaultDispatcher-worker-2
When I start my app it crash and I get get Following error message in logcat:
"lateinit property newTrack has not been initialized"
I have locate the problem to my "showdata" function, but I can't see what the problem is.
class MainActivity : AppCompatActivity(), View.OnClickListener {
val collection = "song"
val artistName = "name"
val trackName = "track"
var docId =""
lateinit var newTrack : SoundTrack
lateinit var db : FirebaseFirestore
lateinit var alSongs : ArrayList<HashMap<String,Any>>
lateinit var adapter: SimpleAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
alSongs = ArrayList()
addData.setOnClickListener(this)
updateInfo.setOnClickListener(this)
deleteInfo.setOnClickListener(this)
IsData.setOnItemClickListener(itemClick)
}
override fun onStart() {
super.onStart()
db = FirebaseFirestore.getInstance()
db.collection(collection).addSnapshotListener { querySnapshot, e ->
if(e != null) Log.d("fireStore", e.message)
showData()
}
}
override fun onClick(v: View?) {
when(v?.id){
//add new data by input
R.id.addData ->{
val hm = HashMap<String, Any>()
hm.set(newTrack.name,ArtistName.text.toString())
hm.set(newTrack.track,track.text.toString())
db.collection(collection).document(ArtistName.text.toString()).set(hm).
addOnSuccessListener {
Toast.makeText(this, "Data Successfully added", Toast.LENGTH_SHORT)
.show()
}.addOnFailureListener { e ->
Toast.makeText(this, "Data unSuccessfully added : ${e.message}", Toast.LENGTH_SHORT)
.show()
}
}
//Update input
R.id.updateInfo -> {
val hm = HashMap<String, Any>()
hm.set(newTrack.name,ArtistName.text.toString())
hm.set(newTrack.track,track.text.toString())
db.collection(collection).document(docId).update(hm)
.addOnSuccessListener { Toast.makeText(this, "Data Successfully updated", Toast.LENGTH_SHORT)
.show() }
.addOnFailureListener { e ->
Toast.makeText(this, "Data unSuccessfully updated : ${e.message}", Toast.LENGTH_SHORT)
.show()
}
}
//delete Input
R.id.deleteInfo -> {
db.collection(collection).whereEqualTo(newTrack.name,docId).get().addOnSuccessListener {
results ->
for(doc in results){
db.collection(collection).document(doc.id).delete()
.addOnSuccessListener {
Toast.makeText(this, "Data Successfully updated", Toast.LENGTH_SHORT)
.show()
}.addOnFailureListener { e ->
Toast.makeText(this, "Data unSuccessfully updated : ${e.message}", Toast.LENGTH_SHORT)
.show()
}
}
}.addOnFailureListener { e ->
Toast.makeText(this, "Cant get data reference: ${e.message}", Toast.LENGTH_SHORT)
.show()
}
}
}
}
val itemClick = AdapterView.OnItemClickListener { parent, view, position, id ->
val hm = alSongs.get(position)
docId = hm.get(newTrack.name).toString()
ArtistName.setText(hm.get(newTrack.name).toString())
track.setText(hm.get(newTrack.name).toString())
}
//Show input data
fun showData(){
db.collection(collection).get().addOnSuccessListener { result ->
alSongs.clear()
for(doc in result){
val hm = HashMap<String,Any>()
hm.set(newTrack.name,doc.get(newTrack.name).toString())
hm.set(newTrack.track,doc.get(newTrack.track).toString())
alSongs.add(hm)
}
adapter = SimpleAdapter(this,alSongs,R.layout.row_data,
arrayOf(newTrack.name,newTrack.track),
intArrayOf(R.id.txName, R.id.TxTrack))
IsData.adapter = adapter
}
}
}
The whole point of lateinit is to prevent nullability. When you use lateinit you are saying that by the time I want to use this value it will be initialized. When you try to use it before you initialize it you get this error so you need to initialize it first
You can use if(::newTrack.isInitialized) like others have said but IMO that defeats the purpose of lateinit
You should initialize newTrack variable or check is it initialized
if(::newTrack.isInitialized){
// logic
}else{
newTrack = SoundTrack()
}
you can using .isInitialized property one can check initialization state of a lateinit variable.
if(this::newTrack.isInitialized){
//newTrack is initialized
}else{
//newTrack is not initialized
}
I'm using Realm in my project and I was trying to update the realm object through RxJava. Realm object is successfully stored but the realm object is not updated.Actually i am performing all Read operations on UI thread and all WRITE operations on background thread using RxJava. Below is my code to perform all Realm's read and write operations.
class SuggestedFriendsController internal constructor(realm : Realm) {
private var realm: Realm? = null
init {
this.realm = realm
}
fun addSuggestedFriends(requestPojo: RequestPojo?) {
realm?.executeTransaction { realm ->
val realmFriends = RealmSuggestedFriends()
realmFriends.friendEmail = requestPojo?.email
realmFriends.friendImage = requestPojo?.image
realmFriends.friendName = requestPojo?.name
realmFriends.friendStatus = requestPojo?.status
realmFriends.friendThumbImage = requestPojo?.thumb_image
realmFriends.friendUid = requestPojo?.uid
realmFriends.requestSent = "No"
realm.copyToRealmOrUpdate(realmFriends)
}
}
fun getRequestStateSync(uid: String?): String? {
var res = Realm.getDefaultInstance().use { realm ->
realm?.where(RealmSuggestedFriends::class.java)
?.equalTo("friendUid", uid)
?.findFirst()
}
return res?.requestSent
}
fun getAllAsync() = Observable.create<List<RealmSuggestedFriends>> { emitter ->
Realm.getDefaultInstance().use { realm ->
val results = realm?.where(RealmSuggestedFriends::class.java)
?.findAll()
emitter.onNext(realm?.copyFromRealm(results)!!)
}
}.flatMapIterable { list -> list }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
fun updateSuggestedFriendAsync(uid: String?, request_type: String?) =
Single.create<String>{emitter ->
Realm.getDefaultInstance().use {realm ->
realm?.executeTransaction{ realm ->
var suggested = realm.where(RealmSuggestedFriends::class.java)
.equalTo("friendUid", uid)
.findFirst()!!
suggested.requestSent = request_type
realm.insertOrUpdate(suggested)
}
emitter.onSuccess("success")
}
}.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
}
Below is my activity code. Here the variable suggestedFriendController?.getRequestStateSync(friend_uid) value is remain unchanged even its value is changed in the database.
class SFriend : AppCompatActivity(){
private var image : NewCircularImagview ?= null
private var name : AppCompatTextView ?= null
private var addFriend : AppCompatButton ?= null
private var imageUrl : String ?= null
private var toolbar : Toolbar ?= null
private var toolbar_text : TextView ?= null
private var progressBar : ProgressBar ?= null
private var friend_uid : String ?= null
private var databaseReference: DatabaseReference? = null
private var uid: String? = null
private var compositeDisposable : CompositeDisposable ?= null
private var realm : Realm ?= null
private var suggestedFriendController : SuggestedFriendsController ?= null
private var request_state : String ?= null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.suggested_friend_profile)
initialize()
friend_uid = intent.getStringExtra("friend_uid")
imageUrl = intent.getStringExtra("imageurl")
name?.text = intent.getStringExtra("name")
request_state = suggestedFriendController?.getRequestStateSync(friend_uid)
if (request_state?.equals("No")!!){
addFriend?.setText("Send Request")
}else{
addFriend?.text = "Cancel Request"
}
}
private fun initialize() {
compositeDisposable = CompositeDisposable()
databaseReference = FirebaseDatabase.getInstance().reference
databaseReference?.keepSynced(true)
uid = FirebaseAuth.getInstance().currentUser?.uid
progressBar = findViewById(R.id.progress_bar)
image = findViewById(R.id.profile_pic)
name = findViewById(R.id.name)
addFriend = findViewById(R.id.addFriend)
toolbar = findViewById(R.id.toolbar)
toolbar_text = toolbar?.findViewById(R.id.toolbar_text1)
toolbar_text?.visibility = View.VISIBLE
setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
getSupportActionBar()?.setHomeButtonEnabled(true)
realm = Realm.getDefaultInstance()
suggestedFriendController = realm?.let { r-> SuggestedFriendsController(r) }
}
override fun onStart() {
super.onStart()
progressBar?.visibility = View.VISIBLE
Picasso.with(this).load(imageUrl!!).into(image,object :Callback{
override fun onSuccess() {
progressBar?.visibility = View.GONE
}
override fun onError() {
showMessage("image loading failed")
}
})
addFriend?.setOnClickListener {
addFriend?.isEnabled = false
if (request_state?.equals("No")!!) {
sendRequest(friend_uid)
}else{
cancelRequest(friend_uid)
}
}
}
private fun cancelRequest(friend_uid: String?) {
Single.create<String>{ subscriber ->
databaseReference
?.child("friend_requests")
?.child(uid)
?.child(friend_uid)
?.removeValue()
?.addOnCompleteListener { task ->
if (task.isSuccessful) {
if (!subscriber.isDisposed) {
subscriber.onSuccess("success")
}
}else{
subscriber.onError(Throwable("error in cancel request"))
}
}
}.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap { Single.create<String>{ subscriber ->
databaseReference
?.child("friend_requests")
?.child(friend_uid)
?.child(uid)
?.removeValue()
?.addOnCompleteListener { task ->
if (task.isSuccessful){
if (!subscriber.isDisposed){
subscriber.onSuccess("success")
}
}else{
subscriber.onError(Throwable("error in cancel request"))
}
}
}.subscribeOn(Schedulers.io())
}
.subscribe({
t1 -> showMessage(t1)
addFriend?.text = "Send Request"
addFriend?.isEnabled = true
suggestedFriendController?.updateSuggestedFriend(friend_uid!!,"No")
},{
t2 -> showMessage(t2.message)
})
}
private fun showMessage(message : String?) {
Toast.makeText(this,message,Toast.LENGTH_SHORT).show()
}
private fun sendRequest(friend_uid : String?){
var d = Single.create<String>{ subscriber ->
databaseReference
?.child("friend_requests")
?.child(uid)
?.child(friend_uid)
?.child("request_type")
?.setValue("sent")
?.addOnCompleteListener { task ->
if (task.isSuccessful){
if (!subscriber.isDisposed){
subscriber.onSuccess("success")
}
}else{
subscriber.onError(Throwable("request failed"))
}
}
}.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap { Single.create<String> { subscriber ->
databaseReference
?.child("friend_requests")
?.child(friend_uid)
?.child(uid)
?.child("request_type")
?.setValue("received")
?.addOnCompleteListener { task ->
if (task.isSuccessful){
if (!subscriber.isDisposed){
subscriber.onSuccess("sent")
}
}else{
subscriber.onError(Throwable("request failed"))
}
}
}.subscribeOn(Schedulers.io())
}.flatMap {
suggestedFriendController?.updateSuggestedFriendAsync(friend_uid,"Yes")
}.subscribe({
t1: String? -> showMessage(t1)
addFriend?.text = "Delete Request"
addFriend?.isEnabled = true
},{
t2 -> showMessage(t2.message)
}
)
compositeDisposable?.add(d)
}
override fun onBackPressed() {
super.onBackPressed()
finish()
}
override fun onStop() {
super.onStop()
compositeDisposable?.clear()
}
override fun onDestroy() {
super.onDestroy()
realm?.close()
}
}
Below code is my Realm model.
open class RealmSuggestedFriends : RealmObject(){
#Required
#PrimaryKey
var friendUid : String ?= null
#Required
var friendName : String ?= null
#Required
var friendEmail : String ?= null
#Required
var friendStatus : String ?= null
#Required
var friendImage : String ?= null
#Required
var friendThumbImage : String ?= null
#Required
var requestSent : String ?= null
}
I need your suggestions to make it work. Help me
Don't get the String, get the object. Also I wouldn't pass a Realm instance to a constructor of something like that.
class SuggestedFriendsController {
fun addSuggestedFriends(requestPojo: RequestPojo) {
Realm.getDefaultInstance().use { r ->
{
r.executeTransaction { realm ->
realm.insertOrUpdate(RealmSuggestedFriends().apply {
friendEmail = requestPojo?.email
friendImage = requestPojo?.image
friendName = requestPojo?.name
friendStatus = requestPojo?.status
friendThumbImage = requestPojo?.thumb_image
friendUid = requestPojo?.uid
requestSent = "No"
})
}
}
}
fun getSuggestedFriend(realm: Realm, uid: String): RealmSuggestedFriends? =
realm.where<RealmSuggestedFriends>().equalTo("friendUid", uid).findFirst()
fun getAllAsync() = Single.create<List<RealmSuggestedFriends>> { emitter ->
Realm.getDefaultInstance().use { realm ->
with(realm) {
emitter.onNext(copyFromRealm(where<RealmSuggestedFriends>().findAll())
}
}
}.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
fun updateSuggestedFriendAsync(uid: String, requestType: String) =
Single.create<String> { emitter ->
Realm.getDefaultInstance().use { r ->
r.executeTransaction { realm ->
var suggested = realm.where<RealmSuggestedFriends>()
.equalTo("friendUid", uid)
.findFirst()!!
suggested.requestSent = requestType
realm.insertOrUpdate(suggested)
}
emitter.onSuccess("success")
}
}.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
class SFriend : AppCompatActivity() {
private lateinit var image: NewCircularImagview
private lateinit var name: AppCompatTextView
private lateinit var addFriend: AppCompatButton
private lateinit var imageUrl: String
private lateinit var toolbar: Toolbar
private lateinit var toolbar_text: TextView
private lateinit var progressBar: ProgressBar
private lateinit var friend_uid: String
private lateinit var databaseReference: DatabaseReference
private lateinit var uid: String
private lateinit var compositeDisposable: CompositeDisposable
private lateinit var realm: Realm
private lateinit var suggestedFriendController: SuggestedFriendsController
private var suggestedFriend: RealmSuggestedFriends
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.suggested_friend_profile)
initialize()
friend_uid = intent.getStringExtra("friend_uid")
imageUrl = intent.getStringExtra("imageurl")
name.text = intent.getStringExtra("name")
suggestedFriend = suggestedFriendController.getRequestStateSync(realm, friend_uid)
addFriend.text = when {
"No" == suggestedFriend?.requestSent -> "Send Request"
else ->
= "Cancel Request"
}
suggestedFriend.addChangeListener(RealmChangeListener {
if(it.isValid()) {
addFriend.text = when {
"No" == it.requestSent -> "Send Request"
else -> "Cancel Request"
}
}
})
}
private fun initialize() {
compositeDisposable = CompositeDisposable()
databaseReference = FirebaseDatabase.getInstance().reference
databaseReference.keepSynced(true)
uid = FirebaseAuth.getInstance().currentUser?.uid
progressBar = findViewById(R.id.progress_bar)
image = findViewById(R.id.profile_pic)
name = findViewById(R.id.name)
addFriend = findViewById(R.id.addFriend)
toolbar = findViewById(R.id.toolbar)
toolbar_text = toolbar?.findViewById(R.id.toolbar_text1)
toolbar_text.visibility = View.VISIBLE
setSupportActionBar(toolbar)
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
supportActionBar!!.setHomeButtonEnabled(true)
realm = Realm.getDefaultInstance()
suggestedFriendController = SuggestedFriendsController()
}
override fun onStart() {
super.onStart()
progressBar.visibility = View.VISIBLE
Picasso.with(this).load(imageUrl).into(image, object : Callback {
override fun onSuccess() {
progressBar.visibility = View.GONE
}
override fun onError() {
showMessage("image loading failed")
}
})
addFriend.setOnClickListener {
addFriend.isEnabled = false
if ("No" == suggestedFriend?.requestSent) {
sendRequest(friend_uid)
} else {
cancelRequest(friend_uid)
}
}
}
private fun cancelRequest(friend_uid: String?) {
Single.create<String> { subscriber ->
databaseReference
.child("friend_requests")
.child(uid)
.child(friend_uid)
.removeValue()
.addOnCompleteListener { task ->
if (task.isSuccessful) {
if (!subscriber.isDisposed) {
subscriber.onSuccess("success")
}
} else {
subscriber.onError(Throwable("error in cancel request"))
}
}
}.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap {
Single.create<String> { subscriber ->
databaseReference
.child("friend_requests")
.child(friend_uid)
.child(uid)
.removeValue()
.addOnCompleteListener { task ->
if (task.isSuccessful) {
if (!subscriber.isDisposed) {
subscriber.onSuccess("success")
}
} else {
subscriber.onError(Throwable("error in cancel request"))
}
}
}.subscribeOn(Schedulers.io())
}
.subscribe({ t1 ->
showMessage(t1)
addFriend.text = "Send Request"
addFriend.isEnabled = true
suggestedFriendController.updateSuggestedFriend(friend_uid!!, "No")
}, { t2 ->
showMessage(t2.message)
})
}
private fun showMessage(message: String?) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
private fun sendRequest(friend_uid: String?) {
var d = Single.create<String> { subscriber ->
databaseReference
.child("friend_requests")
.child(uid)
.child(friend_uid)
.child("request_type")
.setValue("sent")
.addOnCompleteListener { task ->
if (task.isSuccessful) {
if (!subscriber.isDisposed) {
subscriber.onSuccess("success")
}
} else {
subscriber.onError(Throwable("request failed"))
}
}
}.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap {
Single.create<String> { subscriber ->
databaseReference
.child("friend_requests")
.child(friend_uid)
.child(uid)
.child("request_type")
.setValue("received")
.addOnCompleteListener { task ->
if (task.isSuccessful) {
if (!subscriber.isDisposed) {
subscriber.onSuccess("sent")
}
} else {
subscriber.onError(Throwable("request failed"))
}
}
}.subscribeOn(Schedulers.io())
}.doOnNext {
suggestedFriendController.updateSuggestedFriendAsync(friend_uid, "Yes")
}.subscribe({ t1: String? ->
realm.refresh()
showMessage(t1)
addFriend.text = "Delete Request"
addFriend.isEnabled = true
}, { t2 ->
showMessage(t2.message)
})
compositeDisposable.add(d)
}
override fun onBackPressed() {
super.onBackPressed()
finish()
}
override fun onStop() {
super.onStop()
compositeDisposable.clear()
}
override fun onDestroy() {
super.onDestroy()
suggestedFriend.removeAllChangeListeners()
realm.close()
}
}
}