简体   繁体   English

我们如何在ViewModel中将LiveData从Room“分配”到MutableLiveData

[英]How can we “assign” LiveData from Room to MutableLiveData, within ViewModel

Recently, I am stuck with the following code. 最近,我坚持使用以下代码。

public class NoteViewModel extends ViewModel {

    private final MutableLiveData<List<Note>> notesLiveData = new MutableLiveData<>();

    public NoteViewModel() {
        LiveData<List<Note>> notesLiveDataFromRepository = NoteRepository.INSTANCE.getNotes();

        // How can I "assign" LiveData from Room, to MutableLiveData?
    }

}

I was wondering, how can I "assign" LiveData from Room , to MutableLiveData ? 我在想,我怎么能“分配” LiveDataRoom ,到MutableLiveData

Using Transformation.map and Transformation.switchMap wouldn't work, as both returns LiveData , not MutableLiveData . 使用Transformation.mapTransformation.switchMap不起作用,因为它们都返回LiveData ,而不是MutableLiveData


Possible workaround 可能的解决方法

One of the possible solution is that, instead of 其中一个可能的解决方案是,而不是

@Dao
public abstract class NoteDao {
    @Transaction
    @Query("SELECT * FROM plain_note")
    public abstract LiveData<List<Note>> getNotes();

I will use 我会用的

@Dao
public abstract class NoteDao {
    @Transaction
    @Query("SELECT * FROM plain_note")
    public abstract List<Note> getNotes();

Then, in my ViewModel , I will write 然后,在我的ViewModel ,我会写

public class NoteViewModel extends ViewModel {
    private final MutableLiveData<List<Note>> notesLiveData = new MutableLiveData<>();

    public NoteViewModel() {
        new Thread(() -> {
            List<Note> notesLiveDataFromRepository = NoteRepository.INSTANCE.getNotes();
            notesLiveData.postValue(notesLiveDataFromRepository);
        }).start();
    }

}

I don't really like this approach, as I'm forced to handle threading thingy explicitly. 我真的不喜欢这种方法,因为我被迫明确处理线程化问题。

Is there a better way, to avoid handling threading explicitly? 有没有更好的方法,以避免明确处理线程?

The trick is to not do any of the actual fetching in the view model. 诀窍是不在视图模型中进行任何实际的提取。

Getting data, be it from network or database, should be done in the repository. 从网络或数据库获取数据应该在存储库中完成。 The ViewModel should be agnostic in this regard. 在这方面,ViewModel应该是不可知的。

In the ViewModel, use the LiveData class, not MutableLiveData. 在ViewModel中,使用LiveData类,而不是MutableLiveData。 Unless you really find a use case for it. 除非你真的找到它的用例。

// In your constructor, no extra thread
notesLiveData = notesLiveDataFromRepository.getAllNotes();

Then in your repository you can have the logic in the getAllNotes() method for determining where those notes are coming from. 然后在您的存储库中,您可以使用getAllNotes()方法中的逻辑来确定这些注释的来源。 In the repository you have the MutableLiveData. 在存储库中,您拥有MutableLiveData。 You can then postValue to that, from a thread that is getting the data. 然后,您可以从获取数据的线程postValue。 That isn't necessary for room though, that is handled for you. 这对于房间来说不是必需的,这是为你处理的。

So in your repository you would have another LiveData being returned that is backed directly from a DAO method. 因此,在您的存储库中,您将返回另一个直接从DAO方法支持的LiveData。

In that case, you need to stick with public abstract LiveData<List<Note>> getNotes(); 在这种情况下,您需要坚持使用public abstract LiveData<List<Note>> getNotes(); .

Activity 活动

public class MyActivity extends AppCompatActivity {

    private MyViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Set up your view model
        viewModel = ViewModelProviders.of(this).get(MyViewModel.class);

        // Observe the view model
        viewModel.getMyLiveData().observe(this, s -> {
            // You work with the data provided through the view model here.
            // You should only really be delivering UI updates at this point. Updating
            // a RecyclerView for example.
            Log.v("LIVEDATA", "The livedata changed: "+s);
        });

        // This will start the off-the-UI-thread work that we want to perform.
        MyRepository.getInstance().doSomeStuff();
    }
}

ViewModel 视图模型

public class MyViewModel extends AndroidViewModel {

    @NonNull
    private MyRepository repo = MyRepository.getInstance();

    @NonNull
    private LiveData<String> myLiveData;

    public MyViewModel(@NonNull Application application) {
        super(application);
        // The local live data needs to reference the repository live data
        myLiveData = repo.getMyLiveData();
    }

    @NonNull
    public LiveData<String> getMyLiveData() {
        return myLiveData;
    }
}

Repository 知识库

public class MyRepository {

    private static MyRepository instance;

    // Note the use of MutableLiveData, this allows changes to be made
    @NonNull
    private MutableLiveData<String> myLiveData = new MutableLiveData<>();

    public static MyRepository getInstance() {
        if(instance == null) {
            synchronized (MyRepository.class) {
                if(instance == null) {
                    instance = new MyRepository();
                }
            }
        }
        return instance;
    }

    // The getter upcasts to LiveData, this ensures that only the repository can cause a change
    @NonNull
    public LiveData<String> getMyLiveData() {
        return myLiveData;
    }

    // This method runs some work for 3 seconds. It then posts a status update to the live data.
    // This would effectively be the "doInBackground" method from AsyncTask.
    public void doSomeStuff() {
        new Thread(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException ignored) {
            }

            myLiveData.postValue("Updated time: "+System.currentTimeMillis());
        }).start();
    }

}

Very simple. 非常简单。

class MainViewModel: ViewModel() {

    @Inject lateinit var currencyRepository: CurrencyRepository

    val notifyCurrencyList = MediatorLiveData<List<Currency?>>()

    init {
        CurrencyApplication.component.inject(this)
    }

    fun loadCurrencyList() {
        notifyCurrencyList.addSource(currencyRepository.loadLatestRates()) {
            notifyCurrencyList.value = it
        }
    }


}

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM