Android lazy data binding possible? - android

One of the coolest features of the Android data binding support is that it also generates fields for View with IDs set. This tidies up the codebase as no field or findViewById() calls are necessary.
But the problem is that the binding instance can only be retrieved via the bind() call which tends to schedule binding. This is bad when the data is being received asynchronously and commonly the NullPointerException gets thrown.
Can the binding instance with View fields be retrieved minus the actual data binding process?
Stack-trace:
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.Boolean.booleanValue()' on a null object reference
at com.app.android.databinding.ActivityRestaurantDetailsBinding.executeBindings(ActivityRestaurantDetailsBinding.java:381)
at android.databinding.ViewDataBinding.executePendingBindings(ViewDataBinding.java:350)
at android.databinding.ViewDataBinding$6.run(ViewDataBinding.java:167)
at android.databinding.ViewDataBinding$5.onViewAttachedToWindow(ViewDataBinding.java:137)
at android.view.View.dispatchAttachedToWindow(View.java:14525)

This doesn't seem to make sense, data binding will ignore null variables thus no null pointer should be thrown, that is, i believe, one of its most promoted features. If you need to modify variables after async calls etc you can just use dataBinding.executePendingBindings()
From the docs
The generated binding class will have a setter and getter for each of the described variables. The variables will take the default Java values until the setter is called — null for reference types, 0 for int, false for boolean, etc.
and
Generated data binding code automatically checks for nulls and avoid null pointer exceptions. For example, in the expression #{user.name}, if user is null, user.name will be assigned its default value (null). If you were referencing user.age, where age is an int, then it would default to 0.

Got the same problem with java.lang.Boolean. Solved by using primitive boolean type instead.
<variable
name="var"
type="boolean" />

Related

Is 'it' automatically smart cast internally? [duplicate]

This question already has answers here:
Smart cast to 'Type' is impossible, because 'variable' is a mutable property that could have been changed by this time
(12 answers)
Closed 1 year ago.
I am studying Android and I am also studying Kotlin.
While writing Android code, I was curious about using it in a let function.
MainActivity.kt
class MainActivity : AppCompatActivity() {
private var curFrag: Fragment? = null
curFrag = fm.primaryNavigationFragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// curFrag?.let { transaction.hide(curFrag) } // error.
curFrag?.let { transaction.hide(it) }
}
}
ERROR
Smart cast to 'Fragment' is impossible, because 'curFrag' is a mutable property that could have been changed by this time
In the lambda expression of let(), T is curFrag and the type is Fragment? is.
And T(curFrag) can be replaced by it.
But the moment I used curFrag instead of it, the IDE displayed an error message.
Later, when I checked the type of it, it was Fragment? It was not a Fragment type.
Honestly, I don't understand well.
I don't know why it is automatically smart cast and should only be used for immutable variables.
Kotlin is a null safe language, it tries to eliminate every possible null references from the code. You can perform a nullability check on the variable and then can use it like this
if(curfrag != null) { transaction.hide(curFrag)
This too will only work if variable curfrag is immutable (that means a local variable which is not modified between the check and the usage or a member val which has a backing field and is not overridable), because otherwise it might happen that curfrag changes to null after the check from some other thread.
But Safe calls ?. with let always gives us non nullable result, what Safe calls operator ?. does is, it only performs any operation following it, only if the variable is not-null otherwise it returns null.
It works with all mutable types or member var, It check for the null once and then provides the result. If value is non null it performs the defined operation otherwise skips it. it refers to the copy of that non-null value.
So when you do this
curFrag?.let { transaction.hide(curFrag) }
curFrag can be null as you are directly passing a nullable value.
But in this case
curFrag?.let { transaction.hide(it) }
it only passes value if it's a non-null value.
The let function basically creates a new variable with the same value as whatever you called it on, so it is not really smart-casting the original property.
If you use ?.let, let isn't even called if the value was null. The safe call means the receiver let is being called on is not a nullable value to begin with because otherwise let isn't called at all. The it inside let is just a reference to what it was called on.
Effectively, though it is conceptually similar to smart-casting. There is not really a way to write equivalent Kotlin code that does what ?.let is doing because the ?. safe call is a special operator that has no expanded form.

Purpose of with & without underscore variable view binding

What is the purpose of defining 2 variable in this tutorial? Why don't we use 1 variable instead and accessing view with it?
https://developer.android.com/topic/libraries/view-binding#usage
The getter on the second variable (binding) uses the !! operator to assert that the variable is non-null when accessed.
Essentially the backing field (_binding) is nullable in order to represent the state before onCreateView and after onDestroyView whereas the getter provides an easy way to access the field without scattering null checks or assertions elsewhere in your code.

Only safe or non null assserted calls are allowed on a nullable receiver type of arraylist

Just started using kotlin for android development.My arraylist is declared like this-
var day1: ArrayList<DietPlanDetailModel>? = null
Now I am trying to access an element by its position
val dietPlan= day1[position]
but i am getting below compile time error-
Only safe or non null assserted calls are allowed on a nullable
receiver type of arraylist
Why am i getting this error and how can i resolve it?
The problem is, that you defined the ArrayList as nullable. You have two options here:
don't define the variable nullable (this depends on your code):
var day1: ArrayList<DietPlanDetailModel> = ArrayList()
access your data-structure with a null check:
val dietPlan= day1?.get(position)
As defined, day1 can be null but you're invoking a function by doing [], which is basically the same as calling day1.get(index).
This can throw a NullpointerException, which the Kotlin compiler tries to prevend. Thus, only safe calls like this are allowed: day1?.get().
You told compiler that your variable can be null (and assigned null to it).
day1[position] is essentially day1.get(position) which will crash with NPE if day1 is null -> null.get(position)
If you can guarantee that day1 will be initialized id recommend lateinit or just straight up assigning new Arraylist with declaration. Of course, simple day1?.get(position) works fine.

Realm - Skip writing nested objects programatically

I have seen the use of #Ignore for certain fields but I’m looking for something slightly different. https://realm.io/docs/java/latest/#models
Is it possible to specify skipping a nested object when writing a parent object to realm?
The reason for this:
I have a complex JSON object which I’m parsing and then saving to my Realm.
This object can get really large so there is some optimisation on my backend to return:
A complete object
A preview object
At some points I get a preview user object which returns only a subset of fields.
When saving to realm this overwrites the complete object (as expected) and wipes the fields not present.
The problem is that I still need those wiped fields later on.
You are not using the JSON support of Realm? If so you can use this, see last item (my emphasis):
Parsing JSON with Realm is subject to the following rules.
Creating object with JSON which has the field with a null value:
For a not-required field, set it to null which is the default value.
For a required field, throw an exception.
Updating object with JSON which has the field with a null value:
For a not-required field, set it to null.
For a required field, throw an exception.
JSON doesn’t have the field: Leave the value unchanged for both required and not-required fields.
Source:
https://realm.io/docs/java/latest/#json

What is mId in activeandroid and when can it be null?

I am creating and trying to save a table using active android but for some reason the object fails to save. The error that I get is
java.lang.NullPointerException: Attempt to invoke virtual method 'long java.lang.Long.longValue()' on a null object reference
Upon debugging the decompiled Model.class file I observed that an exception occurs while executing the following statement
(Please note that the below line is from the decompiled Model.class file of activeandroid)
long entityId1 = ((Model)e).getId().longValue();
It fails and the above said exception occurs. In the catch block I observe that for all non-primitive type fields the mId is non null, but for the field where the exception occurs the mId is null. I tried to search the web but could only find one line about mId.
ActiveAndroid automatically creates another auto-increment ID column. This is mId.
Then why does it fail to do so in this case. Does somebody have an idea? Thanks !!
OK I found the answer.
From codepath I found that
The problem is that This is because ActiveAndroid needs you to save
all objects separately. Before saving a tweet for example, be sure to
save the associated user object first. So when you have a tweet that
references a user be sure to user.save() before you call tweet.save()
since storing the user requires the local id to be set and assigned as
the foreign key for the tweet.
Thus I had to save my non primitive type object field first before saving the object.

Categories

Resources