Subho Subho - 2 months ago 18
Java Question

Android Data binding issue Binding adapter call twice

I have simple imageview in my layout and I have a api which gives me a image url. I integrate Data binding in my layout. Now after parsing the api I'm setting the model through this line

binding.setUserinfo(memberObj.getMemberdata());


Now I have also a binding adapter where imgurl code is written. Now the custom binding adapter calls twice when activity start and after parsing the api.

Now i want to notify the UI after api has been successfully parsed.

Here is my code of xml activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data class="MainBinding">
<variable
name="userinfo"
type="com.myapplication.retrofit.pojo.ImgTest"/>
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.myapplication.retrofit.MainActivity">
<ImageView
android:layout_width="250dp"
android:layout_height="250dp"
android:id="@+id/imageView"
app:image_url="@{userinfo.imgUrl}"
/>
</RelativeLayout>
</layout>


Here is my Pojo: ImgTest.java

public class ImgTest extends BaseObservable {

String imgUrl;
@Bindable
public String getImgUrl() {
return imgUrl;
}

public void setImgUrl(String imgUrl) {
this.imgUrl = imgUrl;
notifyPropertyChanged(BR.imgUrl);
}
}


Here is my CustomBinder.java

public class CustomBinders {
private static final String TAG = "CustomBinders";
@BindingAdapter({"image_url"})
public static void loadImageWithOUtProgressBar(ImageView view, String imageUrl){

Log.d(TAG, "before loadImageWithOUtProgressBar: "+imageUrl);
Log.d(TAG, "after loadImageWithOUtProgressBar: "+imageUrl);
Picasso.with(view.getContext())
.load(imageUrl)
.into(view);
}

}


Here is MainActivity.java

public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
RestManager mManager;
MainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
mManager = new RestManager();
Call<ResponseBody> getUserInfo = mManager.getService().getUserInfo("25","sell");
getUserInfo.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
int sc = response.code();
Log.d(TAG, "onResponse: "+sc);

if(response.isSuccessful())
{
ImgTest img = new ImgTest();
try {
String res = response.body().string();
JSONObject jobj = new JSONObject(res);
JSONObject obj = jobj.getJSONObject("memberdata");
String imgUrl = "";
imgUrl = obj.getString("prifile_picture");
img.setImgUrl(imgUrl);
binding.setUserinfo(img);
} catch (Exception e) {
e.printStackTrace();
}
}
}

@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {

}
});
}
}


Please let know how to solve this issue. Thanks in advance.

Answer

As Ravi says in the comments, it is working as intended. After you create the initial binding, the values should be set to the values as they are. If you haven't set anything then they will be set to null.

You can change the behavior by explicitly telling the binding to not bind. Add an OnRebindCallback to the binding:

private OnRebindCallback<ActivityMainBinding> delayRebindCallback = 
        new OnRebindCallback<ActivityMainBinding>() {
    @Override
    public boolean onPreBind(ActivityMainBinding binding) {
        return false;
    }
};

// ... and then after creating the binding ...
binding.addOnRebindCallback(delayRebindCallback);

In your onResponse (assuming it is on the UI thread):

binding.removeOnRebindCallback(delayRebindCallback);
binding.setUserinfo(img);
binding.executePendingBindings();

If it isn't on the UI thread, you will have to post an executable to run the binding.executePendingBindings() on the UI thread.