о том, как это сделать. Вы можете найти это полезным.

е удалось создать ViewModel для компонентов Architecuture для Android, который объединяет несколько моделей LiveData в один класс LiveData для наблюдения за моим фрагментом. Я хочу скрыть детали модели от фрагмента и реагировать на изменения внешних данных через отдельные модели.

Проблема в том, что мне нужна ViewModel для наблюдения за изменениями модели, но ViewModel не LifecycleOwner, поэтому он не может наблюдать. Поскольку я не хочу передавать объекты LiveData в пользовательский интерфейс, я застрял.

Это возможно? Нужно ли отказываться от LiveData для моих моделей и прибегать к другой схеме наблюдения / инструменту?

Редактировать: Добавлен псевдокод. Мои настоящие занятия намного сложнее и продолжительнее. Я надеюсь, что мои намерения понятны.

// OneDataModel.kt
class oneDataModel {
    val oneDataElement = ""
}

// AnotherDataModel.kt
class anotherDataModel {
    val anotherDataElement = 19
}

// OneDataRepository.kt
class OneDataRepository {
    val oneDataSet = MutableLiveData<MutableList<oneDataModel>>()

    private val dataListener = object: ChildEventListener {
        override fun onChildAdded(snapshot: DataSnapshot, p1: String?) {
            val newChild = snapshot.getValue(oneDataModel::class.java)
            if (newChild != null) {
                oneDataSet.value?.add(newChild)
            }
        }
    }

    init {
        oneDataSet.value = mutableListOf<oneDataModel>()
        OneNetworkDataTable.addListener(dataListener)
    }
}

// AnotherDataRepository.kt
class AnotherDataRepository {
    var anotherDataSet = MutableLiveData<MutableList<anotherDataModel>>()

    private val dataListener = object: ChildEventListener {
        override fun onChildAdded(snapshot: DataSnapshot, p1: String?) {
            val newChild = snapshot.getValue(anotherDataModel::class.java)
            if (newChild != null) {
                anotherDataSet.value?.add(newChild)
            }
        }
    }

    init {
        anotherDataSet.value = mutableListOf<anotherDataModel>()
        AnotherNetworkDataTable.addListener(dataListener)
    }
}

// ComposedViewModel.kt
class ComposedViewModel: ViewModel() {
    class ComposedItem {
        var dataName: String = ""   // From OneDataRepository items
        var dataValue: Int = -1     // From AnotherDataRepository items
    }
    var publishedDataSet = MutableLiveData<MutableList<ComposedItem>>()

    //***
    //*** WHAT GOES HERE? HOW DO I LISTEN TO EACH OF THE DATA REPOSITORIES AND BUILD UP COMPOSED
    //*** ITEMS FOR THE UI?
    //***
}

// MyFragment.kt
class MyFragment : Fragment() {
    private val composedViewModel: ComposedViewModel by lazy { ViewModelProviders.of(activity).get(ComposedViewModel::class.java) }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.fragment_feed, container, false)

        recyclerView.adapter = UIAdapter

        composedViewModel.publishedDataSet.observe(this, Observer {
            UIAdapter.notifyDataSetChanged()
        })

        return view
    }
}
 Long Ranger28 сент. 2017 г., 06:32
Надеюсь, моя мысль верна. Вещь, которую вы хотите сделать, - это удалить жилые данные "ключ_данныхDataSet» в операторе составеViewViewModel.publishedDataSet.observe (..., ...) и кое-что из того, как фрагмент может иметь видовую модель, которую можно наблюдать автоматически, и обновить пользовательский интерфейс. ?
 Long Ranger27 сент. 2017 г., 03:58
Не могли бы вы предоставить пример кода для вашего вопроса? Трудно понять это без кода.
 19Craig28 сент. 2017 г., 15:46
Спасибо, @Long Ranger, это подход, который я применил к ветке, так как застрял. Что мне не нравится в этом, так это то, что моя ViewModel в основном пуста, просто передавая элементы LiveData. Это означает, что фрагмент и адаптер должны понимать схему базы данных, чтобы знать, где получить то, что им нужно. Это больше похоже на MVC или MVP, что я не думаю, что AAC намеревается.

Ответы на вопрос(2)

Решение Вопроса

Я уже делал пример проекта и теперь интегрирую в эту модель представления другие поддельные жилпаты.Разница в файле

использованиеMediatorLiveData класс, чтобы обернуть несколько источников данных в один.

FeedEntryListViewModel.java

public class FeedEntryListViewModel extends ViewModel {

  //list all your live data here
  private LiveData<List<FeedEntry>> feedEntries = new MutableLiveData<>();
  private MutableLiveData<String> userId = new MutableLiveData<>();
  //show your composite model here
  private MediatorLiveData<CompositeModel> compositeModelLiveData;

  //list all your repository
  private FeedEntryRepository feedEntryDBRepository;

  /*
  The complete model to show the data
   */
  public static class CompositeModel {

    String userId = "SystemId";
    private List<FeedEntry> feedEntries = new ArrayList<>();


    public String getUserId() {
      return userId;
    }

    public void setUserId(String userId) {
      this.userId = userId;
    }

    public List<FeedEntry> getFeedEntries() {
      return feedEntries;
    }

    public void setFeedEntries(
        List<FeedEntry> feedEntries) {
      this.feedEntries = feedEntries;
    }


  }

  public FeedEntryListViewModel(
      FeedEntryRepository feedEntryDBRepository) {
    this.feedEntryDBRepository = feedEntryDBRepository;
    this.feedEntries = feedEntryDBRepository.getAll();
    this.compositeModelLiveData = new MediatorLiveData<>();
    this.compositeModelLiveData.addSource(feedEntries, data ->
    {
      CompositeModel compositeModel = compositeModelLiveData.getValue();
      compositeModel.setFeedEntries(data);
      compositeModelLiveData.postValue(compositeModel);
    });
    this.compositeModelLiveData.addSource(userId, data -> {
      CompositeModel compositeModel = compositeModelLiveData.getValue();
      compositeModel.setUserId(data);
      compositeModelLiveData.postValue(compositeModel);
    });
    //initialize the composite model to avoid NullPointerException
    this.compositeModelLiveData.postValue(new CompositeModel());
  }

  public void loadUserId(String userId) {
    this.userId.setValue(userId);
  }

  public LiveData<List<FeedEntry>> getFeedEntrys() {
    return feedEntryDBRepository.getAll();
  }

  public LiveData<CompositeModel> getCompositeEntrys() {
    return compositeModelLiveData;
  }

  public LiveData<List<FeedEntry>> insert(FeedEntry... feedEntries) {
    feedEntryDBRepository.insertAll(feedEntries);
    return feedEntryDBRepository.getAll();
  }

  public void delete(FeedEntry feedEntry) {
    feedEntryDBRepository.delete(feedEntry);
  }


  public int update(FeedEntry feedEntry) {
    return feedEntryDBRepository.update(feedEntry);
  }

}

В Деятельности вы все еще можете получить композит с оператором

viewModel.getCompositeEntrys().observe(this, entries -> {...});

View Model Constructor добавляет живые данные и привязывает к составным живым данным

 public FeedEntryListViewModel(
      FeedEntryRepository feedEntryDBRepository) {
    this.feedEntryDBRepository = feedEntryDBRepository;
    this.feedEntries = feedEntryDBRepository.getAll();
    this.compositeModelLiveData = new MediatorLiveData<>();
    this.compositeModelLiveData.addSource(feedEntries, data ->
    {
      CompositeModel compositeModel = compositeModelLiveData.getValue();
      compositeModel.setFeedEntries(data);
      compositeModelLiveData.postValue(compositeModel);
    });
    this.compositeModelLiveData.addSource(userId, data -> {
      CompositeModel compositeModel = compositeModelLiveData.getValue();
      compositeModel.setUserId(data);
      compositeModelLiveData.postValue(compositeModel);
    });
    //initialize the composite model to avoid NullPointerException
    this.compositeModelLiveData.postValue(new CompositeModel());
  }
 19Craig29 сент. 2017 г., 17:04
Вы запускали этот код и видели, как данные модели попадают в составную модель и до наблюдателя? Я пробовал подобное с Media, torLiveData по пути без успеха. Ваш подход немного отличается от того, что я помню, поэтому я попробую еще раз.
 19Craig29 сент. 2017 г., 21:07
Работает! Когда я раньше пробовал MediatorLiveData, я ошибался. Правильный способ, как вы показываете, состоит в том, чтобы модели / хранилище публиковали свойства LiveData, а ViewModel объединял их в свойство MediatorLiveData, которое может наблюдать Фрагмент. Теперь мой фрагмент видит только ViewModel, а слой данных соответствующим образом скрыт. Спасибо.

Используйте реактивные потоки (RxJava) представлять вашу модельКонвертируйте ваши RxJava Observables в LiveData, используяlifecycle-reactivestreams из компонентов архитектуры.

ИспользуяRxJava Вы можете легко объединить наблюдаемые вместе и выставить эту комбинацию только на вид, используяLiveData, Я бы порекомендовал использоватьLiveData только выставить состояние на просмотр (Fragment или жеActivity).

Я написалстатья о том, как это сделать. Вы можете найти это полезным.

Ваш ответ на вопрос