Android 数据绑定适配器空指针异常
Android Databinding Adapter Null Pointer Exception
我正在尝试在我的 Android 应用程序中使用 Android 数据绑定。如果我在没有任何数据的情况下初始化对象,我有一个对象 Outlet
。一切正常。所有数据都收集得很好。但是,如果我用数据初始化 Object
并将其传递给布局,它会使应用程序崩溃并出现 Invoking Interface method on Null Views
的抱怨。下面是我的布局文件:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="java.util.List"/>
<import type="android.view.View" />
<variable
name="outlet"
type="co.deliveryscience.dangote.Network.model.Outlet.Create.Outlet"/>
</data>
<android.support.v4.widget.NestedScrollView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="32dp"
android:layout_marginLeft="64dp"
android:layout_marginRight="64dp"
android:layout_marginTop="32dp"
android:background="#FFF"
android:animateLayoutChanges="true"
app:cardCornerRadius="4dp"
app:elevation="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp"
android:animateLayoutChanges="true">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/HeaderText"
android:text="@string/personal_information"
android:layout_marginBottom="8dp"
android:layout_marginTop="16dp"/>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/gray_semi_transparent"
android:layout_marginBottom="32dp"/>
<LinearLayout
android:id="@+id/layoutCreate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginBottom="32dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/name_of_outlet"
android:layout_marginBottom="8dp"/>
<EditText
android:id="@+id/nameOfOutlet"
android:layout_width="match_parent"
android:layout_height="55dp"
android:inputType="textCapWords"
android:singleLine="true"
android:imeOptions="actionNext"
android:text='@{outlet.name ?? ""}'
android:addTextChangedListener="@{outlet.onNameChanged}"
android:nextFocusDown="@+id/address"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:baselineAligned="false">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:layout_marginRight="8dp"
android:layout_marginEnd="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/ownerfirstname"
android:layout_marginBottom="8dp"/>
<EditText
android:id="@+id/fName"
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_marginBottom="16dp"
android:inputType="textCapWords"
android:singleLine="true"
android:imeOptions="actionNext"
android:text="@{outlet.firstName}"
android:addTextChangedListener="@{outlet.onFirstNameChanged}"
android:nextFocusRight="@+id/lName"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/ownerlastname"
android:layout_marginBottom="8dp"/>
<EditText
android:id="@+id/lName"
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_marginBottom="16dp"
android:inputType="textCapWords"
android:text='@{outlet.lastName == null ? "" : outlet.lastName}'
android:addTextChangedListener="@{outlet.onLastNameChanged}"
android:singleLine="true"
android:imeOptions="actionNext"
android:nextFocusDown="@+id/nameOfOutlet"/>
</LinearLayout>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/HeaderText"
android:text="@string/contact_information"
android:layout_marginBottom="8dp"
android:layout_marginTop="16dp"/>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/gray_semi_transparent"
android:layout_marginBottom="32dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/address"
android:layout_marginBottom="8dp"/>
<EditText
android:id="@+id/address"
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_marginBottom="16dp"
android:inputType="textPostalAddress"
android:text='@{outlet.address == null ? "" : outlet.address}'
android:addTextChangedListener="@{outlet.onAddresChanged}"
android:imeOptions="actionNext"
android:nextFocusDown="@+id/lga"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="16dp"
android:baselineAligned="false">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="1"
android:layout_marginRight="8dp"
android:layout_marginEnd="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/lga"
android:layout_marginBottom="8dp"/>
<AutoCompleteTextView
android:id="@+id/lga"
android:layout_width="match_parent"
android:layout_height="55dp"
android:imeOptions="actionNext"
android:inputType="textCapWords"
android:text="@{outlet.lga}"
android:singleLine="true"
android:nextFocusRight="@+id/state"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="1"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/state"
android:layout_marginBottom="8dp"/>
<AutoCompleteTextView
android:id="@+id/state"
android:layout_width="match_parent"
android:layout_height="55dp"
android:imeOptions="actionNext"
android:inputType="textCapWords"
android:singleLine="true"
android:nextFocusDown="@+id/phoneNumber1" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="16dp"
android:baselineAligned="true">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginRight="8dp"
android:layout_marginEnd="8dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/phone_number_1"
android:layout_marginBottom="8dp"/>
<EditText
android:id="@+id/phoneNumber1"
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_marginBottom="16dp"
android:inputType="phone"
android:imeOptions="actionNext"
android:addTextChangedListener="@{outlet.onPhoneNumberChanged}"
android:text="@{outlet.phoneNumber}"
android:singleLine="true"
android:nextFocusDown="@+id/phoneNumber2"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/phone_number_2"
android:layout_marginBottom="8dp"/>
<EditText
android:id="@+id/phoneNumber2"
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_marginBottom="16dp"
android:inputType="phone"
android:imeOptions="actionNext"
android:addTextChangedListener="@{outlet.onOtherPhoneNumberChanged}"
android:text="@{outlet.phoneNumber}"
android:singleLine="true"
android:nextFocusDown="@+id/outletOwnerEmail"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</layout>
我的 Observable 对象是这个
public class Outlet extends BaseObservable {
private static final String TAG = "Outlet";
@SerializedName("name")
@Expose
private String name;
@SerializedName("firstName")
@Expose
private String firstName;
@SerializedName("lastName")
@Expose
private String lastName;
@SerializedName("phoneNumber")
@Expose
private String phoneNumber;
@SerializedName("otherNumber")
@Expose
private String otherNumber;
@SerializedName("address")
@Expose
private String address;
/**
*
* @return
* The name
*/
@Bindable
public String getName() {
return name;
}
/**
*
* @param name
* The name
*/
public void setName(String name) {
setAtomicName(name);
notifyPropertyChanged(BR.name);
}
public void setAtomicName(String basic) {
this.name = basic;
}
public TextWatcher onNameChanged = new SimpleTextWatcher() {
@Override
public void onTextChanged(String newValue) {
Log.e(TAG+"Name", newValue);
setAtomicName(newValue);
}
};
/**
*
* @return
* The firstName
*/
@Bindable
public String getFirstName() {
return firstName;
}
/**
*
* @param firstName
* The firstName
*/
public void setFirstName(String firstName) {
setAtomicFirstName(firstName);
notifyPropertyChanged(BR.firstName);
}
public void setAtomicFirstName(String basic) {
this.firstName = basic;
}
public TextWatcher onFirstNameChanged = new SimpleTextWatcher() {
@Override
public void onTextChanged(String newValue) {
Log.e(TAG+"FirstName", newValue);
setAtomicFirstName(newValue);
}
};
/**
*
* @return
* The lastName
*/
@Bindable
public String getLastName() {
return lastName;
}
/**
*
* @param lastName
* The lastName
*/
public void setLastName(String lastName) {
setAtomicLastName(lastName);
notifyPropertyChanged(BR.lastName);
}
public void setAtomicLastName(String basic) {
this.lastName = basic;
}
public TextWatcher onLastNameChanged = new SimpleTextWatcher() {
@Override
public void onTextChanged(String newValue) {
Log.e(TAG+"lstname", newValue);
setAtomicLastName(newValue);
}
};
/**
*
* @return
* The phoneNumber
*/
@Bindable
public String getPhoneNumber() {
return phoneNumber;
}
/**
*
* @param phoneNumber
* The phoneNumber
*/
public void setPhoneNumber(String phoneNumber) {
setAtomicPhoneNumber(phoneNumber);
notifyPropertyChanged(BR.phoneNumber);
}
public void setAtomicPhoneNumber(String basic) {
this.phoneNumber = basic;
}
public TextWatcher onPhoneNumberChanged = new SimpleTextWatcher() {
@Override
public void onTextChanged(String newValue) {
Log.e(TAG+"phonenumber", newValue);
setAtomicPhoneNumber(newValue);
}
};
/**
*
* @return
* The otherNumber
*/
public String getOtherNumber() {
return otherNumber;
}
/**
*
* @param otherNumber
* The otherNumber
*/
public void setOtherNumber(String otherNumber) {
setAtomicOtherPhoneNumber(otherNumber);
notifyPropertyChanged(BR.phoneNumber);
}
public void setAtomicOtherPhoneNumber(String basic) {
this.otherNumber = basic;
}
public TextWatcher onOtherPhoneNumberChanged = new SimpleTextWatcher() {
@Override
public void onTextChanged(String newValue) {
Log.e(TAG+"otherphone", newValue);
setAtomicOtherPhoneNumber(newValue);
}
};
/**
*
* @return
* The address
*/
@Bindable
public String getAddress() {
return address;
}
/**
*
* @param address
* The address
*/
public void setAddress(String address) {
setAtomicAddress(address);
notifyPropertyChanged(BR.phoneNumber);
}
public void setAtomicAddress(String basic) {
this.address = basic;
}
public TextWatcher onAddresChanged = new SimpleTextWatcher() {
@Override
public void onTextChanged(String newValue) {
Log.e(TAG+"address", newValue);
setAtomicAddress(newValue);
}
};
@BindingAdapter({"bind:email"})
public static void checkEmail(EditText editText, String email) {
if (editText != null) {
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
if (editText.length() > 0) {
if (!Utils.emailMatchPattern(editText.getText().toString())) editText.setError("Email Requried");
}
}
});
}
}
}
当我这样做的时候。 Outlet outlet = new Outlet();
并像这样将其分配给我的绑定数据 binding.setOutlet(outlet);
我不会收到任何错误。但是,如果我这样做:
Outlet outlet = gson.fromJson(realmOutlet.getPayload(), Outlet.class);
binding.setOutlet(outlet);
我得到一个 NPE Error
并且基于 NPE,这不是因为数据不存在。就好像 adapters
还没有初始化一样。我知道它一直指向 addressField
因为它是第一项。这是地址的 adapter
。这是一个摘要 class。所以,我很困惑为什么他们不初始化:
public TextWatcher onAddresChanged = new SimpleTextWatcher() {
@Override
public void onTextChanged(String newValue) {
Log.e(TAG+"address", newValue);
setAtomicAddress(newValue);
}
};
下面是我的 Log
我无法跟踪日志以了解究竟要调试什么。但是,要说附加到 Interface method
的视图是空的。就像 Binding Layouts
还没有初始化。那么,为什么当我用空数据初始化它时它可以工作?
还有我的onCreate
代码
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_create);
binding = DataBindingUtil.setContentView(this, R.layout.activity_create);
realm = RealmUtils.getRealmInstance(getApplicationContext());
setSupportActionBar(binding.createToolbar);
action = getIntent().getStringExtra("action");
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
initAutoCompletedTexts();
if (action != null) {
if (action.equals("create")) {
getSupportActionBar().setTitle(R.string.create);
outlet = new Outlet();
outlet.setShopkeeper(shopkeeper);
binding.setOutlet(outlet);
} else {
getSupportActionBar().setTitle(R.string.update);
binding.saveBtn.setText("UPDATE");
initUpdateSpcific();
}
}
}
//createBinding.setCustomer(outlet);
binding.saveBtn.setOnClickListener(view -> {
save();
});
}
有几点需要注意:
1) 初始化工作方式如下:
Outlet outlet = new Outlet();
2) 赋值:
Outlet outlet = gson.fromJson(realmOutlet.getPayload(), Outlet.class);
为了保持数据绑定,您必须初始化然后相应地更新数据。
因此您必须以结构化的方式同时执行这两项操作,即
Outlet outlet = new Outlet();
Outlet outlet = gson.fromJson(realmOutlet.getPayload(), Outlet.class);
binding.setOutlet(outlet);
以及后续更新:分配值和 setOutlet
outlet = gson.fromJson(realmOutlet.getPayload(), Outlet.class);
binding.setOutlet(outlet);
更新:
这只是对你问题的回答和我们在评论中的聊天的后续,以便其他人参考。
我正在尝试在我的 Android 应用程序中使用 Android 数据绑定。如果我在没有任何数据的情况下初始化对象,我有一个对象 Outlet
。一切正常。所有数据都收集得很好。但是,如果我用数据初始化 Object
并将其传递给布局,它会使应用程序崩溃并出现 Invoking Interface method on Null Views
的抱怨。下面是我的布局文件:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="java.util.List"/>
<import type="android.view.View" />
<variable
name="outlet"
type="co.deliveryscience.dangote.Network.model.Outlet.Create.Outlet"/>
</data>
<android.support.v4.widget.NestedScrollView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="32dp"
android:layout_marginLeft="64dp"
android:layout_marginRight="64dp"
android:layout_marginTop="32dp"
android:background="#FFF"
android:animateLayoutChanges="true"
app:cardCornerRadius="4dp"
app:elevation="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp"
android:animateLayoutChanges="true">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/HeaderText"
android:text="@string/personal_information"
android:layout_marginBottom="8dp"
android:layout_marginTop="16dp"/>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/gray_semi_transparent"
android:layout_marginBottom="32dp"/>
<LinearLayout
android:id="@+id/layoutCreate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginBottom="32dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/name_of_outlet"
android:layout_marginBottom="8dp"/>
<EditText
android:id="@+id/nameOfOutlet"
android:layout_width="match_parent"
android:layout_height="55dp"
android:inputType="textCapWords"
android:singleLine="true"
android:imeOptions="actionNext"
android:text='@{outlet.name ?? ""}'
android:addTextChangedListener="@{outlet.onNameChanged}"
android:nextFocusDown="@+id/address"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:baselineAligned="false">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:layout_marginRight="8dp"
android:layout_marginEnd="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/ownerfirstname"
android:layout_marginBottom="8dp"/>
<EditText
android:id="@+id/fName"
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_marginBottom="16dp"
android:inputType="textCapWords"
android:singleLine="true"
android:imeOptions="actionNext"
android:text="@{outlet.firstName}"
android:addTextChangedListener="@{outlet.onFirstNameChanged}"
android:nextFocusRight="@+id/lName"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/ownerlastname"
android:layout_marginBottom="8dp"/>
<EditText
android:id="@+id/lName"
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_marginBottom="16dp"
android:inputType="textCapWords"
android:text='@{outlet.lastName == null ? "" : outlet.lastName}'
android:addTextChangedListener="@{outlet.onLastNameChanged}"
android:singleLine="true"
android:imeOptions="actionNext"
android:nextFocusDown="@+id/nameOfOutlet"/>
</LinearLayout>
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/HeaderText"
android:text="@string/contact_information"
android:layout_marginBottom="8dp"
android:layout_marginTop="16dp"/>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/gray_semi_transparent"
android:layout_marginBottom="32dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/address"
android:layout_marginBottom="8dp"/>
<EditText
android:id="@+id/address"
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_marginBottom="16dp"
android:inputType="textPostalAddress"
android:text='@{outlet.address == null ? "" : outlet.address}'
android:addTextChangedListener="@{outlet.onAddresChanged}"
android:imeOptions="actionNext"
android:nextFocusDown="@+id/lga"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="16dp"
android:baselineAligned="false">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="1"
android:layout_marginRight="8dp"
android:layout_marginEnd="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/lga"
android:layout_marginBottom="8dp"/>
<AutoCompleteTextView
android:id="@+id/lga"
android:layout_width="match_parent"
android:layout_height="55dp"
android:imeOptions="actionNext"
android:inputType="textCapWords"
android:text="@{outlet.lga}"
android:singleLine="true"
android:nextFocusRight="@+id/state"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="1"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/state"
android:layout_marginBottom="8dp"/>
<AutoCompleteTextView
android:id="@+id/state"
android:layout_width="match_parent"
android:layout_height="55dp"
android:imeOptions="actionNext"
android:inputType="textCapWords"
android:singleLine="true"
android:nextFocusDown="@+id/phoneNumber1" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="16dp"
android:baselineAligned="true">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginRight="8dp"
android:layout_marginEnd="8dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/phone_number_1"
android:layout_marginBottom="8dp"/>
<EditText
android:id="@+id/phoneNumber1"
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_marginBottom="16dp"
android:inputType="phone"
android:imeOptions="actionNext"
android:addTextChangedListener="@{outlet.onPhoneNumberChanged}"
android:text="@{outlet.phoneNumber}"
android:singleLine="true"
android:nextFocusDown="@+id/phoneNumber2"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/phone_number_2"
android:layout_marginBottom="8dp"/>
<EditText
android:id="@+id/phoneNumber2"
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_marginBottom="16dp"
android:inputType="phone"
android:imeOptions="actionNext"
android:addTextChangedListener="@{outlet.onOtherPhoneNumberChanged}"
android:text="@{outlet.phoneNumber}"
android:singleLine="true"
android:nextFocusDown="@+id/outletOwnerEmail"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
</layout>
我的 Observable 对象是这个
public class Outlet extends BaseObservable {
private static final String TAG = "Outlet";
@SerializedName("name")
@Expose
private String name;
@SerializedName("firstName")
@Expose
private String firstName;
@SerializedName("lastName")
@Expose
private String lastName;
@SerializedName("phoneNumber")
@Expose
private String phoneNumber;
@SerializedName("otherNumber")
@Expose
private String otherNumber;
@SerializedName("address")
@Expose
private String address;
/**
*
* @return
* The name
*/
@Bindable
public String getName() {
return name;
}
/**
*
* @param name
* The name
*/
public void setName(String name) {
setAtomicName(name);
notifyPropertyChanged(BR.name);
}
public void setAtomicName(String basic) {
this.name = basic;
}
public TextWatcher onNameChanged = new SimpleTextWatcher() {
@Override
public void onTextChanged(String newValue) {
Log.e(TAG+"Name", newValue);
setAtomicName(newValue);
}
};
/**
*
* @return
* The firstName
*/
@Bindable
public String getFirstName() {
return firstName;
}
/**
*
* @param firstName
* The firstName
*/
public void setFirstName(String firstName) {
setAtomicFirstName(firstName);
notifyPropertyChanged(BR.firstName);
}
public void setAtomicFirstName(String basic) {
this.firstName = basic;
}
public TextWatcher onFirstNameChanged = new SimpleTextWatcher() {
@Override
public void onTextChanged(String newValue) {
Log.e(TAG+"FirstName", newValue);
setAtomicFirstName(newValue);
}
};
/**
*
* @return
* The lastName
*/
@Bindable
public String getLastName() {
return lastName;
}
/**
*
* @param lastName
* The lastName
*/
public void setLastName(String lastName) {
setAtomicLastName(lastName);
notifyPropertyChanged(BR.lastName);
}
public void setAtomicLastName(String basic) {
this.lastName = basic;
}
public TextWatcher onLastNameChanged = new SimpleTextWatcher() {
@Override
public void onTextChanged(String newValue) {
Log.e(TAG+"lstname", newValue);
setAtomicLastName(newValue);
}
};
/**
*
* @return
* The phoneNumber
*/
@Bindable
public String getPhoneNumber() {
return phoneNumber;
}
/**
*
* @param phoneNumber
* The phoneNumber
*/
public void setPhoneNumber(String phoneNumber) {
setAtomicPhoneNumber(phoneNumber);
notifyPropertyChanged(BR.phoneNumber);
}
public void setAtomicPhoneNumber(String basic) {
this.phoneNumber = basic;
}
public TextWatcher onPhoneNumberChanged = new SimpleTextWatcher() {
@Override
public void onTextChanged(String newValue) {
Log.e(TAG+"phonenumber", newValue);
setAtomicPhoneNumber(newValue);
}
};
/**
*
* @return
* The otherNumber
*/
public String getOtherNumber() {
return otherNumber;
}
/**
*
* @param otherNumber
* The otherNumber
*/
public void setOtherNumber(String otherNumber) {
setAtomicOtherPhoneNumber(otherNumber);
notifyPropertyChanged(BR.phoneNumber);
}
public void setAtomicOtherPhoneNumber(String basic) {
this.otherNumber = basic;
}
public TextWatcher onOtherPhoneNumberChanged = new SimpleTextWatcher() {
@Override
public void onTextChanged(String newValue) {
Log.e(TAG+"otherphone", newValue);
setAtomicOtherPhoneNumber(newValue);
}
};
/**
*
* @return
* The address
*/
@Bindable
public String getAddress() {
return address;
}
/**
*
* @param address
* The address
*/
public void setAddress(String address) {
setAtomicAddress(address);
notifyPropertyChanged(BR.phoneNumber);
}
public void setAtomicAddress(String basic) {
this.address = basic;
}
public TextWatcher onAddresChanged = new SimpleTextWatcher() {
@Override
public void onTextChanged(String newValue) {
Log.e(TAG+"address", newValue);
setAtomicAddress(newValue);
}
};
@BindingAdapter({"bind:email"})
public static void checkEmail(EditText editText, String email) {
if (editText != null) {
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
if (editText.length() > 0) {
if (!Utils.emailMatchPattern(editText.getText().toString())) editText.setError("Email Requried");
}
}
});
}
}
}
当我这样做的时候。 Outlet outlet = new Outlet();
并像这样将其分配给我的绑定数据 binding.setOutlet(outlet);
我不会收到任何错误。但是,如果我这样做:
Outlet outlet = gson.fromJson(realmOutlet.getPayload(), Outlet.class);
binding.setOutlet(outlet);
我得到一个 NPE Error
并且基于 NPE,这不是因为数据不存在。就好像 adapters
还没有初始化一样。我知道它一直指向 addressField
因为它是第一项。这是地址的 adapter
。这是一个摘要 class。所以,我很困惑为什么他们不初始化:
public TextWatcher onAddresChanged = new SimpleTextWatcher() {
@Override
public void onTextChanged(String newValue) {
Log.e(TAG+"address", newValue);
setAtomicAddress(newValue);
}
};
下面是我的 Log
我无法跟踪日志以了解究竟要调试什么。但是,要说附加到 Interface method
的视图是空的。就像 Binding Layouts
还没有初始化。那么,为什么当我用空数据初始化它时它可以工作?
还有我的onCreate
代码
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_create);
binding = DataBindingUtil.setContentView(this, R.layout.activity_create);
realm = RealmUtils.getRealmInstance(getApplicationContext());
setSupportActionBar(binding.createToolbar);
action = getIntent().getStringExtra("action");
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
initAutoCompletedTexts();
if (action != null) {
if (action.equals("create")) {
getSupportActionBar().setTitle(R.string.create);
outlet = new Outlet();
outlet.setShopkeeper(shopkeeper);
binding.setOutlet(outlet);
} else {
getSupportActionBar().setTitle(R.string.update);
binding.saveBtn.setText("UPDATE");
initUpdateSpcific();
}
}
}
//createBinding.setCustomer(outlet);
binding.saveBtn.setOnClickListener(view -> {
save();
});
}
有几点需要注意:
1) 初始化工作方式如下:
Outlet outlet = new Outlet();
2) 赋值:
Outlet outlet = gson.fromJson(realmOutlet.getPayload(), Outlet.class);
为了保持数据绑定,您必须初始化然后相应地更新数据。
因此您必须以结构化的方式同时执行这两项操作,即
Outlet outlet = new Outlet();
Outlet outlet = gson.fromJson(realmOutlet.getPayload(), Outlet.class);
binding.setOutlet(outlet);
以及后续更新:分配值和 setOutlet
outlet = gson.fromJson(realmOutlet.getPayload(), Outlet.class);
binding.setOutlet(outlet);
更新:
这只是对你问题的回答和我们在评论中的聊天的后续,以便其他人参考。