为什么使用2路数据绑定时我的Android自定义ArrayAdapter不起作用?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么使用2路数据绑定时我的Android自定义ArrayAdapter不起作用?相关的知识,希望对你有一定的参考价值。

我们正在研究的项目使用MVVM体系结构,房间和2路数据绑定。在我的layout.xml文件中,我们使用AutoCompleteTextView作为国家/地区选择器。国家是我们项目中的模型:

以下是代码,但是很显然,我无法发布整个项目,因此,如果您需要更多数据,请告诉我。

Country.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;
    

layout.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>

View.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我从here

复制了代码
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才能在我们的另一个模型中使用它作为外键。

所以,我以为我会将可观察对象转换为Country类型,但这根本不起作用。一位同事说,我需要@BindingAdapter@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")



像这样,您可以在多个片段之间共享相同的viewmodel实例。

以上是关于为什么使用2路数据绑定时我的Android自定义ArrayAdapter不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

Kotlin 2路绑定自定义视图

android数据绑定的优缺点是啥?

不会触发自定义事件

Android:在自定义视图上使用android绑定点击事件

android数据绑定与自定义视图

iOS web view如何绑定一个自定义的类