基于MVVM架构,如何用RxJava从Room数据库获取数据
Implementing RxJava Data Fetch with Room in MVVM
Hey there! Let's get your RxJava-based data fetching up and running with Room in your MVVM setup. Here's a step-by-step breakdown of the changes you need to make:
1. Refine the UserRepository
First, let's add a method to expose the user data stream, and fix a small anti-pattern (your repo shouldn't handle UI like Toasts—we'll move that responsibility to the ViewModel/View later):
public class UserRepository { private UserDb userDb; private UserDao userDao; private Flowable<List<User>> allUsers; public UserRepository(Application application) { userDb = UserDb.getInstance(application); userDao = userDb.userDao(); // Configure thread scheduling for the data stream allUsers = userDao.getAllUsers() .subscribeOn(Schedulers.io()) // Run DB operations on background thread .observeOn(AndroidSchedulers.mainThread()); // Deliver results to main thread for UI updates } // Let the caller handle success/error by passing an observer public void insert(final User user, CompletableObserver observer){ Completable.fromAction(() -> userDao.insert(user)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(observer); } // Expose the user data stream to ViewModel public Flowable<List<User>> getAllUsers() { return allUsers; } }
Key Notes:
- We removed the
Contextreference from the repo—keeping UI logic out of repositories follows the single responsibility principle. - The
insertmethod now accepts aCompletableObserver, so the ViewModel can handle success/error notifications instead of the repo.
2. Update the ViewModel to Expose Data to the View
Next, modify your MainActivityViewModel to hold the user data stream and manage subscriptions safely:
public class MainActivityViewModel extends AndroidViewModel { private UserRepository repos; private Flowable<List<User>> allUsers; private CompositeDisposable compositeDisposable = new CompositeDisposable(); public MainActivityViewModel(@NonNull Application application) { super(application); repos = new UserRepository(application); allUsers = repos.getAllUsers(); } // Expose the user stream for the Activity/Fragment to subscribe to public Flowable<List<User>> getAllUsers() { return allUsers; } public void insertUser(User user, Context context) { CompletableObserver observer = new CompletableObserver() { @Override public void onSubscribe(Disposable d) { compositeDisposable.add(d); // Track the disposable to avoid memory leaks } @Override public void onComplete() { Toast.makeText(context, "Data inserted", Toast.LENGTH_SHORT).show(); } @Override public void onError(Throwable e) { Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show(); } }; repos.insert(user, observer); } // Clean up all subscriptions when ViewModel is destroyed @Override protected void onCleared() { super.onCleared(); compositeDisposable.dispose(); } }
Key Notes:
- We use a
CompositeDisposableto track active subscriptions—this ensures no lingering connections when the ViewModel is destroyed. - The ViewModel now handles UI feedback like Toasts, which is a more appropriate home for this logic.
3. Subscribe to Data in Your Activity
Finally, connect your ViewModel to the Activity to display and react to data changes:
public class MainActivity extends AppCompatActivity { private MainActivityViewModel viewModel; private CompositeDisposable activityDisposables = new CompositeDisposable(); private UserAdapter userAdapter; // Assume you have a RecyclerView adapter @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Initialize ViewModel viewModel = new ViewModelProvider(this).get(MainActivityViewModel.class); // Set up your RecyclerView and adapter here... // Subscribe to the user data stream Disposable userDisposable = viewModel.getAllUsers() .subscribe(users -> { // Update UI with the latest user list userAdapter.submitList(users); }, throwable -> { // Handle loading errors Toast.makeText(this, "Failed to load users: " + throwable.getMessage(), Toast.LENGTH_SHORT).show(); }); activityDisposables.add(userDisposable); } // Example: Trigger user insertion (e.g., from a button click) private void addSampleUser() { User newUser = new User("Jane Smith", "jane@example.com"); viewModel.insertUser(newUser, this); } @Override protected void onDestroy() { super.onDestroy(); activityDisposables.dispose(); // Clean up activity-level subscriptions } }
Key Notes:
- Room's
Flowable<List<User>>automatically emits a new list every time theUserstable is updated (insert, update, delete)—perfect for reactive UI updates. - RxJava's thread operators ensure database work stays off the main thread, keeping your app responsive.
Why This Works:
This setup follows MVVM best practices:
- Repositories handle raw data operations with Room and RxJava.
- ViewModels manage business logic and expose data streams to the UI.
- Views subscribe to these streams to render updates and handle user interactions.
内容的提问来源于stack exchange,提问作者Digvijay Singh Thakur
相关产品推荐
相关产品推荐

