A few months ago when the initial proposal was drawn, MusicBrainz for Android had a brittle interface. There was hardly any screen free of fatal errors and crashes. Hence, the proposal aimed at eliminating these instability issues. This included rearchitecting the application where necessary, adding tests and incorporating android best practices.
The entire work scoped across three repositories:
The list of commits is available during the span of GSoC period is available here.
To begin with, the Repositories for fetching data from MusicBrainz server were refactored. Every screen had a different repository, hence, there was a lot of code duplication. This also meant that a feature had to be added at multiple places. The approach was essentially bug prone. For instance, the searching for artists produced a fatal whereas other searches worked well. The issue was solved using Java Generics. Now, there is a single LookupRepository
which is utilised by all entities' ViewModels
.
Next comes in dependency injection. Dependency Injection had a huge role to play in writing good unit tests. Dagger Hilt is awesome. Using a few lines of annotations, Hilt made it possible to switch from static methods to constructor injected components. Let's take the example of LookupRepository
to understand the importance. As static methods went away, the LookupRepository
class could extracted in form of an interface. The interface acts as a public contract. As long as the LookupRepository
interface remains unchanged, the actual underlying implementation can be changed without affecting any other part of the app. This is great for testing as we can now just inject a test double to unit test the view models. The same example goes for Retrofit
Service classes.
To further eliminate UI errors, ViewBinding
was introduced. Its a really nice development tool. Whenever a breaking change is introduced in the UI files without making the required changes in the the associated Java/Kotlin code, the project fails to compile. This saves valuable developer time as the errors show themself at compile time with clear stack traces. No fuss of debugging a wrong findViewById
call at runtime. Live Data Transformations
have been heavily leveraged inside the app to follow best practices and avoid unnecessary usage of data from previous attempts.
Then come the actual tests, a good chunk of tests have been written around each component of the search and entiry pages. There are unit tests for each entity json to POJO conversion, fetchData
calls to repository and entity ViewModels
. The number of integration tests is however few and a work in progress. Furthermore, using CircleCI
all commits and pull requests are tested to produce a valid apk and pass the unit tests.
Other than the scope of the project, it was realised that certain features from other Brainz projects should be incorporated in the app as well. As a matter of fact, the application now supports submitting listens. A lot of work has to be done in this regard though. Also, the capability of submitting acoustic data to AcousticBrainz
work has been done on producing a mobile client for AcousticBrainz
. The underlying library is ready for use but is on hold for now till some discrepancies with resolved with the upstream developers.
It has been a long road of development this summer. The biggest challenge I faced rearchitecting the application with a view to make it more maintainable and retain the code readability as well. However, the task I spent the most time on was getting instrumentation tests to run. After spending eight days on debugging, the bug fix turned out to be just 20 characters long. The issue was due inconsistent behaviour of the Android Gradle Plugin
while building test and release applications.
MusicBrainz Android is a living project with a lot of scope of improvements.
Support More tags in tagger feature.
Provide better listening support.
Increasing test coverage.
Write a better wrapper for chromaprint.
Add support for remaining MusicBrainz entities.
Display relevant data about MusicBrainz entities from AcousticBrainz and CritiqueBrainz.