-
Notifications
You must be signed in to change notification settings - Fork 531
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix #4, #70, #71, #86, #87: Introduce data module #85
Conversation
High-level notes: - Data sources are now being referred to as 'DataProviders' - This commit also fixes the build which was broken in a previous PR ('compile' needs to be used for the proto library) - The data source module is referred to as just 'data' - This introduces a few style changes to prohibit wildcard imports - This also normalizes the JDK versions needed across modules, potentially fixing some of the repeated reversions the IDE does for a Java SDK version setting Functional differences: the app now properly shows the correct string upon initial open ("Welcome to Oppia"), and reopening thereafter correctly shows the updated string ("Welcome back to Oppia"). Rotating the device is currently broken without Dagger integration. Overall, this moves all general data provider functionality into the new module, and introduces a PersistentCacheStore to store proto messages on-disk, or load them into memory if they are available. Overall, this commit is introducing a potentially reasonable medium-term solution for data providers and on-disk proto storage. A long-term design should still be determined, but this seems like a good place to start. Tests are currently broken or missing. New TODOs will also be resolved in a later commit.
This is loosely based on both https://github.com/tfcporciuncula/dagger-simple-way and https://dagger.dev/android.html, except this approach is meant to keep activities and fragments as thin as possible and push as much UI presentation and service business logic into Dagger-provided objects as possible. This maximizes Dagger use throughout the codebase, and opens the potential for future code generation for these thin adapter fragments & services. This fixes the rotation bug in the app: rotating upon the initial app open retains the 'Welcome to Oppia' label since the same user app history controller is used in both instances of HomeFragment due to it being singleton scoped and not needing to be recreated. No tests were updated with these changes.
modules & Dagger graph. Update HomeScreenActivityTest to include a new test for the second-app-launch test case. Note that a significant amount of the work going into this commit was around properly setting up tests to switch out their coroutine dispatchers with dispatchers that could be controlled in a test context. Although the affected test suites are passing in this commit, the work isn't quite done yet. Espresso and Robolectric require slightly different mechanisms to block on dispatchers, and with Gradle there isn't an easy way to set up the build graph such that Espresso can do this reliably. A temporary sleep-based workaround wad added for Espresso. Long-term, all tests should use Espresso's idling resource and facilitate proper background thread usage (which also simplifies the Robolectric side--no need to force sequential execution or switch the main thread dispatcher). Otherwise, this commit essentially "Dagger-ifies" the rest of the app. This will become more beneficial over time, especially after the codebase moves to Bazel since we'll be able to more easily swap out modules to change dependency implementations in different contexts.
…d into introduce-data-module
|
||
internal typealias ObserveAsyncChange = suspend () -> Unit | ||
|
||
// TODO(BenHenning): Move this to the Dagger graph rather than making it a singleton. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here and elsewhere (e.g. HomeActivityTest.kt): please link TODOs to issue numbers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your comment came before my commit to actually do this. :) Done.
subscriptionMap.enqueue(id, observeChange) | ||
} | ||
|
||
/** Ubsubscribes the specified callback function from the specified [DataProvider] ID. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Unsubscribes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
PersistentCacheStore. This fixes a few issues in PersistentCacheStore and the DataProvider->LiveData conversion (mostly to ensure that duplicate data notifications don't actually result in propagations to the UI). This also includes correct equals, hash code, and toString behavior for AsyncResult. The PersistentCacheStore tests aren't perfect, but they do expose some issues with the current implementation and seem to provide a reasonable breadth in core coverage. It may be worthwhile to eventually rewrite this class into something both cleaner and easier to maintain.
This is now ready to review. PTAL! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update comments as per JavaDocs.
Other than comments everything is good.
@BenHenning Maybe we can merge this for now and updates comments later on?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Thanks @rt4914. I'll follow up on your comment separately if needed. |
* Initial introduction of the data source module. High-level notes: - Data sources are now being referred to as 'DataProviders' - This commit also fixes the build which was broken in a previous PR ('compile' needs to be used for the proto library) - The data source module is referred to as just 'data' - This introduces a few style changes to prohibit wildcard imports - This also normalizes the JDK versions needed across modules, potentially fixing some of the repeated reversions the IDE does for a Java SDK version setting Functional differences: the app now properly shows the correct string upon initial open ("Welcome to Oppia"), and reopening thereafter correctly shows the updated string ("Welcome back to Oppia"). Rotating the device is currently broken without Dagger integration. Overall, this moves all general data provider functionality into the new module, and introduces a PersistentCacheStore to store proto messages on-disk, or load them into memory if they are available. Overall, this commit is introducing a potentially reasonable medium-term solution for data providers and on-disk proto storage. A long-term design should still be determined, but this seems like a good place to start. Tests are currently broken or missing. New TODOs will also be resolved in a later commit. * Data module dependencies, retrofit and models * Removed kapt from build.gradle in data * Javadoc comments * Introduce one possible integration with Dagger 2. This is loosely based on both https://github.com/tfcporciuncula/dagger-simple-way and https://dagger.dev/android.html, except this approach is meant to keep activities and fragments as thin as possible and push as much UI presentation and service business logic into Dagger-provided objects as possible. This maximizes Dagger use throughout the codebase, and opens the potential for future code generation for these thin adapter fragments & services. This fixes the rotation bug in the app: rotating upon the initial app open retains the 'Welcome to Oppia' label since the same user app history controller is used in both instances of HomeFragment due to it being singleton scoped and not needing to be recreated. No tests were updated with these changes. * Javadoc comments added * Reolved Javadoc mistakes * Renaming test cases * Test cases for TopicService * Made changes to OppiaGaeClient * Made changes to OppiaGaeClient * TopicService test code using Json response * Revert changes in codeStyles/Project.xml * Revert changes in codeStyles/Project.xml * Optimise imports * Check NetworkInterceptor part * Fix part of #9: Introduce Retrofit classroom data handler service (#83) * introduced topic index handler * Call retrofit data handlers from data module * Update topic_index_items.xml * removed extra space * fixed issues * Update AndroidManifest.xml * Removed Ui part. http handlers are included in data module * done changes in handler and data as per the specs * Update TopicSummarytDicts.kt * Update NetworkSettings.kt * added classroom datahandler * renamed corresponding classes to classroom * fixed issues * Update GaeClassroom.kt * removed spaces * Update AndroidManifest.xml * removed unwanted spaces * added space * Resolve typo * NetworkModule introduced * Daggerify NetworkInterceptor * Make retrofit dependency as api * Javadocs and linking of oppia-web to models * Changes in Javadoc, naming and test cases code * Updated TODO comments and NetworkInterceptorTest
First, this introduces a fully functioning data module. It also introduces a lot of constituent pieces in order to make that data module work:
Functionally, this results in the Oppia app now properly showing "Welcome to Oppia!" on initial app open, and "Welcome back to Oppia!" upon returning to the app. Both of these states are also properly retained across configuration changes due to Dagger not leading to activities trying to recreate their dependent controllers.
From a testing side, this added new HomeActivity tests which rely on sleeping rather than idling resource. Long-term once #59 is resolved, we'll be able to consolidate the
runBlockingTest
from Robolectric and idling resource from Espresso into a consistent blocker that waits for real background-executed coroutines to fully resolve before proceeding to continue in tests. In the meantime, this PR updates MainActivity's Espresso behavior to use the AndroidX test orchestrator and properly reset app state across test runs. This is essential to ensure the on-disk cache is removed and reinitialized in each test run.The Dagger introduction here is loosely based on a combination of https://proandroiddev.com/dagger-2-on-android-the-simple-way-f706a2c597e9 and a custom version of Dagger-Android (https://dagger.dev/android.html). We should eventually document and land on a final Dagger approach, but I like this implementation since it's simpler than Dagger-Android, and maximizes injectability. It introduces application, activity, and fragment scopes to provide more granular control over when dependencies should be recreated. It also introduces the concept of application, activity, and fragment controllers to perform actual logic, keeping activities and fragments essentially thin classes that delegate responsibility to their controllers. View models are also injectable, but I'm not sure whether we want to keep this long-term. In order to hook things up correctly, activities and fragments should extend special injectable base activity/fragment classes. Although this additional inheritance isn't great, it's reasonable if we don't add anything to these base classes. Long-term we might be able to replace this with code generation.
This PR introduces a fully-functioning DataProvider framework. This needs to be fully designed yet, as the current implementation will have value and error channel elision issues when converted to LiveData. However, this is a proposed start that lets us perform complex data pipeline transformations that are guaranteed to execute on background threads, and provides complete Kotlin coroutine interop. The conversion to LiveData also happens at the end, ensuring there's one LiveData per UI subscription (which I noticed was mentioned as a possible best practice somewhere, but I can't recall the source at the moment).
Finally, this PR also introduces an on-disk cache that's also a DataProvider. This cache stores protos and is expected to be a viable long-term replacement to SharedPreferences. I ran into a few issues with doing this in a clean way: in the test activity, we're setting that the user opened the app early on. However, we don't want this to change the on-disk file before it's read, and we don't want the change to notify subscribers. This resulted in added complexity:
This PR introduces reasonable tests for the components being covered here, but they are far from comprehensive. Observable behaviors in HomeActivity are at least tested, where all of the infrastructure introduced here is thoroughly integrated. Over time, these tests should be refined as the infrastructure itself matures. There's also some duplication between the tests that will be easier to clean up once #59 is resolved.