There is a REST API where search keyword entered by the user is used to query and get results. Sometimes, too many results are returned. I don't want to put a maximum result limit on the server side so I want to handle it on the application. In the application, I try to follow Clean Architecture. I have a fragment, a presenter, a usecase and an API client. User enters a keyword, presses search button, the keyword passed to related usecase function through presenter. Usecase gets results from API client and pass results to presenter through listener. Presenter notifies fragment so that results are displayed.
I want to show max of ten pages of results. Where should I put this control? Usecase or presenter?
If you will strictly make it ten pages ALWAYS, put it on your usecase because here, application business rules resides. So you don't need to pass it if your just always going to pass ten.
But, I suggest to make it as a parameter on the presenter, to make it flexible because maybe you will have a scenario in which you want to adjust the max pages on a specific activity/fragment.
Is pagination part of your domain? If it’s not, you might want to have a separate query interface/flow. Use the domain repository for write based operations. Load the entity, update, save. For queries have a different interface that enables query and filter operations. The user case still exists. The input still has the parameter, but your domain repository api is clean. You can even have the same database class implement your query api.
Related
Two cases :
1. Session data - For example the logged in User details, or some other session data.
2. Global/stateless data - A repository with retrofit client.
for case 1 :
The easiest way is to use some sort of a Singleton, "DataManager/LoginManger" , but singletons are bad(testing, unpredictable states over time...)
Another way would be to use the Application class, which is also bad.
So where do we store that data?
for case 2:
A simple repository, which holds reference to Retrofit client for example or other clients.
Using this as a singleton makes more sense, as this class would be immutable/stateless. We would only ever want to create a retrofit client once.
But.. Testing?
3. Also, what if we want to fetch location ?
We could have a LiveData responsible for that in the ViewModel. But ViewModel is scoped to a certain View/Activity. So that would mean that if we changed views (for example entered the settings from the drawer, while the homepage's viewmodel was fetching location) , we would lose the location data once it is retrieved, and then when the user comes back to the homepage, instead of just showing them the location, we would have to request the location all over again.
I haven't found any way that deals will all these cases. It seems there's no clear answer.
I've written for the beginning basic, very simple app in Android Studio which just fetches data from various REST methods and presents them in a table.
However, I would like to extend the functionality and offer user possibility of filtering data, for example, to get data from a different time. Let's assume, the user clicks and chooses data from Monday to Tuesday, fast SQL and data are refreshed, then user chooses data only from the previous week, fast SQL and data are refreshed.
I would like to ask first - is it better to load sometimes very huge amount of data and then somehow just filtering them or to execute every time REST method and just refresh grid?
For the time being, the user chooses an option from the menu, I call the REST method and present data in the second activity. Now I would like to execute almost the same SQL, but with different WHERE clause, depending on the user what he wants to see.
Should I call the whole mechanism to execute the REST method or is there some library which allows me to modify SQL and "in the fly" execute REST method with different parameters?
It depends on how large the original data is.
If the data is really big then the best option is to add filtering in the request and receive the filtered data from your backend.
In case your data is pretty much static and would probably stay the same you can fetch it all and save it to your local DB and then query it locally
but if the data is not that big you should just request it all
Anyway you should read about Pagination
The Android team also created a paging library as part of the architecture components
I've seen good examples of MVP architecture (here and here). Both present only simple interactors, but I wonder how to deal with more complex use case, consisting of steps, which are repeated in other use cases.
For example, my API requires token to authenticate any call. I've created an interactor to get that token (GetToken). I want to get user's last login date (GetLastLoginDate) and then fetch a list of changes that occured between that date and now (GetVersionChanges).
Where those interactor should be chained? I want to keep them separate, because some of them are reused in other parts of the code. I've came up with two solutions.
Presenter should chain all interactors. This solution works as long the use case is not complex and doesn't have many preconditions. It seems to me it's not the right place, because it burdens presenter with another responsibility.
Interactor can use many repositories (no clean architecture rules are broken then). Why not use TokenRepository in other interactors? Because getting token is much more complex than just reaching to repository. Repeating the steps in other interactor does not reuse already existing code.
Both solutions have their flaws and are against basic principles (DRY, single responsibility principle).
If I were you I would just put the logic of getting a token in a separate interactor (maybe named getTokenInteractor) and call that interactor from your others interactor who may need it.
That way, it would be in an interactor that you chose either to use a token (and call or not your getTokenInteractor) and also in an interactor that you retrieve it and deal with errors.
I would do the same for your "getVersionChanges" use case and let an interactor chain the calls.
Let's imagine you have a presenter who needs to display the version changes. He will call a first interactor (GetVersionChangesInteractor) who will first check if he has a token (by calling getTokenInteractor), then call GetLastLoginDateRepository for retrieving the date, and call GetVersionChangesRepository with that date and finally give the result to your presenter.
That way, your business logic can stay 100% in your interactor and your presenter can focus on how he will display that on screen.
By the way, if your API needs a token for every call you should move it in an Interceptor so you do not have to deal with it at every call.
It's possible that the MVPC pattern is what you're after. This is something I wrote ages ago on it (though the code example is pretty poor so please excuse that!)
I write android app using MVP pattern. My question is regarding database layer. I want to make it maximally independent, so it will be possible to replace it with something else without code changing in Presenter in the future. I decided to use pure SQLite without ORM, since the user table is updated in different places with differenet fields (in some place I update user's name, in other place in code - token etc.). ORM (I used realm) doesn't allow to do it, you have to write separate method for updating name, separate - for token etc.
Another problem is with ContentValues: when you update user you have to specify the fields you want to change via ContentValues in Presenter, and then Presenter calls repository.updateUserLocal(contentValues), so my Presenter dependents on data layer (if I decided to add ORM to the project, I will need to go to every Presenter and remove ContentValues). So the architecture is bad. Can you please advice how to organize the architecture of the app in the best way?
By following basic tutorials I've created a login fragment that has a username textview, password textview, and button. It POSTS the login info to an API which validates the login. EVERYTHING i do is in the login fragment (controller).
I have 3 questions:
Following Model, View, Controller - I do not have a model. The View is the layout, and the controller is the fragment. Is this right?
I feel as if the login code should be broken down into more classes... such as separating out the post request from the rest of the code. If I were to move the asynchronous request to another class file, I would also have to pass the views needing to be hidden while attempting to validate the user. Is there a better way to accomplish this, or is it OK to leave the http request code in the login fragment?
Is there something I'm missing that might need to be in another class?
In my opinion, in Android you don't have typical MVC pattern like in some web applications. You can treat XML layouts as a views. It's provided by design of the Android API. Activity is the actual controller. If you have some complicated logic you can create separate classes, which will be responsible for that logic. Activity shouldn't be of course "God class" holding all the operations. You can store your models in a separate package as a POJO objects and access them via other classes responsible for logic of the application. You shouldn't keep HTTP requests in Activity or Fragment. You should move them to another class to separate logic responsible for displaying data from logic responsible for retrieving data. Fragments should be used only when it's necessary, but not all the time. You can use them, when you want to display dialog, use tabs in your layout or create adaptive layout for tablets and mobile phones. I think, if you don't really need fragments, you don't have to use them. You can read how Square is advocating against Android Fragments. You can deal with asynchronous requests with RxJava. You can return Observables and subscribe them every time you want to create asynchronous request. It gives you good granulation, separation and control over your code.
Of course, it's only my opinion based on some experiences and I may be wrong. I'm eager to hear opinion of other developers and their experiences.