Android体系结构组件ViewModel可以由多个LiveData返回模型组成一个对象吗? [英] Can an Android Architecture Components ViewModel compose an object from multiple LiveData returning models?

查看:123
本文介绍了Android体系结构组件ViewModel可以由多个LiveData返回模型组成一个对象吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直无法创建一个Android Architecuture组件ViewModel,它将多个LiveData模型组合到一个LiveData类中,以供我的Fragment观察.我想从Fragment中隐藏模型详细信息,并通过各个模型来响应外部数据更改.

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. I want to hide the model details from the Fragment and respond to external data changes through the individual models.

问题是我需要ViewModel来观察模型的变化,但是ViewModel不是LifecycleOwner,因此它无法观察.因为我不想将LiveData对象传递给UI,所以我陷入了困境.

The problem is I need the ViewModel to observe the model changes but ViewModel is not a LifecycleOwner so it can't observe. Since I don't want to pass the LiveData objects through to the UI, I'm stuck.

这可能吗?我需要为模型放弃LiveData并使用其他观察模式/工具吗?

Is this possible? Do I need to abandon LiveData for my models and resort to a different observation pattern / tool?

编辑:添加了伪代码.我的实际课程更加复杂和冗长.我希望我的意图是可以理解的.

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.

我以前做过一个示例项目,现在将另一个伪造的livedata集成到此视图模型中. 文件差异

I have made a sample project before and now integrate another fake livedata into this view model. Difference of the file

使用 MediatorLiveData 类将多数据源包装到一个.

Use MediatorLiveData class to wrap multi data source to one.

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

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

View Model Constructor添加实时数据并绑定到复合实时数据

View Model Constructor add the live data and bind to the composite live data

 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());
  }

这篇关于Android体系结构组件ViewModel可以由多个LiveData返回模型组成一个对象吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆