Android数据绑定到像WPF这样的listview?

时间:2017-06-29 13:49:37

标签: android listview data-binding

我正试图进入android中的数据绑定。 因为我对WPF中的数据绑定更有经验,所以我非常困惑。

尝试了什么: enter image description here

在WPF中,使用自定义项将对象列表绑定到列表视图是很容易的。以下是私人项目的示例:

enter image description here

就是这样。不需要胶水代码或适配器。

我的问题:

  • 是否可以将项目绑定到列表视图而不需要任何代码 背景
  • 我可以在列表视图的布局中定义“列表视图项”吗?

因为我很困惑,关于适配器/充气东西等 有一个很好的关于绑定到列表的教程,但是我仍然需要为绑定编写代码。

http://blog.trsquarelab.com/2016/01/data-binding-in-android-listview.html

2 个答案:

答案 0 :(得分:1)

Android中的东西是不同的

是否可以在后台没有任何代码的情况下将项目绑定到列表视图?

您必须在适配器类中使用数据绑定代码作为列表视图。

我可以在列表视图的布局中定义“列表视图项”吗?

不,你不能!列表视图项必须具有自己的布局。

由于您对适配器感到困惑,因此以下几点可以使其更清晰:

将适配器视为管理数据模型的管理器,并使其适应列表视图的各个条目。适配器将填充每行的布局,并将数据分配给行中的单个视图。

如果没有数据绑定,适配器类可以包含很多代码,具体取决于行UI的复杂程度。因此,使用数据绑定将有助于仅使用几行绑定代码从适配器类中删除所有不必要的代码。

您发布的链接已足够开始,但我建议您使用 Recycler view 。以下是您可以查看的其他链接

  1. https://medium.com/google-developers/android-data-binding-recyclerview-db7c40d9f0e4
  2. https://android.jlelse.eu/recyclerview-with-endlessscroll-2c503008522f

答案 1 :(得分:0)

Android DataBinding需要一些代码即可完成

您的所有项目都可以重用前面的步骤1,接下来的步骤2和3都是布局资源文件,就像WPF一样

步骤1.为所有AbsListView定义BindingAdapter类,您的其他项目AbsListView可以重用该类

public class AbsListViewBindingAdapter {
    @BindingAdapter(value = {"android:items", "android:itemTemplate", "android:dropDownItemTemplate"}, requireAll = false)
    public static <T> void setListAdapter(AbsListView view, List<T> items, @LayoutRes int itemTemplateLayout, @LayoutRes int dropDownItemTemplateLayout) {
        final ListAdapter oldAdapter = view.getAdapter();
        if (oldAdapter instanceof ObservableListAdapter) {
            ((ObservableListAdapter<T>) oldAdapter).setParams(items, itemTemplateLayout, dropDownItemTemplateLayout);
        } else {
            view.setAdapter(new ObservableListAdapter<>(view.getContext(), items, itemTemplateLayout, dropDownItemTemplateLayout));
        }
    }

    @BindingAdapter(value = {"android:items", "android:itemTemplate", "android:dropDownItemTemplate"}, requireAll = false)
    public static <T> void setListAdapter(AbsListView view, T[] items, @LayoutRes int itemTemplateLayout, @LayoutRes int dropDownItemTemplateLayout) {
        setListAdapter(view, items != null ? Arrays.asList(items) : null, itemTemplateLayout, dropDownItemTemplateLayout);
    }

    @BindingAdapter(value = {"android:items", "android:itemTemplate", "android:dropDownItemTemplate"}, requireAll = false)
    public static <T> void setListAdapter(AbsListView view, int[] items, @LayoutRes int itemTemplateLayout, @LayoutRes int dropDownItemTemplateLayout) {
        setListAdapter(view, items != null ? IntStream.of(items).boxed().collect(Collectors.toList()) : null, itemTemplateLayout, dropDownItemTemplateLayout);
    }

    static class ObservableListAdapter<T> extends BaseAdapter {
        private List<T> mList;
        private int mDropDownResourceId = 0;
        private int mResourceId = 0;
        private final LayoutInflater mLayoutInflater;

        final ObservableList.OnListChangedCallback mListChangedCallback = new ObservableList.OnListChangedCallback() {
            @Override
            public void onChanged(ObservableList observableList) {
                notifyDataSetChanged();
            }

            @Override
            public void onItemRangeChanged(ObservableList observableList, int i, int i1) {
                notifyDataSetChanged();
            }

            @Override
            public void onItemRangeInserted(ObservableList observableList, int i, int i1) {
                notifyDataSetChanged();
            }

            @Override
            public void onItemRangeMoved(ObservableList observableList, int i, int i1, int i2) {
                notifyDataSetChanged();
            }

            @Override
            public void onItemRangeRemoved(ObservableList observableList, int i, int i1) {
                notifyDataSetChanged();
            }
        };


        public ObservableListAdapter(Context context, List<T> list, @LayoutRes int itemTemplate, @LayoutRes int dropDownItemTemplate) {
            mLayoutInflater = LayoutInflater.from(context);
            setParams(list, itemTemplate, dropDownItemTemplate);
        }


        public void setParams(List<T> list, @LayoutRes int itemTemplate, @LayoutRes int dropDownItemTemplate) {
            boolean requireNotifyChange = mResourceId != itemTemplate || mDropDownResourceId != dropDownItemTemplate || !Objects.equals(list, mList);
            mResourceId = itemTemplate;
            mDropDownResourceId = dropDownItemTemplate;
            if (!Objects.equals(list, mList)) {
                if (mList instanceof ObservableList) {
                    ((ObservableList) mList).removeOnListChangedCallback(mListChangedCallback);
                }
                mList = list;
                if (mList instanceof ObservableList) {
                    ((ObservableList) mList).addOnListChangedCallback(mListChangedCallback);
                }
            }
            if (requireNotifyChange) {
                notifyDataSetChanged();
            }
        }

        @Override
        public int getCount() {
            return (mList != null) ? mList.size() : 0;
        }

        @Override
        public T getItem(int position) {
            return mList != null ? mList.get(position) : null;
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            return getViewForResource(mResourceId, position, convertView, parent);
        }

        @Override
        public View getDropDownView(int position, View convertView, ViewGroup parent) {
            return getViewForResource(mDropDownResourceId, position, convertView, parent);
        }

        public View getViewForResource(int resourceId, int position, View convertView, ViewGroup parent) {
            final ViewDataBinding binding = (convertView != null)
                    ? DataBindingUtil.getBinding(convertView)
                    : DataBindingUtil.inflate(mLayoutInflater, resourceId, parent, false);
            binding.setVariable(BR.viewModel, getItem(position));
            return binding.getRoot();
        }
    }
}

第2步。声明自己的项目模板(例如WPF),并且必须声明viewModel数据类型,因为Android始终使用静态类型绑定,而WPF使用动态/反射类型绑定,请确保变量 viewModel (= WPF的DataContext)为方便起见在数据部分中声明

例如:java.io.File

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

        <variable
            name="viewModel"
            type="java.io.File" />

    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <TextView
            android:layout_width="0px"
            android:layout_height="wrap_content"
            android:layout_weight="0.2"
            android:text='@{viewModel.directory ? "Folder" : "File"}'
            android:textSize="20sp" />

        <TextView
            android:layout_width="0px"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@{viewModel.name}"
            android:textSize="20sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text='@{viewModel.length()+ ""}'
            android:textSize="20sp" />
    </LinearLayout>
</layout>

第3步。将项目模板添加到ListView布局文件中,此示例列出了外部存储目录中的所有文件

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <import type="android.os.Environment" />

        <variable
            name="viewModel"
            type="com.mycompany.databindingtest.MainActivity.ViewModel" />

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <ListView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:animateLayoutChanges="true"
            android:dropDownItemTemplate="@{@layout/file_list_item_template}"
            android:itemTemplate="@{@layout/file_list_item_template}"
            android:items="@{Environment.externalStorageDirectory.listFiles()}" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>