简体   繁体   English

Android架构组件ViewModel可以从多个LiveData返回模型组成一个对象吗?

[英]Can an Android Architecture Components ViewModel compose an object from multiple LiveData returning models?

I've been unable to create an Android Architecuture Components ViewModel that composes multiple LiveData models into one LiveData class for my Fragment to observe. 我无法创建一个Android Architecuture组件ViewModel,它将多个LiveData模型组合成一个LiveData类,供我的Fragment观察。 I want to hide the model details from the Fragment and respond to external data changes through the individual models. 我想隐藏片段中的模型细节,并通过各个模型响应外部数据更改。

The problem is I need the ViewModel to observe the model changes but ViewModel is not a LifecycleOwner so it can't observe. 问题是我需要ViewModel来观察模型更改,但ViewModel不是LifecycleOwner,因此无法观察。 Since I don't want to pass the LiveData objects through to the UI, I'm stuck. 由于我不想将LiveData对象传递给UI,因此我陷入困境。

Is this possible? 这可能吗? Do I need to abandon LiveData for my models and resort to a different observation pattern / tool? 我是否需要为我的模型放弃LiveData并采用不同的观察模式/工具?

Edit: Pseudocode added. 编辑:添加了伪代码。 My actual classes are much more complex and lengthy. 我的实际课程更加复杂和冗长。 I hope my intent is understandable. 我希望我的意图是可以理解的。

// 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
    }
}

Hope my work satisfy your question. 希望我的工作满足你的问题。

I have made a sample project before and now integrate another fake livedata into this view model. 我之前制作了一个示例项目,现在将另一个假的liveata集成到这个视图模型中。 Difference of the file 文件的差异

Use MediatorLiveData class to wrap multi data source to one. 使用MediatorLiveData类将多数据源包装为一个。

FeedEntryListViewModel.java 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);
  }

}

In the Activity, you still can get the composite with the statement 在Activity中,您仍然可以使用该语句获取复合

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

View Model Constructor add the live data and bind to the composite live data 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());
  }

I would suggest to take a different approach: 我建议采取不同的方法:

  • Use reactive streams ( RxJava ) to represent your model 使用反应流( RxJava )来表示您的模型
  • Convert your RxJava Observables into LiveData using lifecycle-reactivestreams from the Architecture Components. 使用Architecture Components中的lifecycle-reactivestreams流将您的RxJava Observable转换为LiveData。

By using RxJava you can easily merge observables together and only expose that combination to the view using LiveData . 通过使用RxJava,您可以轻松地将可观察对象合并在一起,并且仅使用LiveData将该组合公开给视图。 I would recommend to use LiveData only to expose state to the view ( Fragment or Activity ). 我建议仅使用LiveData将状态公开给视图( FragmentActivity )。

I wrote an article on how to do this. 我写了一篇关于如何做到这一点的文章 You might find it useful. 你可能会发现它很有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Android体系结构组件:如何通过ViewModel观察存储库中的LiveData - Android Architecture Components: How is LiveData in the repository observed by a ViewModel Android Architecture Components如何结合数据库和网络中的LiveData? - Android Architecture Components how to combine LiveData from both database and network? 使用 Android 架构组件 LiveData &amp; ViewModel 时是否需要使用 onSaveInstanceState 和 onRestoreInstanceState? - Is there any need to use onSaveInstanceState and onRestoreInstanceState when using Android Architecture Components LiveData & ViewModel? Android架构组件,Android绑定和LiveData - Android Architecture Components, android binding and LiveData Android架构组件ViewModel上下文 - Android Architecture Components ViewModel Context Android架构组件:绑定到ViewModel - Android Architecture Components: bind to ViewModel 谁能解释在Android中实现MVVM架构时如何使用ViewModel和LiveData - Can any one explain how to use ViewModel and LiveData while implementing MVVM architecture in android Android MVVM,您可以在ViewModel中使用另一个LiveData对象观察LiveData吗? - Android MVVM, can you observe LiveData inside an ViewModel with another LiveData object? 如何使用 Android 的架构组件从 ViewModel 完成活动? - How to finish activity from ViewModel using Android's architecture components? 架构组件刷新LiveData - Architecture Components refresh LiveData
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM