preface
We reconstructed the file package and extracted the corresponding UserState interface, but we found that the layer passing of UserState interface required us to manually maintain a lot of construction methods and corresponding injection. This is very inconvenient for code management and maintenance. And with more decoupled interfaces, more boilerplate code is generated, so we need a better way to manage it uniformly.
This article is divided into three parts. The first part is about common di methods, the second part is about the best di practices in the industry, and finally we will continue to refactor CloudDisk for DI.
Dependency Injection
Static injection (code that connects dependencies at compile time)
Static injection is the most common approach, relying on abstractions in classes, exposing seams, and implementing injection at the point of invocation. There are two common injection methods.
-
Constructor injection. You pass the dependencies of a class into its constructor (as was the case with CloudDisk in the previous article).
-
Field injection (or setter injection). Some Android framework classes, such as activities and fragments, are instantiated by the system and therefore cannot do constructor injection. When field injection is used, dependencies are instantiated after the class is created
Because dependencies are connected at compile time, type checking is performed during the edit phase.
Dynamic injection (connecting dependencies at run time)
The most common form of dynamic injection is done at run time through a mechanism called reflection.
Because the dependencies are connected at run time, there are no checks at compile time and performance issues due to reflection. But the benefit is flexibility, and if any modules are loaded dynamically, it’s easier to handle them this way.
contrast
Static injection | The dynamic injection |
---|---|
Type safety, compile-time checking | Runtime binding, no dependencies at compile time |
No performance loss | There is a performance penalty for reflection |
More suitable for package compilation | It is suitable for dynamic module loading scenarios |
Open source implementations | Fewer open source implementations |
Outstanding practice in the industry
As mentioned earlier, applying a manual approach to DEPENDENCY injection management can be very difficult and challenging. Fortunately, there are mature solutions in the industry. In this chapter we look at some of the best practices in the industry.
hilt
Hilt takes a static injection approach, building on the Dagger dependency injection library, providing a standard way to incorporate Dagger into Android applications.
Detailed introduction and use of you can view the official introduction
Developer.android.com/training/de…
Here we highlight some of the benefits of the library.
- Compared to Dragger, it’s actually easier to use
- IDE support link jump, good development experience
- Complete test suite for easy automated test writing
- Jetpack ecological components, ecological chain integrity, community activity
koin
Koin is a practical lightweight dependency injection framework for Kotlin, written in pure Kotlin, using only functional resolution, no proxy, no code generation, no reflection.
Detailed introduction and use of the same you can see the official introduction
The insert – koin. IO/docs/quicks…
Here we also share some of the advantages of the library.
- Simple to use, no complex annotations
- It is lightweight, takes faster compilation time and generates less code than hilt
Of course, since Koin itself is written in Kotlin, it is best to write projects in Kotlin as well. It doesn’t have the same fine-grained lifecycle management and IDE support as Hilt, and it doesn’t have the same ecological richness as Jetpack.
CloudDisk Example of dependency injection reconstruction
We previously shared some of the best dependency injection practices in the industry, but since CloudDisk was developed in the Java language and was expected to migrate to the JetPack ecosystem, we decided to use Hilt’s solution.
We will not demonstrate the specific transformation process of Hilt, but refer to the documents on the official website for operation. Here’s a look at the code snippets before and after the makeover.
Concrete code: Github links
Using manual injection:
public class FileFragment extends Fragment { FileController fileController; public FileFragment(UserState userState) { fileController = new FileController(userState); } public static FileFragment newInstance(UserState userState) { FileFragment fragment = new FileFragment(userState); Bundle args = new Bundle(); fragment.setArguments(args); return fragment; }}Copy the code
Using Hilt injection:
@AndroidEntryPoint
public class FileFragment extends Fragment {
@Inject
FileController fileController;
public static FileFragment newInstance() {
FileFragment fragment = new FileFragment();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
Copy the code
Hilt essentially generates code at compile time and injects it into our classes through annotations and the Gradle plug-in. Using the framework helped us reduce a lot of template code and unify configuration management.
Note here that the test code also needs to be configured accordingly.
@RunWith(AndroidJUnit4.class)
@LargeTest
@HiltAndroidTest
@Config(application = HiltTestApplication.class)
public class SmokeTesting {
@Rule
public HiltAndroidRule hiltRule = new HiltAndroidRule(this);
}
Copy the code
conclusion
In this chapter, we introduce the common dependency injection methods and the best practices in the industry, and we transform CloudDisk to use Hilt to manage injection. Through the IDE dependency analysis, we can find that the App depends on the Fragment of the fileBundle, and there is a compilation dependency on the UI.
In the next installment, Mobile Legacy Refactoring (9) – Routing, we’ll share common page routing methods and best practices in the industry, and continue to refine DiskCloud.
The resources
Dependency injection in Android
CloudDisk example code
CloudDisk
Series of links
Refactoring legacy Systems for mobile Applications (1) – Start
Refactoring legacy systems for mobile applications (2) – Architecture
Refactoring legacy systems for mobile applications (3) – Examples
Refactoring legacy Systems in Mobile Applications (4) – Analysis
Mobile application legacy System refactoring (5) – Refactoring methods
Refactoring legacy Systems for mobile applications (6) – Test
Mobile application legacy System refactoring (7) – Decoupled refactoring Demonstration (1)+ video demonstration
The outline
about
Welcome to the CAC Agile Coach public account. Wechat search: CAC Agile Coach.
- Author: Huang Junbin
- Blog: junbin. Tech
- GitHub: junbin1011
- Zhihu: @ JunBin