簡體   English   中英

我們如何在ViewModel中將LiveData從Room“分配”到MutableLiveData

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

最近,我堅持使用以下代碼。

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

}

我在想,我怎么能“分配” LiveDataRoom ,到MutableLiveData

使用Transformation.mapTransformation.switchMap不起作用,因為它們都返回LiveData ,而不是MutableLiveData


可能的解決方法

其中一個可能的解決方案是,而不是

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

我會用的

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

然后,在我的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();
    }

}

我真的不喜歡這種方法,因為我被迫明確處理線程化問題。

有沒有更好的方法,以避免明確處理線程?

訣竅是不在視圖模型中進行任何實際的提取。

從網絡或數據庫獲取數據應該在存儲庫中完成。 在這方面,ViewModel應該是不可知的。

在ViewModel中,使用LiveData類,而不是MutableLiveData。 除非你真的找到它的用例。

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

然后在您的存儲庫中,您可以使用getAllNotes()方法中的邏輯來確定這些注釋的來源。 在存儲庫中,您擁有MutableLiveData。 然后,您可以從獲取數據的線程postValue。 這對於房間來說不是必需的,這是為你處理的。

因此,在您的存儲庫中,您將返回另一個直接從DAO方法支持的LiveData。

在這種情況下,您需要堅持使用public abstract LiveData<List<Note>> getNotes();

活動

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

視圖模型

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

知識庫

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

}

非常簡單。

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