I am having a small issue, when i comment out the binding.setData(dataContainer); in onChanged while observing Livedata in my Activity, I am not able to update the UI, when I uncomment it, the UI is updated. Please guide and do a little code review if you feel the need.
I am having a Runnable that runs repeatedly after every x seconds. This is made Livedata which I observe in my Activity.
Thanks.
public class MainActivity extends AppCompatActivity {
TextOnScreen dataContainer;
ActivityMainBinding binding;
ViewModelClass modelClass;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
modelClass = ViewModelProviders.of(this).get(ViewModelClass.class);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
dataContainer = new TextOnScreen("hello");
binding.setData(dataContainer);
modelClass.getLiveData().observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
Log.e("TAG", "--onChanged--" + s);
dataContainer.onscreen.set(s);
// this line allows the textview to update
// other wise no change on UI is seen
binding.setData(dataContainer);
}
});
}
}
public class TextOnScreen {
public final ObservableField<String> onscreen=new ObservableField<>();
public TextOnScreen(String t) {
onscreen.set(t);
}
public String getOnscreen() {
return onscreen.get();
}
public void setOnscreen(String onscreen) {
this.onscreen.set(onscreen);
}
}
public class ViewModelClass extends ViewModel{
private MutableLiveData<String> liveData;
public ViewModelClass() {
ModelClass modelClass = new ModelClass();
liveData= modelClass.generateName();
}
public LiveData<String> getLiveData() {
return liveData;
}
}
public class ModelClass {
MutableLiveData<String > data =new MutableLiveData<>();
MutableLiveData<String> generateName(){
final android.os.Handler handler=new android.os.Handler();
Runnable runnable=new Runnable() {
@Override
public void run() {
data.setValue(data.getValue()+"*");
handler.postDelayed(this,1000);
}
};
handler.postDelayed(runnable,2000);
return data;
}
}
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="data"
type="dsfa.drish.com.livedatasample.TextOnScreen"/>
</data>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{data.onscreen}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
</layout>
Don't worry, LiveData is not going to be deprecated.
No, It is not mandatory to use LiveData always inside ViewModel, it is just an observable pattern to inform the caller about updates in data. If you have something which won't be changed frequently and can be accessed by its instance.
For me it was just missing:
binding.setLifecycleOwner(this);
I could achieve the same desired result, while maintaining most of your code, by removing TextOnScreen and modifying MainActivity to:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewModelClass modelClass = ViewModelProviders.of(this).get(ViewModelClass.class);
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setData(modelClass); // <-- set the ViewModel to be binded
binding.setLifecycleOwner(this); // <-- this enables MutableLiveData to be update on your UI
modelClass.getLiveData().setValue("hello");
modelClass.getLiveData().observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
Log.e("TAG", "--onChanged--" + s);
}
});
}
and on your activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="data"
type="com.rafaelfukuda.stackoverflow.ViewModelClass"/>
</data>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{data.liveData}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
</layout>
Other code improvements:
I would keep my models very simple (POJO with no MutableLiveData properties) and move the generateName to the ViewModel. That would maintain a proper MVVM structure and it will be very easy to understand and extend your code in the future.
Result:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With