Kotlin Firebase Realtime database transaction errors - android

I have the following code
database.child("users").child(this.invitedBy).runTransaction(object : Transaction.Handler {
override fun doTransaction(mutableData: MutableData): Transaction.Result {
val u = mutableData.getValue(User::class.java)
?: return Transaction.success(mutableData)
if (u.numReferrals == null || u.referralEarning == null) {
// Unstar the post and remove self from stars
u.numReferrals = 1
u.referralEarning = 1;
} else {
// Star the post and add self to stars
u.numReferrals = u.numReferrals!! + 1
u.referralEarning = u.referralEarning!! + 1;
}
// Set value and report transaction success
mutableData.value = u
return Transaction.success(mutableData)
}
override fun onComplete(
databaseError: DatabaseError?,
committed: Boolean,
currentData: DataSnapshot?
) {
// Transaction completed
Log.d("MUser", "postTransaction:onComplete:" + databaseError!!)
}
})
When I run it, it gives me the following error:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.test.test, PID: 5375
kotlin.KotlinNullPointerException
at com.test.test.MUser$setReferral$1.onComplete(MUser.kt:229)
at com.google.firebase.database.core.Repo$16$1.run(com.google.firebase:firebase-database##19.2.1:1006)
at android.os.Handler.handleCallback(Handler.java:907)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7478)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:549)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941)
W/System.err: kotlin.KotlinNullPointerException
W/System.err: at com.test.test.MUser$setReferral$1.onComplete(MUser.kt:229)
at com.google.firebase.database.core.Repo$16$1.run(com.google.firebase:firebase-database##19.2.1:1006)
at android.os.Handler.handleCallback(Handler.java:907)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7478)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:549)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941)
Here's my User.kt
import com.google.firebase.database.IgnoreExtraProperties
// [START rtdb_user_class]
#IgnoreExtraProperties
data class User(
var id: String = "",
var name: String = "",
var email: String = "",
var userReads: Int? = 0,
var userPlays: Int? = 0,
var userWatches: Int? = 0,
var paidDate : Int? = 0,
var endPaidDate : Int? = 0,
var paidStatus : String? = "",
var paymentMethod : String? = "",
var planid : String? = "",
var firebaseUid : String? = "",
var referralEarning : Int? = 0,
var numReferrals : Int? = 0
)
What am I doing wrong?

Please take a look at onComplete method:
override fun onComplete(
databaseError: DatabaseError?,
committed: Boolean,
currentData: DataSnapshot?
) {
// Transaction completed
Log.d("MUser", "postTransaction:onComplete:" + databaseError!!)
}
You are using !! operator when referencing databaseError parameter, but it can be null, so you can't use !!. To avoid that Exception just remove !! operator:
Log.d("MUser", "postTransaction:onComplete:" + databaseError)
databaseError: DatabaseError? - it is a nullable object (nullable objects marked with ? operator), you can't use !! operator on it if you are not 100% sure that it is not null.
Also you can use ? operator on nullable objects to call its methods or properties, e.g.:
Log.d("MUser", "postTransaction:onComplete:" + databaseError?.getMessage())
More info about Null Safety in Kotlin.

Related

Why i can't update a realmObject that has a realmList inside it ? (I get an error)

I want to update a RealmObject that contains RealmList and I faced this error : (look at the images)
So why I faced this error? and what's the solution?
Also why RealmObject has duplicate parameters (image 2)
My code and the error are below
InvoiceModel :
open class PurchaseDatabase : RealmObject {
#PrimaryKey
var id: Int? = 0
var date: String? = ""
var supplier: String? = ""
var products: RealmList<ProductBuyModel> = realmListOf()
var totalPrice: Int? = 0
var paymentMethod: String? = ""
var paymentPrice: Int? = 0
var restPrice: Int? = 0
}
Error :
FATAL EXCEPTION: main
Process: com.bakirdev.gestiondestock, PID: 9705
java.lang.IllegalArgumentException: Cannot import an outdated object. Use findLatest(object) to find an
up-to-date version of the object in the given context before importing it.
at io.realm.kotlin.internal.RealmObjectListOperator.insert(RealmListInternal.k:370)
at io.realm.kotlin.internal.ListOperator$DefaultImpls.insertAll(RealmListInternal.kt:202)
at io.realm.kotlin.internal.BaseRealmObjectListOperator.insertAll(RealmListInternal.kt:258)
at com.bakirdev.gestiondestock.ui.purchases.PurchaseDatabase.setProducts(PurchaseDatabase.kt:150)
at com.bakirdev.gestiondestock.ui.purchases.AddNewInvoice$initListenerEdit$2$1.invoke(AddNewInvoice.kt:168)
at com.bakirdev.gestiondestock.ui.purchases.AddNewInvoice$initListenerEdit$2$1.invoke(AddNewInvoice.kt:162)
at io.realm.kotlin.internal.SuspendableWriter$write$2.invokeSuspend(SuspendableWriter.kt:109)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:236)
at android.os.HandlerThread.run(HandlerThread.java:67)
My Code :
var invoiceModel: PurchaseDatabase? = purchasesList[position]
realm.writeBlocking {
// fetch a frog from the realm by primary key
invoiceModel = this.query<PurchaseDatabase>("id == ${model.id}").first().find()
// modify the frog's age in the write transaction to persist the new age to the realm
invoiceModel?.supplier = purchasesSupplier
invoiceModel?.products?.clear()
invoiceModel?.products = products
invoiceModel?.totalPrice = totalPrice
invoiceModel?.paymentMethod = paymentMethod
invoiceModel?.paymentPrice = purchasesPaymentPrice.trim().toInt()
invoiceModel?.restPrice = purchasesRestPrice.trim().toInt()
}
Purchases.invoiceModel = invoiceModel
val returnedValue = Intent().apply {
putExtra("position", position)
}
setResult(RESULT_OK, returnedValue)
finish()

FlexboxLayoutManager throw an indexOutOfBoundException

We have a RecyclerView with a FlexboxLayoutManager witch throw an IndexOutOfBound on each scroll of the recyclerView.
FlexBox version: 2.0.1
Kotlin version: 1.4.30
Our code
C = EbookFlexController(this)
B.recycler.setItemViewCacheSize(10)
C.adapter.hasStableIds()
B.recycler.adapter = C.adapter
B.recycler.layoutManager = getFlexLayoutManager()
C represents the FlexBoxController
class FlexController(private val callbacks: Callbacks) : TypedEpoxyController<StreamCluster?>() {
interface Callbacks {
fun onAppClick(app: AppItem)
fun onAppLongClick(app: AppItem)
}
override fun buildModels(streamCluster: StreamCluster?) {
if (streamCluster == null) {
for (i in 1..8) {
add(
AppViewShimmerModel_()
.id(i)
)
}
} else {
streamCluster.appList.forEach { app ->
add(
AppViewModel_()
.id(app.packageName)
.click { _ ->
callbacks.onAppClick(app)
}
.longClick { _ ->
callbacks.onAppLongClick(app)
false
}
.app(app)
)
}
}
}
}
The stream Cluster
data class EbookStreamCluster(val id: String = UUID.randomUUID().toString()) {
var title: String = String()
var subtitle: String = String()
var category: String = String()
var url: String = String()
var ebookList: MutableList<EbookItem> = ArrayList()
var hasNext: Boolean = false
var isPaid:Boolean = false
var page: Int = 0
var type: Type = Type.CLUSTER
}
On firebase, we have this error:
Process: com.gara.store, PID: 3655
java.lang.IndexOutOfBoundsException: Index: 18, Size: 18
at java.util.ArrayList.get(ArrayList.java:437)
at com.google.android.flexbox.FlexboxLayoutManager.recycleFlexLinesFromStart(FlexboxLayoutManager.java:1335)
at com.google.android.flexbox.FlexboxLayoutManager.recycleByLayoutState(FlexboxLayoutManager.java:1315)
at com.google.android.flexbox.FlexboxLayoutManager.fill(FlexboxLayoutManager.java:1302)
at com.google.android.flexbox.FlexboxLayoutManager.handleScrollingMainOrientation(FlexboxLayoutManager.java:1974)
at com.google.android.flexbox.FlexboxLayoutManager.scrollVerticallyBy(FlexboxLayoutManager.java:1935)
at androidx.recyclerview.widget.RecyclerView.scrollStep(RecyclerView.java:1972)
at androidx.recyclerview.widget.RecyclerView$ViewFlinger.run(RecyclerView.java:5476)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1037)
at android.view.Choreographer.doCallbacks(Choreographer.java:845)
at android.view.Choreographer.doFrame(Choreographer.java:775)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1022)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7870)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
The same lib is used somewhere in the app and works without bugs. We don't know why with the exact same code, it is not working.
Please how could we do ?
Thanks

The On Success Listener for query.get() won't execute properly. The code returns an error saying that the load has not been initialized

So, my roommate and I are trying to develop an app to help students living on campus at our school keep track of their laundry. However, we are having trouble creating new laundry loads.
Our addLoad function is supposed to add a LaundryHolder object to Firebase (containing the machine number, whether it is a washer or dryer, who owns the load, and how many seconds are left for the load), whereas the LaundryLoad object contains a LaundryHolder, observer function (notifyDataSetChanged() for the LaundryLoadFragment), and timer (with time form LaundryHolder).
In Firebase, each clothingItem has a load ID with which to identify which load it is in on the user side. For our implementation to work, we need to fetch the ID which Firebase gives our LaundryHolder, which is why we are adding an onSuccessListener to a temporary query. The issue arises, however, when the query doesn't succeed or fail, and we can't figure out what is going on here.
This is the error we get:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: edu.rosehulman.roselaundrytracker, PID: 11847
kotlin.UninitializedPropertyAccessException: lateinit property load has not been initialized
at edu.rosehulman.roselaundrytracker.model.LaundryLoadViewModel.addLoad(LaundryLoadViewModel.kt:42)
at edu.rosehulman.roselaundrytracker.adapter.AddLoadAdapter.addLoad(AddLoadAdapter.kt:67)
at edu.rosehulman.roselaundrytracker.fragment.AddLoadFragment.onCreateView$lambda-1(AddLoadFragment.kt:32)
at edu.rosehulman.roselaundrytracker.fragment.AddLoadFragment.$r8$lambda$lIyFvxsLH_bCt-kHzadMjy2Ls_Y(Unknown Source:0)
at edu.rosehulman.roselaundrytracker.fragment.AddLoadFragment$$ExternalSyntheticLambda0.onClick(Unknown Source:2)
at android.view.View.performClick(View.java:7455)
at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1119)
at android.view.View.performClickInternal(View.java:7432)
at android.view.View.access$3700(View.java:835)
at android.view.View$PerformClick.run(View.java:28810)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7842)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
Does anyone have any idea?
class LaundryLoadViewModel: ViewModel() {
private var loads = ArrayList<LaundryLoad>()
private var curPos = 0
lateinit var ref: CollectionReference
lateinit var uid: String
private var onlyOwned = true
private val subscriptions = HashMap<String, ListenerRegistration>()
fun getPreference() = onlyOwned
fun addLoad(machineNumber: Int, machineType: String, contents: ArrayList<ClothingItem>, time: Long, observer: () -> Unit){
val holder = LaundryHolder(machineNumber, machineType.lowercase(Locale.getDefault()) == "dryer", time * LaundryLoadFragment.SEC_TO_MIN, uid)
// val load = LaundryLoad(holder, observer)
// loads.add(load)
ref.add(holder)
lateinit var load: LaundryLoad
val query = ref
.whereEqualTo("machineNumber",machineNumber)
.whereEqualTo("owner",uid)
query.get().addOnSuccessListener { snapshot ->
snapshot.documents.forEach {
Log.d(Constants.TAG,"Retrieving load from Firebase")
load = LaundryLoad.from(it, observer)
}
}
query.get().addOnFailureListener {
Log.d(Constants.TAG,"Retrieval failed due to $it")
}
// val query = ref.whereEqualTo("machineNumber",machineNumber).whereEqualTo("dryer",machineType.lowercase(Locale.getDefault())=="dryer")
load.addMany(contents)
loads.add(load)
}
fun addListener(fragmentName: String, observer: () -> Unit) {
lateinit var subscription: ListenerRegistration
loads.clear()
val auth = Firebase.auth
val user = auth.currentUser!!
val clothes = ArrayList<ClothingItem>()
uid = user.uid
ref = Firebase.firestore.collection(LaundryLoad.COLLECTION_PATH)
val ref2 = Firebase.firestore.collection(ClothingItem.COLLECTION_PATH)
val inLoadQuery = ref2.whereNotEqualTo("load","")
inLoadQuery.addSnapshotListener { snapshot: QuerySnapshot?, error: FirebaseFirestoreException? ->
error?.let {
Log.d(Constants.TAG, "Error: $it")
return#addSnapshotListener
}
snapshot?.documents?.forEach {
clothes.add(ClothingItem.from(it))
}
}
if(onlyOwned) {
val query = ref.whereEqualTo("owner",uid)
subscription = query
.addSnapshotListener { snapshot: QuerySnapshot?, error: FirebaseFirestoreException? ->
error?.let {
Log.d(Constants.TAG, "Error: $it")
return#addSnapshotListener
}
retrieveLoads(snapshot, clothes, observer)
}
} else {
subscription = ref
.addSnapshotListener { snapshot: QuerySnapshot?, error: FirebaseFirestoreException? ->
error?.let {
Log.d(Constants.TAG, "Error: $it")
return#addSnapshotListener
}
retrieveLoads(snapshot, clothes, observer)
}
}
subscriptions[fragmentName] = subscription
observer()
}
private fun retrieveLoads(snapshot: QuerySnapshot?, clothes: ArrayList<ClothingItem>, observer: () -> Unit) {
snapshot?.documents?.forEach {
loads.add(LaundryLoad.from(it, observer))
}
for (load in loads) {
for (item in clothes) {
if (item.load == load.getId()) {
load.addToLoad(item)
}
}
}
}
fun removeListener(fragmentName: String) {
for(load in loads) {
ref.document(load.getId()).set(load.laundryHolder)
}
subscriptions[fragmentName]?.remove()
subscriptions.remove(fragmentName)
}
fun togglePreference() {
onlyOwned = !onlyOwned
}
}
It looks like ref has not been initialized when you ref.add(holder) in addLoad. It's impossible for us to say why that is, as the code that calls addLoad seems to be missing, but the stack trace should point you pretty directly to where the problem is.

How to extract data from an JsonObject in an android studio project

I'm working on a REST API application in android studio. I want to extract the data from a JsonObject which I saved using the model class when retrieving data using retrofit library. But It shows the below error.
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.covid_19updates, PID: 15236
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 
Caused by: org.json.JSONException: No value for flag
at org.json.JSONObject.get(JSONObject.java:400)
at org.json.JSONObject.getJSONObject(JSONObject.java:620)
at com.example.covid_19updates.MainActivity$onCreate$1.onResponse(MainActivity.kt:52)
at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1.lambda$onResponse$0$DefaultCallAdapterFactory$ExecutorCallbackCall$1(DefaultCallAdapterFactory.java:89)
at retrofit2.-$$Lambda$DefaultCallAdapterFactory$ExecutorCallbackCall$1$hVGjmafRi6VitDIrPNdoFizVAdk.run(Unknown Source:6)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 
The single data object I'm extracting is below:
{"updated":1606563124609,"country":"Afghanistan","countryInfo":{"_id":4,"iso2":"AF","iso3":"AFG","lat":33,"long":65,"flag":"https://disease.sh/assets/img/flags/af.png"},"cases":45966,"todayCases":127,"deaths":1752,"todayDeaths":12,"recovered":36709,"todayRecovered":414,"active":7505,"critical":93,"casesPerOneMillion":1170,"deathsPerOneMillion":45,"tests":146413,"testsPerOneMillion":3727,"population":39280785,"continent":"Asia","oneCasePerPeople":855,"oneDeathPerPeople":22421,"oneTestPerPeople":268,"activePerOneMillion":191.06,"recoveredPerOneMillion":934.53,"criticalPerOneMillion":2.37}
I want to retrieve data inside the countryInfo object. Below is my modal class
data class Covid(
var updated: Long,
var country:String,
var countryInfo:JSONObject,
var cases:Int,
var todayCases:Int,
var deaths:Int,
var todayDeaths:Int,
var recovered:Int,
var todayRecovered:Int,
var active:Int,
var critical:Int,
var casesPerOneMillion:Double,
var deathsPerOneMillion:Double,
var test:Long,
var testPerOneMillion:Double,
var population:Long,
var continent:String,
var oneCasePerPeople:Double,
var oneDeathPerPeople:Double,
var oneTestPerPeople:Double,
var activePerOneMillion:Double,
var recoveredPerOneMilion:Double,
var criticalPerOneMillion:Double
)
And the code piece I wrote to get the data
override fun onResponse(call: Call<List<Covid>>, response: Response<List<Covid>>) {
var list = response.body()
Log.d("Response: ",response.toString())
var countryList = ArrayList<String>()
var countList = ArrayList<String>()
var activeList = ArrayList<String>()
var deathList = ArrayList<String>()
var recoveredList = ArrayList<String>()
var imageList = ArrayList<String>()
list?.map { item ->
countryList.add(item.country.toString())
var totalCases = "Total Cases: "+item.cases.toString()
var activeCases = "Active Cases: "+item.active.toString()
var deaths = "Total Deaths: "+item.deaths.toString()
var recovered = "Total Recovered: "+item.recovered.toString()
var image = item.countryInfo.getJSONObject("flag").toString()
countList.add(totalCases)
activeList.add(activeCases)
deathList.add(deaths)
recoveredList.add(recovered)
}
Try and make a separate data class for CountryInfo.
In covid class
val countryInfo: CountryInfo,
Then
data class CountryInfo(
val _id: Int,
val iso2: String,
val iso3: String,
val lat: Double, //trust me you should use double on latLng values.
val long: Double,
val flag: String
)
Sidenote, you can use this site to automate making kotlin objects from JSONs.

kotlin.TypeCastException: null cannot be cast to non-null type kotlin.collections.Map<kotlin.String, kotlin.Any>

I have searched for an answer that would help my code extensively, but the solutions I have found did not work for me.
I get the following error:
kotlin.TypeCastException: null cannot be cast to non-null
type kotlin.collections.Map<kotlin.String, kotlin.Any>
FATAL EXCEPTION: main
Process: com.meetHitch.HitchApp, PID: 4021
kotlin.TypeCastException: null cannot be cast to non-null
type kotlin.collections.Map<kotlin.String, kotlin.Any>
at ... helpers.RestAPIKt$getUserProfile$1 ...
at com.google.android.gms.tasks.zzj.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main ...
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$Method...
at com.android.internal.os.ZygoteInit.main
My code is the following:
private val TAG: String
get() = "RestAPI"
private val fUser: FirebaseUser?
get() = FirebaseAuth.getInstance().currentUser
private val uid: String?
get() = fUser?.uid
private val baseDoc: DocumentReference
get() = FirebaseFirestore.getInstance().
collection("users").document(uid!!)
private val leadsDoc: DocumentReference
get() {
appUser.currentConference?.id?.let {
return baseDoc.collection("leads").document(it)
}
return baseDoc.collection("leads").document(demoID)
}
private val conferencesCollection: CollectionReference
get() = FirebaseFirestore.getInstance().
collection("conferences")
fun getUserProfile(callback: (AppUser) -> Unit) {
// Source can be CACHE, SERVER, or DEFAULT.
val source = Source.DEFAULT
baseDoc.get(source)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
val document = task.result
if (document != null) {
printnLog(TAG, "Loaded profile for User
with UID: $uid successfully!")
val user = AppUser(task.result.data as
Map<String, Any>)
callback(user)
} else {
println("No profile set. Saving initial
profile...")
appUser = AppUser(fUser!!)
setUserProfile()
}
} else {
Log.w(TAG, "getUser:onCancelled",
task.exception)
}
}
}
I have referred to kotlin.TypeCastException: null cannot be cast to non-null type com.midsizemango.databasekotlin.Note and none of the solutions have worked, although it could be that I am not implementing ? in the right place. I tried "as? Map" but I get a type mismatch error.
With the line val user = AppUser(task.result.data as Map<String, Any>), make the Any variable nullable:
val user = AppUser(task.result.data as Map<String, Any?>)

Categories

Resources