A common approach to architecture in Android development was the layered architecture, where apps would be split into three layers the user interface, domain, and data layers.
Next, we need to provide a Retrofit object: The Retrofit object will need a base URL that will act as the host for our backend service, OkHttpClient, and the JSON converter factory, which were provided earlier. This is often the reason why in many applications, you will see these methods used to load data and on the opposite site unsubscribing from any operations that might trigger a change in the user interface.
We can observe how fragments have their own internal lifecycle for managing the views that they display between the onCreateView method and onDestroyView methods. We will focus more on the particularities of each in Chapter 8, Implementing an MVVM Architecture. This solves an issue that developers would have in the past where a view would be deleted from your XML file, but your application would still run because of another view with the same name in another file.
In Android, you can view them as individual modules.
We can also see that the dependencies go from the classes at the bottom toward the classes at the top, similar to how the dependencies go from the outer layers toward the inner layers here. Fragments are meant to control portions of an activity's user interface.
We will analyze some of the newer libraries, frameworks, and technologies that we can incorporate into an Android application. This comes at a couple of costs: the life cycle of the fragment was even more complex than the life cycle of the activity, where you would have fragments that had their views destroyed but the fragments themselves weren't.
This is represented by a set of libraries that help developers make their apps scalable, testable, and maintainable. This allows developers to build UIs directly in Kotlin without the use of XML files through composable functions.
We can see that it travels from ConcreteDataService into MainActivity. The book starts by explaining clean architecture principles and Android architecture components and then explores the tools, frameworks, and libraries involved. Finally, the Hilt module will be updated as follows: Here, we can see that ConcreteDataUseCase just invokes ConcreteDataRepository, which just invokes ConcreteDataSource. Another cost was the communication between two fragments.
Let's assume you wanted an operation to be executed on a separate thread, and then you wanted to transform your data all you need to do here is invoke the data you want, apply mapping functions, and then subscribe to get the final result. Now, let's say we were in a place where we could ship out our LoadConcreteDataTask. What would you need to do then? In the next section, we will see how these principles lead to the evolution of the Android platform and what an application may look like now. Unlock this book with a 7 day free trial.
In this case, we have a bit of fake duplication.
This will then be set in LiveData. Developers no longer need to deal with the SQLite interaction and the many dependencies that come with it; instead, they can focus on creating their own models and providing the abstractions for what needs to be queried, deleted, updated, and deleted; Room will take care of the actual implementations.
A component can be defined as the smallest piece of deliverable code. The problem here was that the domain layer depended on the data layer, so when the data layer changed, the domain layer needed to change too. Because of multi-threading. The name is an acronym for a set of design principles that were collected by Robert C Martin. The following are the hardware requirements for this chapter: In this section, we will look at how Android applications used to be built in the past and what difficulties developers had with the approach taken. With that, we have explored the evolution of the Android platform and tools, what an application may look like using the latest tools and libraries, and how this evolution solved many problems developers had in the past. Youll learn how to structure your application in the data and domain layers, the technologies that go in each layer, and the role that each layer plays in keeping your application clean. Do they want to persist data locally? These are some of the most known design principles. This came with certain limitations for applications.
Several libraries have emerged to tackle this issue: Dagger, Koin, and Hilt.
MainActivity will be updated to use the textData object from MainViewModel: With that, MainActivity has been updated to use LiveData, which emits a String instead of a ConcreteData object. This is similar if it was the opposite way around and the activity or ViewModel would've done the same. This is a problem because the classes are then coupled together and making a change to one implies making a change to the other. The word 'Packt' and the Packt logo are registered trademarks belonging to
Now, we need to create a concrete JsonMapper.java that will be responsible for converting a JSONObject into ConcreteData: The convert method creates a new ConcreteData object, extracts the data from the JSONObject object, and populates the field1 and field2 values. In Android, even if we use the latest libraries and frameworks, we should still make sure that our domain is still protected by changes in those frameworks. If those developers follow the guidelines you've set up, they can work with a minimal level of overlap. The product owner has asked you to deliver a demo with some mock data for tomorrow. We looked at all of these changes through a small example, where we saw them transition from what they may have looked like in 2010 to what they may look like now. Things are going great and people love your product, so your company decides to open your APIs for other businesses to integrate into their systems.
It removes the boilerplate code that was required for Dagger and provides support for Android dependencies as well. Next, we will need to provide the JSON serialization: We are using the Moshi library for JSON serialization, so we will have to provide a Factory that will be used by Retrofit for JSON conversion. DataStore provides two options for storing data: safely typed data and no type safety data. Your company also wants to provide an Android library so that it's easier for businesses to access your APIs. This means that we would need something to help with this. Packt Publishing Limited.
As an example, let's imagine we have some data we will need to fetch from our backend that will then need to be stored locally in case we want the user to view it offline. You are faced with a choice here: you can build the product that's been requested by the product owner as fast as possible and then constantly refactor your code for each new integration and the change in requirements, or you can take a little bit more time and factor in the future changes that will come into your approach.
In the dependencies section, we specify which external libraries we want to add to the project.
After that, we'll introduce clean architecture so that we know what our system needs to be improved and what questions we must ask, as developers, so that we can create a robust, scalable, maintainable, and testable application. To borrow from the construction industry, we can define architecture as a plan for the structure of a building; a design would be a plan to create each part of the building.
Some of the most popular libraries include Volley and Retrofit. These layers are as follows: Let's consider a scenario: you've recently been hired by a start-up company as their first Android engineer. Initially, Android development used the Eclipse IDE and Ant as its build system. If you needed to update the user interface being handled by Fragment1 because of a change in Fragment2, you would need to communicate through the activity.
In this chapter, we're going to cover the following main topics: By the end of this chapter, you will know about the evolution of Android development, its architecture, and its design concepts, as well as the concept of clean architecture and how it can be used to build flexible, maintainable, and testable applications.
What we want to do is have a system where we can easily plug things in and easily plug them out. Can we export that and publish it somewhere where other developers can get it? They were released on Android Honeycomb, which was an Android release that only targeted tablets. Its adoption and transition into Kotlin programming has added others. You may be wondering why this boilerplate is necessary.
This is something specific to processing the data that your app will use. This is because, at the end of the day, the fact that we chose Retrofit and Moshi shouldn't impact the rest of the application. To understand why this is a problem, let's look at an example of what some older application code would look like.
Another improvement fragments brought was the ability to change and replace fragments at runtime. The following is an example of what Compose looks like: In this example, we can see a screen that contains an input field, some text that displays Example Text, and a button with the text Button. This would update what the view would display without it interacting with the activity. Let's look at the following diagram and see how it compares to Figure 1.4: If we look at the top row, we will see the use case and the entity. Here are some useful Gradle/adb commands for executing this example: Refer to the issues section: https://github.com/android10/Android-CleanArchitecture/issues, Here you can download and install the java codestyle. When these principles are incorporated, they end up conflicting with each other.
Then, we'll look at some key design principles for software development and apply those principles to our legacy examples.
The principles that follow represent an expansion of SOLID.
Clean architecture represents an integration of multiple types of architecture that provide independence from frameworks, user interfaces, and databases, as well as being testable. Another benefit is in situations where we depend on abstractions. One of the most important is the concept of mutability. But to do that, we will need to define our entity: It looks like it's a duplicate of ConcreteData, but this is a case of fake duplication. Sign up to our emails for regular updates, bespoke offers, exclusive
The use of generics allows us to apply this logic to any POJO. Flows represent an extension of coroutines where we can have multiple emissions of data, such as RxJava, providing similar benefits. We've looked at some of the most important software design principles, such as SOLID, to get a better understanding of how to improve our code and how these principles helped the Android platform evolve. Data binding allows us to bind our views to data sources. Components are responsible for how the dependencies are managed, while modules are responsible for providing the appropriate dependencies. This allows us to write extra scripts and easily integrate plugins and tools, such as performance monitoring of an application, Google Play services, Firebase Crashlytics, and more. However, we risk creating a context leak (if, for any reason, the Activity object is destroyed, then the garbage collector will not be able to collect the Activity object while AsyncTask is running since Activity has a dependency on AsyncTask) by using an inner AsyncTask class. The following code shows what the build.gradle file for a module looks like: In the plugins section, we can define external plugins that will provide certain methods and scripts that our project can use. When code is written with the notion that it needs to be unit tested, then the way we write that code becomes more rigorous and more maintainable.
The fact that we had the option to make a less desirable solution or to be stuck in a situation where we had to pick between the frying pan or the fire represents a problem. Finally, we can use this in our Activity to execute the request and update our user interface (UI) with the result. Luckily, Android provides the AsyncTask class, which offers a set of methods for doing work on a separate thread and then processing the results on the main thread. The combination of the Android ViewModel and LiveData has helped developers implement the MVVM pattern, which is also life cycle aware. Next, we must create a ConcreteRequest.java that will extend BaseRequest and use ConcreteMapper: This class will inherit the execute method from BaseRequest and supply a new ConcreteMapper object so that we can convert the backend data into ConcreteData. We started by looking at an example of what the code in an older Android application looked like before looking at the design principles we should incorporate into our work. It will be responsible for retrieving the data on a separate thread by using Kotlin flows. The layout of the screen is defined as a function annotated with the @Compose annotation. None? In the preceding figure, we can see the difference between the lifecycle of activities and the lifecycle of fragments. Lambdas represent another great feature of Kotlin that allows boilerplate code to be reduced when you're dealing with callbacks. These files are written in a language called Groovy. This content is then set in an activity through the setContent method, where a theme is provided.