android - 为什么我的 Android 自定义 ArrayAdapter 在使用 2 路数据绑定时不起作用?
问题描述
我们正在进行的项目使用 MVVM 架构、房间和 2-way 数据绑定。在我的 layout.xml 文件中,我们AutoCompleteTextView
用于国家/地区选择器。这些国家是我们项目中的模型:
以下是代码,但显然我无法发布整个项目,所以如果您需要更多数据,请告诉我。
国家.java
@Entity
public class Country
{
@PrimaryKey
@ColumnInfo(name = "ID")
private Long id;
@ColumnInfo(name = "Name")
private String countryName;
@ColumnInfo(name = "Code")
private String countryCode;
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
public String getCountryName()
{
return countryName;
}
public void setCountryName(String countryName)
{
this.countryName = countryName;
}
public String getCountryCode()
{
return countryCode;
}
public void setCountryCode(String countryCode)
{
this.countryCode = countryCode;
}
}
布局.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">
<data>
<import type="android.view.View" />
<variable name="myViewModel" type="ViewModel" />
</data>
<android.support.v4.widget.NestedScrollView>
<AutoCompleteTextView
android:id="@+id/countryAutoCompleteTextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:completionThreshold="1"
android:dropDownWidth="match_parent"
android:imeOptions="actionNext"
android:inputType="text"
android:maxLines="1"
android:text="@={myViewModel.countryObservable}"
android:textIsSelectable="false"
android:textColor="@color/edit_text_black_color_selector" />
<android.support.v4.widget.NestedScrollView>
</layout>
查看.java
public class View {
onCreate(){
ViewModel myViewModel = new ViewModel();
ActivityViewBinding binding = DataBindingUtil();
binding.setViewModel(myViewModel);
AutoCompleteCountryAdapter countryAdapter = new AutoCompleteAdapter();
binding.countryAutoCompleteTextView.setAdapter(countryAdapter);
}
}
ViewModel.java
public class ViewModel extends AndroidViewModel {
private final ObservableField<String> countryObservable = new ObservableField<>();
}
AutoCompleteCountryAdapter.java我从这里 复制了代码
public class AutoCompleteCountryAdapter extends ArrayAdapter<CountryItem> {
private List<CountryItem> countryListFull;
public AutoCompleteCountryAdapter(@NonNull Context context, @NonNull List<CountryItem> countryList) {
super(context, 0, countryList);
countryListFull = new ArrayList<>(countryList);
}
@NonNull
@Override
public Filter getFilter() {
return countryFilter;
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(android.R.layout.simple_dropdown_item_1line, parent, false);
}
TextView textViewName = convertView.findViewById(R.id.text_view_name);
CountryItem countryItem = getItem(position);
if (countryItem != null) {
textViewName.setText(country.getCountryName());
}
return convertView;
}
private Filter countryFilter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
List<CountryItem> suggestions = new ArrayList<>();
if (constraint == null || constraint.length() == 0) {
suggestions.addAll(countryListFull);
} else {
String filterPattern = constraint.toString().toLowerCase().trim();
for (CountryItem item : countryListFull) {
if (item.getCountryName().toLowerCase().contains(filterPattern)) {
suggestions.add(item);
}
}
}
results.values = suggestions;
results.count = suggestions.size();
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
clear();
addAll((List) results.values);
notifyDataSetChanged();
}
@Override
public CharSequence convertResultToString(Object resultValue) {
return ((CountryItem) resultValue).getCountryName();
}
};
}
如您所见,我的可观察字段类型为String
. 这工作......有点。每当我从 AutoCompleteTextView 的下拉列表中选择一个国家时,它都会填充该AutoCompleteTextView
android:text
字段;但是,我需要 Country 对象中的数据库 ID 才能使用它,它是我们另一个模型中的外键。
所以,我想我会把 observable 变成 type Country
,但这根本不起作用。一位同事说我需要 an@BindingAdapter
和 an@InverseBindingAdapter
来完成这项工作,所以我创建了它们。
@BindingAdapter(value = {"android:text", "android:onItemSelected"}, requireAll = false)
public static void setText(AutoCompleteTextView autoCompleteTextView, Country newSelectedValue, final InverseBindingListener newTextAttrChanged)
{
autoCompleteTextView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
{
@Override
public void onItemSelected(AdapterView<?> adapterView, View subView, int position, long id)
{
newTextAttrChanged.onChange();
}
@Override
public void onNothingSelected(AdapterView<?> adapterView)
{
}
});
if (newSelectedValue != null)
{
int pos = autoCompleteTextView.getListSelection();
autoCompleteTextView.setText(autoCompleteTextView.getAdapter().getItemViewType(pos));
}
}
@InverseBindingAdapter(attribute = "android:text", event = "android:onItemSelected")
public static Country getText(AutoCompleteTextView textView)
{
int pos = textView.getListSelection();
Country country = (Country) textView.getAdapter().getItem(pos);
return countryISO;
}
我现在的问题是,@BindingAdapter
一旦加载活动,我就会被调用,但再也不会......尤其是当我更改值时,这是我需要它做的。
那么,我做错了什么,我能做些什么来解决这个问题?
解决方案
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle? ): View? {
val application = requireNotNull(this.activity).application
val viewModelFactory = HomePageViewModelFactory(application)
val homePageViewModel = activity?.run {
ViewModelProviders.of(
this, viewModelFactory
).get(HomePageViewModel::class.java)
}
val binding: FragmentReviewPageBinding = DataBindingUtil.inflate(
inflater,
R.layout.fragment_review_page,
container,
false
)
binding.homePageViewModel = homePageViewModel
这就是将 xml 变量与绑定链接的方式
binding.homePageViewModel = homePageViewModel
工厂类
class HomePageViewModelFactory(
private val application: Application) : ViewModelProvider.Factory {
@Suppress("unchecked_cast")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(HomePageViewModel::class.java)) {
return HomePageViewModel(application) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}
像这样,您可以跨多个片段共享相同的视图模型实例。
推荐阅读
- bash - 为标志查找文件(-i -d -p -a 等)
- swift - 新窗口总是以设定的大小打开
- wordpress - 如何在单击 url (wordpress) 时到达目标 # 锚点?
- python - 如何使用熊猫减去数据集中所有列的分组数据中的第一个和最后一个值
- c# - 在存储过程中将 DataTable 传递给表值参数不起作用
- typescript - 为什么函数接受对象引用但在插入与文字对象相同的对象时拒绝它?
- python - 进程以退出代码 -1073740791 (0xC0000409) Tensorflow 错误完成
- spring-batch - 将行写入csv文件时如何在Spring Batch的FlatFileItemWriter中包含一个计数器
- r - 如何按组计算加权中位数
- c++ - 在反序列化使用 std::wofstream 序列化的对象时,宽字符输入流 std::wifstream 正在损坏