parse-community / Parse-SDK-Android

The Android SDK for Parse Platform
https://parseplatform.org/
Other
1.88k stars 734 forks source link

ParseUser.findInBackGround.result throws NullPointerException, even if the Query exists #1043

Closed Berki2021 closed 4 years ago

Berki2021 commented 4 years ago

Hello,

I am trying to search my user database for a specific key e.g. name here. The problem is that findInBackground throws a NullPointerException even if the user exists AND the specific key is found. Using find or first works but blocks the main thread.

Here is my code: fun checkNameExistsNullPointer(value: Any) = ParseUser.getQuery().whereEqualTo("username", "User1").findInBackground().result.isNullOrEmpty()

fun checkNameExistsWorksBlocking(value: Any) = !ParseUser.getQuery().whereEqualTo("username", "User1").find().isNullOrEmpty()

Jawnnypoo commented 4 years ago

That is because the bolts Task has not completed yet when you do findInBackground, therefore there is no result at the time that you are calling it. You would have to do something like findInBackground with a continuation to see the results. For example:

ParseUser.getQuery().whereEqualTo("username", "User1").findInBackground().continueWithTask { 
   if (it.result.isNullOrEmpty())
       doSomething()
   if (it.isFaulted()) 
       doSomethingForTheError()
}
Berki2021 commented 4 years ago
fun checkNameExistsNullPointer(value: Any) {
    ParseUser.getQuery().whereEqualTo("username", "value").findInBackground().continueWithTask {
        return@continueWithTask it.result.isNullOrEmpty()
    }
}

Error:

Type mismatch. Required: ((Task<(Mutable)List<ParseUser!>!>!) → Task<(???..???)>!)! Found: (Task<(Mutable)List<ParseUser!>!>!) → Boolean

Jawnnypoo commented 4 years ago

You cannot return@continueWithTask the boolean, since it is expecting a Task. You'll want to read more about Bolts tasks and how they work here: https://github.com/BoltsFramework/Bolts-Android

Berki2021 commented 4 years ago

Okay I will, but couldn't you provide me the answer?

EDIT: Ok, I got it:

` fun checkEmailExistsAsync(value: Any): Boolean {

    val result = ParseUser.getQuery().whereEqualTo("email", value).findInBackground().continueWith {
        return@continueWith it.result

    }.result

    return result.isNullOrEmpty()
} `
Jawnnypoo commented 4 years ago

This comment https://github.com/parse-community/Parse-SDK-Android/issues/1043#issuecomment-654349191 provides the answer you need. You cannot call async code, ie. a bolts task like this and expect it to return a synchronous result. You either need to change it to be fun checkEmailExistsAsync(value: Any): Task<Boolean> and transform the task from a list of users to the boolean you want, or you need to do the background threading yourself and use find instead of findInBackground.

Berki2021 commented 4 years ago

Hmm okay, thanks.

Berki2021 commented 4 years ago

@Jawnnypoo I have another question. Couldn't I write a cloud function which checks, if the email aka user already exists and call this cloud function asynchronously within android?

Jawnnypoo commented 4 years ago

Yes, that would be a good solution. Something like this:

            val params = mutableMapOf<String, Any>()
            params["email"] = value
            ParseCloud.callFunctionInBackground<Boolean>("checkEmailExists", params) {
                  doSomethingBasedOnResult()
            }
Berki2021 commented 4 years ago

Amazing, thank you very much. Using a cloud function will give me the ability to call it from ios as well