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.

  1. Constructor injection. You pass the dependencies of a class into its constructor (as was the case with CloudDisk in the previous article).

  2. 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.

  1. Compared to Dragger, it’s actually easier to use
  2. IDE support link jump, good development experience
  3. Complete test suite for easy automated test writing
  4. 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.

  1. Simple to use, no complex annotations
  2. 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