Return null from fun in kotlin - android

I've written a function to perform a database query. I want it to return null if it cannot fetch any result.
fun getServiceCharge(model: String): ServiceChargeMasterList {
val unique = VideoconApplication.daoSession.serviceChargeMasterListDao.queryBuilder().where(ServiceChargeMasterListDao.Properties.ModelCategory.eq(model)).unique()
if (unique != null)
return unique
else
return null!!
}
It gives me kotlin.KotlinNullPointerException.
Can anyone tell me how can I solve this?

Just specify your return type as ServiceChargeMasterList? and return null. The !! operator is very ugly to use.
You don't even have to use that if statement if your unique() method return and optional (or Java object). In that case, you method could look like this:
fun getServiceCharge(model: String): ServiceChargeMasterList? {
return VideoconApplication.daoSession.serviceChargeMasterListDao.queryBuilder().where(ServiceChargeMasterListDao.Properties.ModelCategory.eq(model)).unique()
}

Use this
fun getServiceCharge(model: String): ServiceChargeMasterList? =
VideoconApplication.
daoSession.
serviceChargeMasterListDao.
queryBuilder().
where(ServiceChargeMasterListDao.Properties.ModelCategory.eq(model)).
unique()
Explanation
In Kotlin, there are optional types. If you return ServiceChargeMasterList, you say to the compiler that you will never return null. If you want to return null, you have to add ? sign at the end of the type which indicates that you can return an instance of ServiceChargeMasterList or null.
The operator !! can be explained in Java as
//Kotlin
variable!!
//Java
if (variable == null)
throw new kotlin.NullPointerException();

Your method’s return type does not allow null to be returned. You need to change it to it’s nullable versionServiceChargeMasterList? (nullability denoted by the question mark).
The not-null assertion operator !! should only be used in very rare cases because it tries to transform nullable types into non-nullable types and might throw a NullPointerException when invoked on null.
Your code null!! is the perfect demonstration for this.
Instead of applying safe operators like in nullableVar?.foo(), this operator is used like this: nullableVar!!.foo().
In your case though, the !! operator is the wrong choice. If your method is really supposed to return null, change the return type.

open fun getProfile() : ProfileModel? {
if (MyApplication.sharedPreference.getString("profile","")!=null){
var profileModel : ProfileModel = Profile()
return profileModel
}
return null
}
add ? after your return type then return null it works

Related

How To Return Nested Variable?

I don't know how to RETURN variable from the following function.
Here is the code...
downloadData.setOnClickListener {
val handler = Handler(Looper.getMainLooper())
handler.post {
val fetchData =
FetchData("http://localhost/xampp/CRM/PHP/show_contacts_db.php")
if (fetchData.startFetch()) {
if (fetchData.onComplete()) {
val result = fetchData.data.toString()
Log.i("FetchData", result)
val companyName = result.substringAfter("Name: ").substringBefore(";")
showContactName.text = "${companyName}"
val companyNumber = result.substringAfter("Number: ").substringBefore(";")
showContactNumber.text = "${companyNumber}"
}
}
}
}
companyName and companyNumber needed to be returned so I can use it in other places.
When I Try to use Return companyNumber I have a message that "return" is not allowed here.
Generally with lambdas, you don't explicitly return a value - the lambda returns the value of the last expression. Using your code as an example (it won't actually work but we'll get to that!):
handler.post {
...
companyNumber
}
which is the same as how things like map calls take a transformation function
listOf(1, 2, 3).map { it * 2 }
that's just doubling each number, but the result is being implicitly returned and stored in the resulting list, right? And it lets you chain lambdas together, since each one evaluates to a value (which might be Unit if it "doesn't return a result")
If you want, you can explicitly use what's called a qualified return:
handler.post {
...
return#post companyNumber
}
where you're naming the function call you're returning to.
Kotlin docs: returning a value from a lambda expression
Also if you want to return two values, you can't do that - so you'll have to bundle them up in a single object. You could just return a Pair, or create a data class that's more readable:
return#post Pair(companyName, companyNumber)
//or
data class CompanyDeets(val name: String, val number: String)
...
return#post CompanyDeets(companyName, companyNumber)
But aside from how you do it in general, why do you want to return anything here? Handler#post takes a Runnable which returns nothing (void in Java), and View.OnClickListener#onClick doesn't return anything either.
Neither of them would do anything with a value you returned - and if you explicitly return a value, that means your lambda's signature doesn't match (right now it's implicitly returning Unit to match what's expected by the caller), and you'll get an error
What you probably want to do instead, is create a function inside your class (Activity or whatever) that uses your data, something like fun doSomethingWith(companyName: String, companyNumber: String) and call that inside your lambda. That's way you're executing code in reaction to a click
just declare var Company Name in global, or create a function with that params
var companyName: String? = null
handler.post {
...
companyName = result.substringAfter("Name: ").substringBefore(";")
}
OR
handler.post {
...
save(result.substringAfter("Name: ").substringBefore(";"))
}
fun save(companyName: String){ ... }

Get Enum type by mapping Enum value always complain null issue Android Kotlin

I have enum class and I am mapping by value, when I am return Enum value it always complain about null issue.
ConversationStatus.kt
enum class ConversationStatus(val status: String) {
OPEN("open"),
CLOSED("closed");
companion object {
private val mapByStatus = values().associateBy(ConversationStatus::status)
fun fromType(status: String): ConversationStatus {
return mapByStatus[status]
}
}
}
This always complain this issue. How can I fix this? Any recommendation for that. Thanks
There's 3 possible ways to go to.
Android Studio is often good at suggested fixes as you can see in the screenshot. It suggests to change the return type to ConversationStatus? which means it might return null. It will become this then:
companion object {
private val mapByStatus = values().associateBy(ConversationStatus::status)
fun fromType(status: String): ConversationStatus? {
return mapByStatus[status]
}
}
Another way is to tell the compiler that you ensure it will always not be null by adding !! to the return statement. Like this:
companion object {
private val mapByStatus = values().associateBy(ConversationStatus::status)
fun fromType(status: String): ConversationStatus {
return mapByStatus[status]!!
}
}
This will cause a crash though if you call the function with a status that's not "open" or "closed"
Alternatively you could provide a fall back value. With this I mean that it returns a default value in case you call the function with a string that's not "open" or "closed". If you want that to be OPEN you could do like this:
companion object {
private val mapByStatus = values().associateBy(ConversationStatus::status)
fun fromType(status: String): ConversationStatus {
return mapByStatus[status] ?: OPEN
}
}

What does Room return if a query had no results

Having a difficult time finding this answer and the documentation doesn't seem to answer the question.
If I have a basic ROOM query,
#Query("SELECT * FROM geotable WHERE geohash = :geohash")
abstract suspend fun getGeoTable(geohash: String) : GeoTable
and there is no such item that uses this primary key, what happens? Android studio says that the DAO object will never return a null. It seems that EmptyResultSetException only gets thrown when you have Single using RxJava which I am not using. So what does plain old ROOM throw when it finds nothing?
Based on the documentation a fruitless query's behavior is defined by the declared return type:
fun func(foo: Foo): Bar would throw a EmptyResultSetException
fun func(foo: Foo): Bar? would return null
fun func(foo: Foo): List<Bar> would return an empty list
If nothing is found based on your criteria, it will return null.
By looking at how Daos code is generated in the respective *Dao_Impl, your Daos implementation should be contain something similar:-
final GeoTable result;
if(_cursor.moveToFirst()) {
....
}else {
_result = null;
}
return _result;
}
So if there are no records in the cursors result set, the _cursor.moveToFirst() should return false and eventually result in returning a null.
if there are no results
it returns nothing simply
and nothing happens

How do I initialize a collection value for a MutableLiveData object?

class Foo : ViewModel() {
val bars: MutableLiveData<ArrayList<Bar>> = MutableLiveData()
get() {
if(field.value == null) {
field.setValue(ArrayList()) // NullPointerException
}
}
}
class FooTest(){
#Test fun itShouldNotBlowUp() {
Foo() //nullPointerException
}
}
I don't understand how to initialize the value of a MutableLiveData object. I've tried to lazily initialize it via the getter and with an init block. Both approaches throw a null pointer when setting the value. bars is not null however.
Here is the stacktrace:
java.lang.NullPointerException
at android.arch.core.executor.DefaultTaskExecutor.isMainThread(DefaultTaskExecutor.java:58)
at android.arch.core.executor.ArchTaskExecutor.isMainThread(ArchTaskExecutor.java:116)
at android.arch.lifecycle.LiveData.assertMainThread(LiveData.java:434)
at android.arch.lifecycle.LiveData.setValue(LiveData.java:279)
at android.arch.lifecycle.MutableLiveData.setValue(MutableLiveData.java:33)
at org.Foo.<init>(Foo.kt:10)
at org.FooTest.ShouldNotBlowUp(FooTest.kt:3)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
How do I initialize the ArrayList and set it as the value of bars?
Maybe the reason is that you are trying to run this in the test. Your sample fails in DefaultTaskExecutor.isMainThread(), that looks like this:
public boolean isMainThread() {
return Looper.getMainLooper().getThread() == Thread.currentThread();
}
So Looper.getMainLooper() returns null in the test environment.
And also, have you tried to initialize property via 'lazy' delegate?
val bars: MutableLiveData<List<Bar>> by lazy {
MutableLiveData<List<Bar>>().apply {
value = emptyList()
}
}
That works fine in my case and feels more idiomatic
The answer to the question is: if you want to give it an empty value clearly, but the variable is not null and you can at least use it without breaking the program.
to create a variable:
val myVariable = MutableLiveData<ArrayList<String>>()
Well, now you only have to pass the constructor of the empty list within the type parentheses so that your variable does not remain with a Null value.
val myVariable = MutableLiveData<ArrayList<String>>(arrayListOf())
I know it's an old question but in case it can help someone, it helped me discover this ;)

what does Array<T?> mean

When converting a java code into Kotlin, the
public MayData[] getDataArray() {
return new MayData[0];
}
changed to
fun getDataArray(): Array<MyData> {
return arrayOfNulls<MyData>(0)
}
but I got an error:
Error:(50, 16) Type mismatch: inferred type is Array<MyData?> but Array<MyData> was expected
it has to add the ‘?’
fun getDataArray(): Array<MyData?> {
return arrayOfNulls<MyData>(0)
}
what does the ‘?’ mean with the template type?
arrayOfNulls returns an array of objects, initialized with null values. The '?' means that the object may be null.
return arrayOfNulls<MyData>(0)
What this line means:
arrayOfNulls Return an array of N elements (zero in your case), but fill it with null
<MyData> The Data-Type is MyData, which is NOT nullable
So you create an array with null values (even if the size is zero) but the DataType is not nullable:
Two solutions:
// zero elements in the array but not nullable
fun getDataArray(): Array<MyData> {
return arrayOf()
}
// array with nullable data-type
fun getDataArray(): Array<MyData?> {
return arrayOfNulls<MyData?>(0)
}
T is a generic. ? marks a type as nullable. In Kotlin you make a distinction between types that can be null, and those that cannot.
Since in Java all types except the atomic ones (int, long, float...) can be null you need to add the ? operator to deal with this case as well.
You need to know that In Kotlin every class can be used in two variants: a nullable and a non-nullable one. For example, the class String can be used for the String or the String? type, the former one meaning "not null" and the latter one meaning "nullable".
The <> chars introduce a "generic type", e.g. for an Array<String> this means, that this Array can only hold objects of type String, whereas Array<String?> means it can hold instances of String and null on top of that.
As your making use of arrayOfNulls the function's return type will be Array<MyData?>, which is why the compiler complains:
inferred type is Array but Array was expected
Blockquote
In order to fix that, you can either make your function return the nullable version, like you already did or you do not use arrayOfNulls, when you're sure you don't want to include nulls in your array.
fun getDataArray(): Array<MyData?> {
return arrayOfNulls<MyData>(0)
}
or
fun getDataArray(): Array<MyData> {
return arrayOf<MyData>()
}

Categories

Resources