android - 我们如何在 ViewModel 中将 "assign"LiveData 从 Room 转移到 MutableLiveData

标签 android android-architecture-components

最近,我被下面的代码困住了。

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

}

我想知道,如何将 Room 中的 LiveData“分配”到 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();
    }

}

我不太喜欢这种方法,因为我不得不显式地处理线程问题。

是否有更好的方法来避免显式处理线程?

最佳答案

诀窍是不在 View 模型中进行任何实际的抓取。

无论是从网络还是数据库获取数据,都应该在存储库中完成。 ViewModel 在这方面应该是不可知的。

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

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

然后在您的存储库中,您可以在 getAllNotes() 方法中使用逻辑来确定这些注释的来源。在存储库中,您有 MutableLiveData。然后,您可以从获取数据的线程向其发布值。不过,这不是房间所必需的,而是为您处理的。

因此,在您的存储库中,您将返回另一个直接从 DAO 方法支持的 LiveData。

在这种情况下,您需要坚持使用 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();
    }
}

View 模型

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

}

关于android - 我们如何在 ViewModel 中将 "assign"LiveData 从 Room 转移到 MutableLiveData,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49602606/

相关文章:

java - 更新对应于数据库行的 ListView 行中的 CheckBox

javascript - 安卓 WebView : Handle arrow keys in JavaScript

android - 在 RxJava MVVM 中组合不同的源(FCM、网络、ROOM)

android - 连接 ROOM 数据库中的表

android - 分页库 - 一个具有多种 View 类型的回收器

android - 我如何使用 ActivityResultLauncher.GetContent() 请求多个 MIME 类型?

android - 在通知中使用大图标时出现 java.lang.NoClassDefFoundError

java - Android:如何从 Sqlite 中求和实际值?

android - ViewModel 状态如何自动更新

android - 房间查询 : find within list is always returning null