activity_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="android.view.View" />
<variable
name="callback"
type="com.buscom.ActionCallBack" />
</data>
<LinearLayout xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/ll_oml"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/grey_50"
android:orientation="vertical">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="#{(v) -> callback.onClick(v)}"
android:text="Menu" />
</android.support.design.widget.CoordinatorLayout>
</LinearLayout>
</layout>
ActionCallBack.java
This is the interface I implement in MainActivity
public interface ActionCallback {
void onClick(View view);
}
MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
actionCallBack = new ActionCallBack() {
#Override
public void onClick(View view) {
System.out.println("Call onclick method *****");
}
}
}
When i click on button onClick() method is not evoked, noting is shown in output or no action performed. But is works in the traditional way with onClickListener
I think there is a mistake in your Activity declaration. Anyhow, you are still not setting your callback, as such:
binding.setCallback(this);
or
binding.setCallback(actionCallback);
I solved this issue using this:
binding.setHandlers(this);
I was working in a fragment.
Related
i made a simple hello world for 2 way data binding and seams works perfectly (when write on editext, the textview update automatically), but all code found online like official documentation has much more code and complications like https://developer.android.com/topic/libraries/data-binding/two-way
this is my code:
public class MainActivity extends AppCompatActivity {
public String pippo;
public Boolean visible = true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DataBindingUtil.setContentView(this, R.layout.activity_main);
}
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="pippo"
type="String" />
<variable
name="visible"
type="Boolean" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#={pippo}" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#{pippo}"
android:visibility="#{visible ? android.view.View.VISIBLE: android.view.View.GONE}" />
<CheckBox
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checked="#={visible}" />
</LinearLayout>
</layout>
In particular documentation use this things but seams useless:
BaseObservable
#Bindable
code to Avoids infinite loops
notifyPropertyChanged
so, what wrong or missing with my code?
In the two-way data binding you need to create class that extends from BaseObservable, annotate getters with #Bindable and call notifyPropertyChanged in your setters as below:
public class Person extends BaseObservable {
private String name;
Person(String name) {
this.name = name;
}
#Bindable
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
}
Then pass this class as a databinding layout variable of type Person.
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="person"
type="com.example.android......Person" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#={person.name}" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#{person.name}" />
</LinearLayout>
</layout>
Note: change the class path in the type attribute.
and then set this layout variable in your activity with setPerson()
public class ExampleActivity extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DataBindingUtil.setContentView(this, R.layout.activity_example);
ActivityExampleBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_example);
mActivityMainBinding.setPerson(new Person(""));
}
}
The most simple way to me is using #={variable} instead #{variable}
You can see it in:
https://developer.android.com/topic/libraries/data-binding/two-way
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#={viewModel.name}"
android:inputType="text" />
I have a test project where I want to bind the press of a button to trigger a function via the DataBinding Libray and add:command.
Unfortunately, I'm getting the error:
Found data binding errors.
****/ data binding error ****msg:Could not resolve com.example.ckleineidam.testproject.ViewModel.testButton as an accessor or listener on the attribute.
MainActivity:
public class MainActivity extends AppCompatActivity {
ViewModel mModel;
ActivityMainBinding binding;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
mModel = new ViewModel(this);
binding.setViewModel(mModel);
}
}
ViewModel:
public class ViewModel extends BaseObservable {
private static final String TAG = "VIEW_MODEL";
private Context mActivity;
public ViewModel(Context context) {
this.mActivity=context;
}
public void testButton(){
Log.i(TAG, "Button Click");
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<layout
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"
tools:context=".MainActivity">
<data>
<variable
name="ViewModel"
type="com.example.ckleineidam.testproject.ViewModel" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="title"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/activation_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Test Button"
android:background="?android:attr/selectableItemBackground"
app:command="#{ViewModel.testButton}"
app:layout_constraintTop_toBottomOf="#id/title" />
</android.support.constraint.ConstraintLayout >
</layout>
The code is also as an example project at Github.
You are getting this error because there is no attribute app:command on a button.
If you are trying to achieve an onClick functionality, you can use android:onClick="#{ViewModel.testButton}" and change your function signature to void testButton(View view).
To use custom attributes, you need to define a binding adapter
My question is simple but I can't seem to do what I want to.
So In my activity I have this method.
public void performButtonClick(View view)
{
Log.i("INTRO", "OK");
}
Which is called from a button click event defined in xml like so
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="performButtonClick"
android:text="#string/start"/>
Now I've heard that this approach is using reflection which slows down performance so I'm trying to replace the onClick event with databinding.
I tried various combinations like
android:onClick="#{performButtonClick}"
or
android:onClick="#{(v) -> performButtonClick(v)}"
or
android:onClick="#{(v) -> MainActivity::performButtonClick}"
but None of these worked.
Could you help me out?
Ok answering to my own question.
I am new to DataBinding but I do not understand why I have to use copy-pasted solutions which make use of an accessory Handlers class and end up with more boilerplate code than I used to have.
All I wanted is an equivalent to android:onClick="performButtonClick" So here is my solution:
activity_main.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="activity"
type="com.example.mydatabinding.MainActivity"/>
</data>
<LinearLayout
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/bg"
android:orientation="vertical">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="#{activity::performButtonClick}"
android:text="#string/start"/>
</LinearLayout>
MainActivity.java
public final class MainActivity extends AppCompatActivity
{
ActivityMainBinding binding;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setActivity(this);
}
public void performButtonClick(View view)
{
Log.i("INTRO", "OK");
}
}
I'm trying to handle clickable TextView on data binding method, but i get this error:
Cannot find the setter for attribute 'android:clickable' with parameter type lambda on android.widget.TextView
my TextView widgets must be clickable and i show simple Toast, how can i set text to that such as android:text="#string/my_text and can be clickable?
ActivityRegister:
public class ActivityRegister extends BaseActivities
implements ActivityRegisterContract.View{
private ActivityRegisterBinding binding;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_register);
ActivityRegisterPresenter mainActivityPresenter = new ActivityRegisterPresenter(this);
ActivityRegisterData viewModel = new ActivityRegisterData();
viewModel.setReadContactPermission(Utils.getString(R.string.get_read_contact_permission, context));
binding.setPresenter(mainActivityPresenter);
}
#Override
public void getReadContactsPermission() {
Utils.toast("CLICKED", context);
}
}
presenter:
public class ActivityRegisterPresenter {
private ActivityRegisterContract.View view;
public ActivityRegisterPresenter(ActivityRegisterContract.View mView) {
view = mView;
}
public void getReadContactsPermission(){
view.getReadContactsPermission();
}
}
ActivityRegisterContract
public interface ActivityRegisterContract {
public interface View {
void getReadContactsPermission();
}
}
and then ActivityRegisterData
public class ActivityRegisterData extends BaseObservable {
private String readContactPermission;
public ActivityRegisterData() {
}
#Bindable
public String getReadContactPermission() {
return readContactPermission;
}
public void setReadContactPermission(String readContactPermission) {
this.readContactPermission = readContactPermission;
notifyPropertyChanged(BR.readContactPermission);
}
}
my layout:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:slidingLayer="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="com.example.Ui.Register.Model.ActivityRegisterData"/>
<variable
name="presenter"
type="com.example.Ui.Register.Presenter.ActivityRegisterPresenter"/>
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#d1d1d1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="#+id/permission_for_read_contacts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="#string/permission_for_read_contacts"
android:textColor="#color/white"/>
<TextView
android:layout_width="match_parent"
android:layout_height="#dimen/default_textview_height"
android:background="#drawable/selector_blue_buttons"
android:clickable="#{()->presenter.getReadContactsPermission()}"
android:text="#{viewModel.readContactPermission}"
android:textColor="#color/white"/>
</LinearLayout>
</LinearLayout>
</FrameLayout>
</layout>
problem is for this line on layout:
<TextView
android:layout_width="match_parent"
android:layout_height="#dimen/default_textview_height"
android:background="#drawable/selector_blue_buttons"
android:clickable="#{()->presenter.getReadContactsPermission()}"
android:text="#{viewModel.readContactPermission}"
android:textColor="#color/white"/>
I dont know about your code.but to make a clickable text, you just have to add listener to it or you can define onClick attribute in Xml and define that method in Activity to handle click event.
Use this:
android:onclick="doSomething"
And in activity
public void doSomething(View v){
//Write your code here
}
I am programming an android-App and I am using the MVVM-Pattern. I have problems seeing the data in the layout in my view. I am new to android programming, so maybe i am thinking the wrong way. In C# i had no problems creating an MVVMC-App. To be honest, i do not understand how to show the contents in the layouts in the activity :-(
This is my code in the view:
#Override
protected void onCreate(Bundle savedInstanceState) {
//This is the code which shows the white window with my data
super.onCreate(savedInstanceState);
ContentSelectItemBinding binding = DataBindingUtil.setContentView(this, R.layout.content_select_item);
this.aSelectItemViewModel = new SelectItemViewModel();
binding.setItem(this.aSelectItemViewModel.item);
//when i add this, it will just show the empty view
setContentView(R.layout.activity_select_item);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
And thats how my easy SelectItemViewModel looks like
public TestItem item;
public SelectItemViewModel() {
item = new TestItem("Test", "User");
}
public List<TestItem> getItemList() {
return this.aTestItemList;
}
And here are my XML-Files:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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"
android:fitsSystemWindows="true"
tools:context="private.testapp.view.SelectItemActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_select_item" />
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="#dimen/fab_margin"
app:srcCompat="#android:drawable/ic_dialog_email" />
</android.support.design.widget.CoordinatorLayout>
This is my layout file
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="item" type="private.testapp.model.TestItem"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:textSize="128sp"
android:layout_height="wrap_content"
android:text="#{item.name}"/>
<TextView android:layout_width="wrap_content"
android:textSize="128sp"
android:layout_height="wrap_content"
android:text="#{item.description}"/>
</LinearLayout>
</layout>
All i want to do first is just display the testitem... Since it displays it when i just show the layout, i am sure that the binding and my viewmodel works.
I don`t understand how the data in the layout will be shown in my view.
Option 1- forward variable from activity xml to included xml:
First,
ContentSelectItemBinding binding = DataBindingUtil.setContentView(this,R.layout.content_select_item);
this.aSelectItemViewModel = new SelectItemViewModel();
binding.setItem(this.aSelectItemViewModel.item);
//when i add this, it will just show the empty view
setContentView(R.layout.activity_select_item);
You're setting your activity content twice which is wrong, replace it with just:
DataBindingUtil.setContentView(this,R.layout.activity_select_item);
this.aSelectItemViewModel = new SelectItemViewModel();
binding.setItem(this.aSelectItemViewModel.item);
To set your activity xml as your layout.
Next, your activity_select_item xml should also be wrapped with a <layout> tag and a <data> tag inside to denote this is a data binding layout:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="item" type="private.testapp.model.TestItem"/>
</data>
<android.support.design.widget.CoordinatorLayout
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"
android:fitsSystemWindows="true"
tools:context="private.testapp.view.SelectItemActivity">
.
.
.
</layout>
Finally, forward the variable to your included layout inside the <include> tag:
.
.
.
<include
layout="#layout/content_select_item"
app:item="#{item}"/>
.
.
.
</android.support.design.widget.CoordinatorLayout>
Option 2- find included view and bind it
First, mark included view with id:
<include
id="#+id/content"
layout="#layout/content_select_item" />
Next, find it in code and bind it:
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_select_item);
View content= findViewById(R.id.content);
ViewDataBinding binding = DataBindingUtil.bind(content);
Finally, set the variable on the generic binding using generated id inside BR class (like R class but for data binding variables):
this.aSelectItemViewModel = new SelectItemViewModel();
binding.setVariable(BR.item, aSelectItemViewModel.item);