Android - с использованием привязки данных, в действии вместо макета

Я работаю в шаблоне проектирования MVVM. Я хочу использовать dataBinding или RXJava, чтобы уведомлять представление об изменении модели. dataBinding может сделать это внутри xml. но я хочу уведомить Activity об изменении модели и сделать что-то более сложное. предположим, я хочу, чтобы мой TextView менял цвет, когда текст не пуст. Вы можете помочь мне сделать это через dataBinding или RXJava?

вот мой код:

XML

<?xml version="1.0" encoding="utf-8"?>

<data>

    <variable
        name="viewModel"
        type="edi.com.mydatabindingsimple.MyViewModel" />
</data>

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <EditText
        android:id="@+id/editText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="@={viewModel.txt}" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@={viewModel.txt}" />

</LinearLayout>

Мероприятия

import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import edi.com.mydatabindingsimple.databinding.ActivityMainBinding;

    public class MainActivity extends AppCompatActivity {

        MyViewModel viewModel = new MyViewModel();

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            final ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
            binding.setViewModel(viewModel);
        }
    }

видМодель

    import android.databinding.BaseObservable;
import android.databinding.Bindable;



public class MyViewModel extends BaseObservable{
    private String txt;

    @Bindable
    public String getTxt() {
        return txt;
    }

    public void setTxt(String txt) {
        this.txt = txt;
        notifyPropertyChanged(edi.com.mydatabindingsimple.BR.txt);
    }

}

person ediBersh    schedule 28.03.2017    source источник
comment
но я хочу уведомить Activity об изменении модели и сделать что-то посложнее.. Почему активность? Виртуальная машина получает изменения и уведомляет свойства. Это должно быть все. Если привязка не поддерживается изначально, вы можете использовать @BindingAdapter, чтобы добавить свою собственную   -  person Blackbelt    schedule 28.03.2017
comment
спасибо за ответ черный пояс. Я прочитал о @BindingAdapter и понял, что его можно использовать только в установщике. но мне это нужно в геттере. на случай, если мне нужен логический флаг в моей модели, который говорит мне показать/скрыть вид   -  person ediBersh    schedule 28.03.2017
comment
поэтому добавьте android:background="@{viewModel.textViewColor}" в свой <TextView> и добавьте метод @Bindable int getTextViewColor() в MyViewModel   -  person pskink    schedule 29.03.2017
comment
@pspink, спасибо за ответ, но я не хочу делать это напрямую в xml. конечно, это будет работать в этом конкретном случае, но если я хочу, чтобы моя модель представления сообщала, что представление должно быть видимым, не зная постоянного числа View.Visible, я ожидаю, что действие справится с этим.   -  person ediBersh    schedule 29.03.2017
comment
Итак, некоторые свойства представления вы хотите установить в xml/presenter/view-model (например, android:text), а некоторые (например, android:background) через активность? имеет ли это смысл? но, конечно, вы все еще можете вызывать viewModel.addOnPropertyChangedCallback(...) внутри MainActivity#onCreate, поэтому теперь, когда ваш текст изменяется, обратный вызов вызывается в вашей деятельности, но... после добавления обратного вызова ваша модель представления имеет ссылку на действие. это то, чего вы хотели бы избежать...   -  person pskink    schedule 30.03.2017
comment
@pskink Я согласен, что это не имеет смысла, но что я могу сделать в случае сложного изменения пользовательского интерфейса (например, скрытия клавиатуры)? я не могу сделать это, изменив атрибут xml, но я все еще не хочу создавать обратный вызов, что означает добавление ссылки на Activty и нарушение архитектуры MVVM.   -  person ediBersh    schedule 30.03.2017
comment
честно говоря? я не знаю другого способа, если действие, которое вы хотите выполнить, полностью не зависит от данных модели (например, изменение цвета текста текста EditText в зависимости от его длины), вы можете сделать это, просто предоставив некоторые обратные вызовы в вашей деятельности (например, TextWatcher) , но если это должно зависеть от данных модели, необходимо сделать некоторую ссылку на Activty   -  person pskink    schedule 30.03.2017


Ответы (1)


Что вы можете сделать, так это создать механизм обратного вызова для запуска метода в вашей деятельности. Это все равно сначала уведомит ViewModel, но эффект будет таким же.

Вы можете создать новый интерфейс (или добавить его внутри ViewModel)

public interface ViewModelCallback{
   void ActionCallback();
}

В вашей деятельности:

public class MainActivity extends AppCompatActivity implements ViewModelCallback

В вашей ViewModel

private ArrayList<ViewModelCallback> callbacks = new ArrayList<>();

public void notifyCallbacks(){
  for(ViewModelCallback c : callbacks){
     if(c != null){
         c.ActionCallback
      }
   }
}

public void addCallback(ViewModelCallback c){
     callbacks.add(c);
}

Вызовите notifyCallback после вашего NotifyPropertyChanged(). И не забудьте добавить свою активность в качестве обратного вызова в onCreate.

viewModel.addCallback(this)

Вы также должны удалить его в onDestroy.

person Arthur Attout    schedule 28.03.2017
comment
спасибо, но я не хочу, чтобы в моей модели представления была ссылка на действие. это противоречит принципам MVVM. - person ediBersh; 28.03.2017
comment
Я не уверен в этом, это просто обратный вызов, и он не использует код, подходящий для Android. И вы быстро поймете, что такой трюк не означает, что ваше приложение не следует принципу MVVM (точно так же, как код в WPF. Код позади не означает автоматически нарушение MVVM) - person Arthur Attout; 28.03.2017