Is it good practice implementing Parcelable on a Room database entity? - android

I'm brushing on my Android dev skills and have been playing around with the Architecture Components. So I created an entity class using Room annotations for persistence to the database and implemented Parcelable on the entity class partly for the purpose of putting the entity object into an Intent object and passing it between activities/fragments. I just want to know if this is a good practice. Are there any cons of using such approaches such as database leaks or security flaws? Just curious.

I just want to know if this is a good practice.
IMHO, in modern Android app development, no, for a few reasons, including:
Repository pattern: The current pattern in Android app architecture is to isolate data storage and transfer concerns into a "repository" object. The repository knows the details of where the data is coming from and going to (Room, Realm, Retrofit, etc.). The rest of the app neither knows nor cares, as the rest of the app just talks to the repository. With this pattern, you would pass identifiers around between activities and fragments, and the repository would hand over model objects based on those identifiers.
Hide implementation details: Your UI should work with an ideal set of model classes, ones that are not tied to particular implementations of data storage or transfer. That way, should you elect to change your implementation (e.g., from Room to Realm), your changes remain isolated and should have little effect on the UI. If you use a repository, the repository would be responsible for converting from Room entities and Retrofit responses into standardized model objects that the rest of the app knows how to use.
Single source of truth: Once you start passing objects around via Intent extras, you are making copies. If one part of your app then wishes to modify that model object... how will the rest of the app, holding other copies of the data, know about those changes? Ideally, you have a repository with a reactive API, where the repository is the party that makes the data changes. It can then notify other interested parties about the data changes, delivering an up-to-date rendition of the model object.
IPC memory limits: Every time you use an Intent with startActivity(), startActivityForResult(), setResult(), etc., the contents of that Intent are passed to a core OS process... even if the activity being started is in the same process as the code that is requesting that activity be started. There are memory limits for how big an Intent can be (roughly speaking, 1MB or lower). Passing full model objects around may work fine right now, but later if somebody adds a Bitmap field or something to the model, you can get in trouble.

Related

Can a use case be called in data layer in context of Clean Architecture?

I have read a couple articles about clean architecture concepts here and here and others.
I think I understand what is going on but they didn't solve the question that I have.
I wonder if a use case can be called from data layer. if so, how? if not why?
UPDATE:
what I am trying to do is to track what is happening during each usecase with a event usecase. Sometimes, I need to collect those info in data layer as well.
Let's say I have
CollectEventUseCase
for that event usecase. I want to track if a person data lookup from network was fail but successful from database during the LookupPersonUsecase and I want to collect that information that lookup was failed from network but successful from database, is this a bad idea to call CollectEventUseCase in data layer? is this okay solution to this case? or whatelse should be the right approach?
Short Answer - No, in a CLEAN architecture the data layer should not be calling through to a use case as it would be breaking the separation of concerns. Data layer should only be concerned with data, not business logic which lives in a use case.
Long Answer
One main reason for implementing a CLEAN architecture is for implementing separation of concerns, meaning each layer addresses a specific concern in your app. Expanding on the photo in domain layer Android documentation, an app architecture might look like the picture below.
Where the domain layer would contain all of the business logic for presentation and use cases which can communicate with different sources in the data layer.
The data layer exists to serve as an abstraction over where data is coming from and that should be its only responsibility. Most apps data layers are fetching data from the network and then caching that data in a local database. So to best separate the concerns, a use case should only be concerned about interacting with different sources from the data layer and any business logic.

Using LiveData and ViewModel without using Room

For android MVVM architecture, in all the examples that I have seen, people either use Room to store/retrieve data or they get data directly from API calls through the Repository class.
I'm neither doing an API call nor using I have Room database to store data. But I need my ViewModel to get the data from the repository and pass it to my Actvity.
Can your Repository class inherit from Application class so that you can save static variables/companion objects if you don't intend to use Room for saving data locally ?
What is a good way to handle this case?
In general, in Software Engineering a Repository is used to abstract the Data Layer (Database, Web Service) from the rest of the application (usually directly Business Tier), a good example would be this schema of a booking website:
It receives the updates via the Publish/Subscribe asynchronous connection and sends them to the other components. So the components are independent of each other.
So Repository is just a simple mediator class that is used to make the application more modular, so that you can swap out pieces easier, and make sure that the rest of the app doesn't bother with DB connections or HTTP calls and so on. So technically, you can inherit from Application (or anything else) and use it to save static variables and so on.
But as explained here:
The application object is not guaranteed to stay in memory forever, it will get killed. Contrary to popular belief, the app won’t be restarted from scratch. Android will create a new Application object and start the activity where the user was before to give the illusion that the application was never killed in the first place.
So it's entirely up to you, you can use the repository style as you wish, it's not at all tied to Room or anything else.

Is Content Provider an implementation of Repository Pattern?

Repository Pattern is defined by Hieatt and Rob Mee as design pattern that mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.
Basically it abstracts one or more I/O devices (cloud, disk, data base, etc) into a common collection-like interface where you can read, write, seek and delete data.
On Fernando Cejas's Android Clean Architecture, all data needed for the application comes from this layer through a repository implementation (the interface is in the domain layer) that uses a Repository Pattern with a strategy that, through a factory, picks different data sources depending on certain conditions.
However, as pointed out by professor Douglas Schmidt at Coursera course, content provider manages and mediates access to a central repository of data to one or more applications
In the book Programming Android, content providers are used as a Facade for a RESTful Web Service. This approach was initially presented by
Virgil Dobjanschi during Google I/O 2010.
Thus, instead of using content providers to access the local SQLite database, why not using it as the repository pattern itself?
Let's try to compare the Repository Pattern definition from the book "Patterns of Enterprise Application Architecture" by Martin Fowler
(with Dave Rice, Matthew Foemmel, Edward Hieatt, Robert Mee, and Randy Stafford) with what we know about ContentProviders.
The book states:
A Repository Mediates between the domain and data mapping layers using
a collection-like interface for accessing domain objects.
The important bit is accessing domain objects. So at first glance it seems that the repository pattern is only meant for accessing (querying) data. With a ContentProvider, however, you not only can access (read) data but also insert, update or remove data.
However, the book says:
Objects can be added to and removed from the Repository, as they can
from a simple collection of objects, and the mapping code encapsulated
by the Repository will carry out the appropriate operations behind the
scenes.
So, yes Repository and ContentProvider seem to offer the same operations (very high level point of view) although the book explicitly states simple collection of objects which is not true for ContentProvider as it requires android specific ContentValues and Cursor from Client (who uses a certain ContentProvider) to interact with.
Also, the book mentions domain objects and data mapping layers:
A Repository Mediates between the domain and data mapping layers
and
Under the covers, Repository combines Metadata Mapping (329) with a Query Object (316)
Metadata Mapping holds details of object-relational mapping in metadata.
Metadata Mapping basically means i.e. how to map a SQL column to a java class field.
As already mentioned ContentProvider returns a Cursor object from a query() operation. From my point of view a Cursor is not a domain object. Moreover, mapping from cursor to domain object must be done by the client (who uses a ContentProvider). So data mapping is completely missing in ContentProvider from my point of view. Furthermore, the client may have to use a ContentResolver too to get the domain object (data). In my opinion this API is a clear contradiction with the definition from the book:
Repository also supports the objective of achieving a clean separation
and one-way dependency between the domain and data mapping layers
Next let's focus on the core idea of the Repository pattern:
In a large system with many domain object types and many possible
queries, Repository reduces the amount of code needed to deal with all
the querying that goes on. Repository promotes the Specification
pattern (in the form of the criteria object in the examples here),
which encapsulates the query to be performed in a pure object-oriented
way. Therefore, all the code for setting up a query object in specific
cases can be removed. Clients need never think in SQL and can write
code purely in terms of objects.
ContentProvider requires a URI (string). So it's not really a "object-oriented way". Also a ContentProvider may need a projection and a where-clause.
So one could argue that a URI string is some kind of encapsulation as the client can use this string instead of writing specific SQL code for instance:
With a Repository, client code constructs the criteria and then passes
them to the Repository, asking it to select those of its objects that
match. From the client code's perspective, there's no notion of query
"execution"; rather there's the selection of appropriate objects
through the "satisfaction" of the query's specification.
ContentProvider using a URI (string) doesn't seem to contradict with that definition, but still misses the emphasized object-oriented way. Also strings are not reusable criteria objects that can be reused in a general way to compose criteria specification to "reduces the amount of code needed to deal with all the querying that goes on."
For example, to find person objects by name we first create a criteria
object, setting each individual criterion like so:
criteria.equals(Person.LAST_NAME, "Fowler"), and
criteria.like(Person.FIRST_NAME, "M"). Then we invoke
repository.matching(criteria) to return a list of domain objects
representing people with the last name Fowler and a first name
starting with M.
As you have already said (in your question) Repository is also useful to hide different data sources as an implementation detail the client doesn't know about.
This is true for ContentProviders and specified in the book:
The object source for the Repository may not be a relational database
at all, which is fine as Repository lends itself quite readily to the
replacement of the data-mapping component via specialized strategy
objects. For this reason it can be especially useful in systems with
multiple database schemas or sources for domain objects, as well as
during testing when use of exclusively in-memory objects is desirable
for speed.
and
Because Repository's interface shields the domain layer from awareness
of the data source, we can refactor the implementation of the querying
code inside the Repository without changing any calls from clients.
Indeed, the domain code needn't care about the source or destination
of domain objects.
So to conclude: Some definitions from Martin Fowler et al. book match the API of a ContentProvider (if you ignore the fact that the book emphasized object-oriented):
Hides the fact that a repository / ContentProvider has different data sources
Client never has to write a query in a datasource specific DSL like SQL. That is true for ContentProvider if we consider URI as not datasource specific.
Both, Repository and ContentProvider, have the same "high level" set of operations: read, insert, update and remove data (if you ignore the fact that Fowler talks a lot about object orientated and collection of objects whereas ContentProvider uses Cursor and ContentValues)
However, ContentProvider really misses some key points of the repository pattern as described in the book:
Since ContentProvider uses URI (also string for the where clause) a client can't reuse Matching Criteria objects. That is an important thing to note. The book clearly says that the repository pattern is useful "In a large system with many domain object types and many possible queries, Repository reduces the amount of code needed to deal with all the querying that goes on". Unfortunately, ContentProvider doesn't have Criteria objects like criteria.equals(Person.LAST_NAME, "Fowler") that can be reused and used to compose matching criterias (since you have to use strings).
ContentProvider miss entirely data mapping as it returns a Cursor. This is very bad because a client (who uses a ContentProvider to access data) has to do the mapping of Cursor to domain object. Furthermore, that means that client has knowledge of repository internals like name of columns. "Repository can be a good mechanism for improving readability and clarity in code that uses querying extensively." That certainly is not true for ContentProviders.
So no, a ContentProvider is not a implementation of the Repository pattern as defined in the Book "Patterns of Enterprise Application Architecture" because it misses at least two essential things I have pointed out above.
Also, please note that as the name of the book already suggests, the repository pattern is meant to be used for Enterprise Application where you do a lot of queries.
Android developers tend to use the term "Repository pattern" but don't actually mean the "original" pattern described by Fowler et al. (high reusability of Criterias for queries) but rather mean a interface to hide the underlying data source (SQL, Cloud, whatever) and domain object mapping.
More here: http://hannesdorfmann.com/android/evolution-of-the-repository-pattern
Short answer: a Contentprovider is a datasource and not a repository.
The purpose of SQL-Database/Android-Contentproviders/Repositories is to create/read/update/delete/find data
Repositories usually operate on high level busines specific java classes (like Customer, Order, Product, ....)
while SQL-Database and Android-Contentproviders operate on low level table, rows and colums as a datasource.
Because a SQL-Database is not a repository so an Android-Contentprovider is not a repository, too.
But you can implement a repository by using an underlying Contentprovider
I'll mention Dianne Hackborn (from Android Framework team) to give my opinion.
ContentProvider
Finally, the ContentProvider is a fairly specialized facility for publishing data from an app to other places. People generally think of them as an abstraction on a database, because there is a lot of API and support built in to them for that common case... but from the system design perspective, that isn't their point.
What these are to the system is an entry-point into an app for publishing named data items, identified by a URI scheme. Thus an app can decide how it wants to map the data it contains to a URI namespace, handing out those URIs to other entities which can in turn use them to access the data. There are a few particular things this allows the system to do in managing an app:
• Handing out a URI doesn't require the app remain running, so these can go all over the place with the owning app being dead. Only at the point where someone tells the system, "hey give me the data for this URI" does it need to make sure the app owning that data is running, so it can ask the app to retrieve and return the data.
• These URIs also provide an important fine-grained security model. For example, an application can place the URI for an image it has on the clipboard, but leave its content provider locked up so nobody can freely access it. When another app pulls that URI off the clipboard, the system can give it a temporary "URI permission grant" so that it is allowed to access the data only behind that URI, but nothing else in the app.
What we don't care about:
It doesn't really matter how you implement the data management behind a content provider; if you don't need structured data in a SQLite database, don't use SQLite. For example, the FileProvider helper class is an easy way to make raw files in your app available through a content provider.
Also, if you are not publishing data from your app for others to use, there is no need to use a content provider at all. It is true, because of the various helpers built around content providers, this can be an easy way to put data in a SQLite database and use it to populate UI elements like a ListView. But if any of this stuff makes what you are trying to do more difficult, then feel free to not use it and instead use a more appropriate data model for your app.
Full text here:
https://plus.google.com/+DianneHackborn/posts/FXCCYxepsDU
Kudos for the question, it's a nice observation :). IMHO, this is not a yes or no question because it is quite general, as most design patterns related topics are. The answer is depending on what context are you taking in account:
If you have an app that relies entirely on the platform, meaning that take into account only the context of the Android ecosystem, then yes, the ContentProvider IS an implementation of the Repository pattern. The argument here it is that the content provider was designed to solve some of the same challenges that the repository patterns aim to solve:
It provides abstraction over data layer, so the code is not necessarily dependent on the storage environment
No direct data access from everywhere. You can put all your SQL queries (or whatever) in a single place. When I first implemented a ContentProvider as a noob, it was like a revelation to me how clean my code can look like and how comfortable I can be doing changes
Centralizes the data and shares it between multiple clients (other apps, a search widget as you already know) and provides mechanism for data security
You can definitely define data related behavior (one way is by using ContentObserver)
It's a pretty good way to force you from the early stages to organize your code with unit testing/ automated testing in mind
If you put all of above side by side with the principles of the repository pattern, there are some serious similarities. Not all of them are satisfied, but the core ideas are the same.
Now, considering an app working on a larger scale in multiple environments (i.e web, mobile, PC) the requirements change completely. It is a bad idea as everyone suggested to rely on the ContentProvider as a design pattern.
It's not necessarily a bad idea in itself, but a design pattern must be implemented so others can understand your code as fast as possible. You see, even here everyone suggested a common use of ContentProvider: as a datasource, or anyhow something platform dependent. So if you force an implementation on top of a component with known purpose, things can become rather unclear. It's much nicer to organize your code in a classical pattern.
tl;dr; If your app is isolated on your Android device you can definitely merge the two concepts. If your app is used on a larger scale, on multiple platforms it's cleaner, to organize your code in a classical manner.
That is an interesting question. I think my first answer will be no, Content Provider is not an implementation of the Repository Pattern.
As you mentioned, the Repository Pattern is meant to separate the business logic (domain) from the data layer. This approach allows you to create unit tests for your business logic (so domain should not depend on Android at all). By using a Content Provider you will need to have some sort of Android objects in your domain.
You could imagine a way to hide the Content Provider logic behind an Interface, but you will loose many of the nice stuff a Content Provider allows you to do.
If you are interested in Android Architecture I would recommend you to have a look at this Github project Android Clean Architecture. You will find a nice way to separate your presentation, domain and data layer, and the communication between the domain and data is done by using a Repository Pattern.
Hope this will help!
IMHO, it's better to consider a Contentprovider as a datasource, although the data can be stored in several ways (SQLite database, files, ...), to keep some independence between the architecture and the Android framework.
A Google repository provide some samples of architecture. One of them contains an example of architecture with a content provider and a repository :
googlesamples/android-architecture/todo-mvp-contentproviders
Selected excerpts :
You could then use content providers to support additional features that are not covered by this sample, providing the following possible benefits:
Allow you to securely share data stored in your app with other apps.
Add support for custom searches in your app.
Develop widgets which access data in your app.
The problem with using ContentProviders as Repository is that you add a dependency in your model to the Android Framework. Using the repository patterns allows you to easily mock, test and replace implementations.
The correct approach would be to hide the ContentProvider under an interface, and have the model accessing the data through this interface. This way, your code is decoupled from the platform.
Basically, the ContentProvider is the I/O source you want to abstract.
Content Provider is a Android component, the smell will not be good if you mix the repository concept with this component, it creates a blocking dependency on your application.

Android where to store cached data?

My app will pull some json data when it is started and realistically, once the data has been pulled, I really won't need to pull it again for the duration of the user experience. The backend data may update a few times a day at most, so I think I would like to just grab the data upon app start and then use that same data for the duration and give the user an option to manually refresh the data. So, my question is, where/how should I store that data? I've got all of my data structures set up (classes and sub-classes). And there may be 200 or so instances of some of the classes. If I store everything as member variables in my activity_main class, it won't be available to other activities once the other activities are started. Storing them all in databases could be an option, but it sort of feels like overkill. I really don't need the data to persist between sessions. Is there a way to easily store it in memory and still have it easily accessible to all activities?
You should think about OS killing your app process on low-memory, so backing your data on disk is a good thing to do. Doing so you have an ability to show user data from disk cache while refreshing it in background from server.
Choosing the tool for data storage depends on the way you need to work with data.
Of course, there is an option to use Realm, but you should consider the fact that it is not the relational database. So if you have complex domain model with joins and other relational stuff for your business logic, I'd go with something other. It is thread-safe, also has migrations (but, as for me, migrarations are always pain, you just can not do anythig about it). Realm is supposed to be RxJava-friendly now (support added in v0.87) There are some disadvantages(part of them may already be fixed), but you should consider it before using.
As for more relational approach, there is SQLBrite library:
A lightweight wrapper around SQLiteOpenHelper which introduces reactive stream semantics to SQL operations.
It is not an ORM (but you can add some kind of it on top of SQLBrite if you wish: see this for more info). In fact, being alone this library is doing one thing (and doing it good) - it provides a mechanism for coordinating and composing the notification of updates to tables(Realm also has such ability) such that you can update queries(in SQL fashion) as soon as data changes. And it respects RxJava!
As an alternative to SQLBrite you can look at StorIO.
There are also lots of different ORM solutions, like GreenDAO, ORMLite etc.
But I'm pretty sure, one of the first two libraries (Realm or SQLBrite) will likely help you. So analyze your app, these libs and decide what fits better.
P.S. Great article on how RxJava would help you to work with data from different data sources (in-memory cache + disk cache + network) easily. Might be helpful!
I would still recommend a SQLite Databse, you can easily declare it as a 'in-memory' database, if that is what you want.
However.... I would be rather upset as a user of your application if it downloaded redundant data over and over. I would just recommend making a content provider and being done with it. This gives you access to a SyncAdapter, and defines clear boundaries between where code should go.
The 'trick' with making a good ContentProvider is to make good POJOs, that have methods to convert from POJO -> ContentValues and Cursor -> POJO(s).
Easiest thing is to do is store the json file in Apps data storage and parse the json every time you need.
But this is not recommended as it is costly to parse data every time.
Best option is to implement Realm (Replacement for Sqlite) which is very easy to implement and its amazingly fast.

How to properly add a ContentProvider into an existing app architecture?

I'm in the process of implementing my first ContentProvider. Since I'm quite inexperienced I wanted to check if my general design is sound.
So these are my requirements:
The web-service providing the original data might update the data it holds once per day. I can check for such a version change.
From the app's point of view, the data is read-only (think of weather or stocks data).
I already have a class that can take queries from the application domain, transform them into matching HTTP requests and asynchronously return domain objects. As you might guess, this is what the app currently uses to obtain data directly from an activity.
Now I want to do better and employ a ContentProvider to persist data locally.
Once per day the app would start a Service, that checks the data version on the server and when needed, update the data contained in the ContentProvider.
The following is the design that I've come up with:
Arrows indicate data-flow, not code-dependency.
I've noticed, I forgot to add a layer on top of the ContentProvider to convert Cursors to domain objects, but ignoring these details, do you think, this is a sound way of adding a ContentProvider to an app's architecture?
Any advice is greatly appreciated!

Categories

Resources