Как связать переменную модели представления с пользовательским типом класса

Что работает?

XML:

            name="viewModel"
            type="com. . . . .MyViewModel" />
...
...
...
<android.support.v7.widget.RecyclerView
            android:id="@+id/feeds_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center_horizontal"
            app:items="@{viewModel.feeds}"
            />

MyViewModel класс:

private String[] feeds;
...
...
public MyViewModel() {
    String[] feeds = new String[] {"foo", "bar"};
    setFeeds(feeds);
}

@Bindable
    public  String[]  getFeeds() {
        return feeds;
    }

    public void setFeeds( String[]  feeds) {
        this.feeds = feeds;
        notifyPropertyChanged(BR.feeds);
    }

MyActivity:

    @BindingAdapter({"items"})
    public static void myMethod(View view, String[] feeds) {
        // Do somthing
    }

Что я хочу изменить?

Я хочу изменить String [] на List<Feed>, а myMethod не достигается.

Мой класс Feed:

public class Feed {
    private String name;

    public Feed(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

На данный момент этот класс содержит только один член String, но, конечно, он будет содержать больше.


person Matan Marciano    schedule 31.07.2019    source источник
comment
Используйте список строк вместо массива строк.   -  person Rajnish suryavanshi    schedule 31.07.2019
comment
Спасибо за ответ, но ... Вы прочитали мой вопрос? String [] работает. Список ‹Feed› не работает. @Rajnishsuryavanshi   -  person Matan Marciano    schedule 31.07.2019
comment
вы можете опубликовать свой класс фида?   -  person Rajnish suryavanshi    schedule 31.07.2019
comment
@Rajnishsuryavanshi - Конечно. Отредактировано. Смотрите сейчас.   -  person Matan Marciano    schedule 31.07.2019
comment
Откуда вы вызываете метод setFeeds.?   -  person Rajnish suryavanshi    schedule 31.07.2019
comment
Из конструктора ViewModel @Rajnishsuryavanshi   -  person Matan Marciano    schedule 31.07.2019


Ответы (2)


Измените это, как показано ниже, в модели просмотра

   private MutableLiveData<List<Feed>> feedListLivedata =  new MutableLiveData<>();;



 public MyViewModel() {
    //create a list of feed here
    setFeeds(feeds);
}



public void setFeeds( List<Feed>  feeds) {
        feedListLivedata .postValue(feeds);
    }

// создаем геттер и сеттер для текущих данных списка каналов.

А теперь в xml

 app:items="@{viewModel.feedListLivedata }"
person Rajnish suryavanshi    schedule 31.07.2019
comment
Браво! Спас мой день! - person Matan Marciano; 31.07.2019
comment
Кстати. Это работает в моем фрагменте. когда я пытаюсь сделать то же самое в каком-то другом действии, метод BindableAdapter достигается до (!) вызова postValue. - person Matan Marciano; 01.08.2019
comment
Но в этом случае значение будет нулевым. - person Rajnish suryavanshi; 01.08.2019
comment
То, что я имел в виду, в классе фрагментов все ок. Но в классе активности нет. Может быть, мы можем поговорить наедине, чтобы сохранить этот пост в чистоте? - person Matan Marciano; 01.08.2019
comment
Конечно. Это мой адрес электронной почты для видеовстречи [email protected]. - person Rajnish suryavanshi; 01.08.2019

ЕСЛИ вы хотите привязать List к RecyclerView.

Шаги, которым нужно следовать.

1- Создайте RecyclerView внутри файлов xml с тегом app:items, чтобы установить элементы для привязки к

 <androidx.recyclerview.widget.RecyclerView
        android:layout_width="match_parent"
        android:id="@+id/recycler_view"
        android:layout_height="match_parent"
        android:scrollbars="vertical"
        app:items="@{viewmodel.items}"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

2- Создать макет для строк списков RecyclerView. Элементы должны иметь SomeObject в качестве переменной.

<?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.widget.CompoundButton" />

        <variable
            name="task"
            type="com...data.model.Task" />

        <variable
            name="viewmodel"
            type="com...TaskListViewModel" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="?android:attr/listPreferredItemHeight"
        android:orientation="horizontal"
        android:onClick="@{() -> viewmodel.openTask(task.id)}">

        <CheckBox
            android:id="@+id/complete"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:onClick="@{(view) -> viewmodel.completeTask(task, ((CompoundButton)view).isChecked())}"
            android:checked="@{task.completed}" />

        <TextView
            android:id="@+id/title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="@dimen/activity_horizontal_margin"
            android:layout_marginStart="@dimen/activity_horizontal_margin"
            android:textAppearance="@style/TextAppearance.AppCompat.Title"
            android:text="@{task.titleForList}"
            app:completedTask="@{task.completed}" />
    </LinearLayout>
</layout>

3- Используйте ListAdapter, это новая функция, которая вычисляет разницу строк сама по себе и в рабочем потоке, а не RecyclerView.Adapter, и привязывает SomeObject и ViewModel к этому адаптеру.

/ ** * Адаптер для списка задач. Имеет ссылку на [TaskListViewModel] для отправки на него действий. * /

class TasksAdapter(private val viewModel: TaskListViewModel) :
        ListAdapter<Task, CustomViewHolder>(TaskDiffCallback()) {

    override fun onBindViewHolder(holder: CustomViewHolder, position: Int) {
        val item = getItem(position)

        holder.bind(viewModel, item)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomViewHolder {
        return CustomViewHolder.from(parent)
    }

    class CustomViewHolder private constructor(val binding: TaskItemBinding) :
            RecyclerView.ViewHolder(binding.root) {

        fun bind(viewModel: TaskListViewModel, item: Task) {

            binding.viewmodel = viewModel
            binding.task = item
            binding.executePendingBindings()
        }

        companion object {
            fun from(parent: ViewGroup): CustomViewHolder {
                val layoutInflater = LayoutInflater.from(parent.context)
                val binding = TaskItemBinding.inflate(layoutInflater, parent, false)

                return CustomViewHolder(binding)
            }
        }
    }
}

/**
 * Callback for calculating the diff between two non-null items in a list.
 *
 * Used by ListAdapter to calculate the minimum number of changes between and old list and a new
 * list that's been passed to `submitList`.
 */
class TaskDiffCallback : DiffUtil.ItemCallback<Task>() {
    override fun areItemsTheSame(oldItem: Task, newItem: Task): Boolean {
        return oldItem.id == newItem.id
    }

    override fun areContentsTheSame(oldItem: Task, newItem: Task): Boolean {
        return oldItem == newItem
    }
}
person Thracian    schedule 31.07.2019