使用Hilt搭建隔离层架构

news2024/12/23 17:49:04

在我们的日常编码的过程中,常常会遇到这种需求。例如:这个版本我们使用okhttp作为网络通信库,如果下个版本我们想要用volley作为网络通信库,那该怎么办呢?我们总不能对使用okhttp的地方一个个改成volley吧!这样得要改到猴年马月啊!因此,通常情况下,我们接入第三方库的时候总会有一个隔离层,方便我们日后切换不同的第三方库。接下来,笔者将手把手演示如何搭建一个隔离层。

技术方案

一般,我们搭建隔离层的技术方案有两种:

  • 使用代理方式实现
  • 使用Hilt反射方式实现

我们首先使用代理的方式来实现隔离层,以切换log为例。

  1. 首先,我们需要针对不同的库,定义一个统一的接口
package com.example.test;

public interface ILogCallback {
    void d(String tag,String msg);
    void e(String tag,String msg);
}

  1. 实现该接口,例如我们定义了BLog和XLog这两个类,在接口的方法中做不同的实现以示功能的区分。
package com.example.test;

import android.util.Log;

public class BLog implements ILogCallback{
    @Override
    public void d(String tag, String msg) {
        Log.d("BLog"+tag,msg);
    }

    @Override
    public void e(String tag, String msg) {
        Log.e("BLog"+tag,msg);
    }
}

package com.example.test;

import android.util.Log;

public class XLog implements ILogCallback{
    @Override
    public void d(String tag, String msg) {
        Log.d("XLog"+tag,msg);
    }

    @Override
    public void e(String tag, String msg) {
        Log.e("XLog"+tag,msg);
    }
}

  1. 定义一个统一的类,来决定我们要使用的是BLog还是XLog类。
package com.example.test;

public class LogHelper {
    private ILogCallback callback;
    private static LogHelper helper;

    private LogHelper() {
    }

    public static LogHelper getInstance() {
        if (helper == null) {
            helper = new LogHelper();
        }
        return helper;
    }

    public void init(ILogCallback callback) {
        this.callback = callback;
    }

    public void e(String tag, String msg) {
        callback.e(tag, msg);
    }

    public void d(String tag, String msg) {
        callback.d(tag, msg);
    }

}

5.在application中初始化

package com.example.test;

import android.app.Application;

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        LogHelper.getInstance().init(new XLog());
        //LogHelper.getInstance().init(new BLog());
    }
}

package com.example.test

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import javax.inject.Inject

class MainActivity : AppCompatActivity() {

    @Inject
    lateinit var student:Student

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        LogHelper.getInstance().d("MainActivity","Hello World")
    }
}

这样,我们就只需要更改application中的一句代码就能够灵活地切换BLog和XLog了。

接下来,我们来间接如何使用Hilt来搭建隔离层架构。首先,我们得要搞清楚Hilt究竟是一个什么东西,它与dagger2有什么区别。简单来说,Hilt与Dagger2的关系就是okhttp与retrofit的关系,hilt仅仅只是对dagger2的二次封装而已,为了更加好用,核心的功能还是由dagger2来实现的。
hilt相较于dagger2的最明显特征就是:

  1. 简单
  2. 提供了Android专属的API

学习Hilt,我们需要知道下面几个概念。

  • Hilt组件
    对于您可以从中执行字段注入的每个 Android 类,都有一个关联的 Hilt 组件,您可以在 @InstallIn 注解中引用该组件。每个 Hilt 组件负责将其绑定注入相应的 Android 类。
    在这里插入图片描述
  • Hilt组件的生命周期
    在这里插入图片描述
  • 组件作用域
    默认情况下,Hilt 中的所有绑定都未限定作用域。这意味着,每当应用请求绑定时,Hilt 都会创建所需类型的一个新实例。

不过,Hilt 也允许将绑定的作用域限定为特定组件。Hilt 只为绑定作用域限定到的组件的每个实例创建一次限定作用域的绑定,对该绑定的所有请求共享同一实例。
在这里插入图片描述
了解完上面这几个概念之后,我们用一个案例来说明如何使用Hilt。

  1. Hilt的引入
    首先,将 hilt-android-gradle-plugin 插件添加到项目的根级 build.gradle 文件中:
plugins {
  ...
  id 'com.google.dagger.hilt.android' version '2.44' apply false
}

然后,应用Gradle插件并在app/build。gradle文件中添加下面依赖项:

...
plugins {
  id 'kotlin-kapt'
  id 'com.google.dagger.hilt.android'
}

android {
  ...
}

dependencies {
  implementation "com.google.dagger:hilt-android:2.44"
  kapt "com.google.dagger:hilt-compiler:2.44"
  annotationProcessor "com.google.dagger:hilt-compiler:2.44"

}
  1. 新建一个module
package com.example.test;

public class Student {
}

package com.example.test;

import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;
import dagger.hilt.InstallIn;
import dagger.hilt.android.components.ActivityComponent;
import dagger.hilt.components.SingletonComponent;


// ActivityComponent.class    能注入到Activity,不能注入到Application
// SingletonComponent.class 能注入到Activity, 能注入到Application

@Module
@InstallIn(SingletonComponent.class) // 注入到Activity里面去(按规则来,该是哪个注入,就写哪个,不要乱搞)
public class StudentMoudle {


   // @Singleton // 上面的InstallIn 必须是 (SingletonComponent.class) 才能全局单例
    @ActivityScoped // 上面的InstallIn 必须是 (ActivityComponent.class) 才能局部单例
    @Provides
    public Student getStudnet(){
        return new Student();
    }
}

package com.example.test

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    @Inject
    lateinit var stu:Student
    @Inject
    lateinit var stu2:Student

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        Toast.makeText(this,"${stu2.hashCode()}",Toast.LENGTH_LONG).show()
        Toast.makeText(this,"${stu.hashCode()}",Toast.LENGTH_LONG).show()
//        LogHelper.getInstance().d("MainActivity","Hello World")
    }
}

与dagger2相比,Hilt不需要在创建component注解了。

接下来,我们就利用Hilt来搭建隔离层框架
首先,我们需要为BLog和XLog类做一些修改

package com.example.test;

import android.util.Log;

import javax.inject.Inject;

public class XLog implements ILogCallback{

    @Inject
    public XLog(){

    }
    @Override
    public void d(String tag, String msg) {
        Log.d("XLog"+tag,msg);
    }

    @Override
    public void e(String tag, String msg) {
        Log.e("XLog"+tag,msg);
    }
}

package com.example.test;

import android.util.Log;

import javax.inject.Inject;

public class BLog implements ILogCallback{

    @Inject
    public BLog(){}

    @Override
    public void d(String tag, String msg) {
        Log.d("BLog"+tag,msg);
    }

    @Override
    public void e(String tag, String msg) {
        Log.e("BLog"+tag,msg);
    }
}

接着,创建两个注解,我们通过切换不同的注解来更换不同的log

package com.example.test.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import javax.inject.Qualifier;

@Qualifier // 此注解就是为了让 hilt 区分这个注解(做自己的逻辑处理)  自己定义标识,限定符号
@Retention(RetentionPolicy.RUNTIME)
public @interface BLog {
}

package com.example.test.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import javax.inject.Qualifier;

@Qualifier // 此注解就是为了让 hilt 区分这个注解(做自己的逻辑处理)  自己定义标识,限定符号
@Retention(RetentionPolicy.RUNTIME)
public @interface XLog {
}

最后,新建一个Module,在里面进行绑定

package com.example.test;


import javax.inject.Singleton;

import dagger.Binds;
import dagger.Module;
import dagger.hilt.InstallIn;
import dagger.hilt.components.SingletonComponent;

@Module
@InstallIn(SingletonComponent.class)
public abstract class LogInterfaceModule {

    @com.example.test.annotation.XLog
    @Binds
    @Singleton
    public abstract ILogCallback bind(XLog log);

    @com.example.test.annotation.BLog
    @Binds
    @Singleton
    public abstract ILogCallback bindB(com.example.test.BLog log);
}

package com.example.test;

import android.app.Application;

import com.example.test.annotation.BLog;
import com.example.test.annotation.XLog;

import javax.inject.Inject;

import dagger.hilt.android.HiltAndroidApp;

@HiltAndroidApp
public class MyApplication extends Application {

//只需要切换不同的注解便可以切换log
    @Inject
//    @XLog
    @BLog
    public ILogCallback logCallback;

    @Override
    public void onCreate() {
        super.onCreate();

//        LogHelper.getInstance().init(new XLog());
//        LogHelper.getInstance().init(new BLog());
    }

    public ILogCallback getLog(){
        return logCallback;
    }
}

package com.example.test

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    @Inject
    lateinit var stu:Student
    @Inject
    lateinit var stu2:Student

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        (application as MyApplication).log.d("xxxx","MainActivity")
    }

}

参考资料

https://developer.android.com/training/dependency-injection/hilt-android#component-hierarchy

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/80802.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

上班都在刷的Java八股文,老板都想要一份?

今天心血来潮刷刷牛客看到这,小伙在上班刷八股文被老板逮到!真行啊,结果还让他给老板也发一份,感觉过不了多久就跟老板一起提桶跑路了 说到这,我最近也整理了GitHub上高标星的面试八股文,这种金九银十的节骨…

Java并发编程之Condition await/signal原理剖析

Java并发编程之Condition await/signal原理剖析 文章目录Java并发编程之Condition await/signal原理剖析Condition与Lock的关系Condition实现原理await()实现分析signal()实现分析Condition接口与Object监听器的区别Condition与Lock的关系 Condition本身也是⼀个接口&#xff…

OpenStack的简单部署

OpenStack的简单部署 文章目录OpenStack的简单部署一、OpenStack概述二、环境准备三、搭建流程1. 更新 & 升级2. 安装好用的vim VimForCpp3. 安装必要依赖4. 关闭防火墙、核心防护、NetworkManager5. 配置静态IP地址6.配置yum源7. 安装时间同步服务8. 使用packstack 一键部…

C罗老矣,我的程序人生还有多远

☆ 随着12月11号摩洛哥1-0葡萄牙比赛的结束,不仅说明葡萄牙对要结束本届卡塔尔世界杯了,就连C罗此生的世界杯之旅也将画上句号了。 ☆ 37岁的球星本该是人生最璀璨的阶段,但在足球生涯中,这已经是大龄了。不禁让我想到&#xff0c…

机器视觉(五):机器视觉与世界杯

11月22日晚上,球迷再次为阿根廷而惋惜。在当天晚上进行的世界杯小组赛C组首轮比赛中,阿根廷队1:2不敌沙特阿拉伯队,爆出了本届世界杯开赛至今最大的冷门。 天台好冷不仅如此,阿根廷队全场比赛总计被吹罚了10次越位,刷新…

SpringMVC(一) 构建项目

SpringMVC(一) 构建项目 1.创建项目 创建一个空的Maven项目 删除src目录,将新建的项目作为一个工作空间使用,然后在里面创建Module。 2.创建Module 选中刚才创建的项目,右键创建Module 选择Java语言的Maven 项目 3.添加SpringMVC依赖 在…

1-48-mysql-基础篇-DML-select

1-mysql-基础篇: 推荐网站 mysql:https://dev.mysql.com/doc/refman/8.0/en/ 算法:https://www.cs.usfca.edu/~galles/visualization/about.html 数据库 1、数据库概述相关 1、 数据库的相关概念 DB:数据库(Data…

git 多用户配置(公司/个人)

背景 张三是一个程序员,他的英文名叫 outlaw,emial: outlaw163.com。 张三入职了一家公司,公司给张三的企业邮箱是 zhangsancompany.com 这一次,他 0 元购了一台新笔记本,需要配置一下 git git 账号配置 配置全局用…

微信公众号开发,获取openid,授权登录 WeChat-official-account-openid

微信公众号开发 功能:自动登录,获取个人信息,上传图片 超多麻烦的情况,怎样获取openid呢? 以下我给大家提供源码,文本,视频资料 保证让你看了就明白哈 look效果 1.拉起用户授权 2.后台获取到…

微服务雪崩问题解决 Sentinel

雪崩问题以及解决方案 限流设置 达到阈值的效果 隔离和降级 熔断 授权规则 设置规则持久化 雪崩问题以及解决方案雪崩微服务调用链路中的某个服务出现故障,引起链路上其他服务都不可用,这就是雪崩解决方案超时处理,设定超时时间,请…

【软件工程期末复习内容】

前言 时不可以苟遇,道不可以虚行。 一、软件工程的概念 软件是计算机系统运行的 指令、数据 和 相关文档 的集合,即软件等于程序、数据、加上文档。程序:是事先按照预定功能性能等要求设计和编写的指令序列;数据:是使…

Python编程 while循环

作者简介:一名在校计算机学生、每天分享Python的学习经验、和学习笔记。 座右铭:低头赶路,敬事如仪 个人主页:网络豆的主页​​​​​​ 目录 前言 一.循环控制 1.循环控制介绍 2.while循环表达式 3.while循环表达式 4.b…

Python实现ALO蚁狮优化算法优化支持向量机回归模型(SVR算法)项目实战

说明:这是一个机器学习实战项目(附带数据代码文档视频讲解),如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 蚁狮优化(Ant Lion Optimizer,ALO)算法是Mirjalili于2015提出的一种新型元启发式群智能算法…

47-linux-vim-安装以及权限等-缺少

47-linux-vim-安装以及权限等: vi编辑器简介 vim是一个全屏幕纯文本编辑器,是vi编辑器的增强版,我们主要讲解的是vim编辑器。可以利用别名让输入vi命令的时候,实际上执行vim编辑器,例如: [rootlocalhost ~]# alias v…

HTTP协议介绍

了解HTTP HTTP是什么呢?它是超文本传输协议,HTTP是缩写,它的全英文名是HyperText Transfer Protocol。 那么什么是超文本呢? 超文本指的是HTML,css,JavaScript和图片等,HTTP的出现是为了接收和…

一位全栈工程师转岗项目经理的初体验与总结

从上周开始,公司这边把我从全栈工程师的岗位调到了项目经理的岗位,开始尝试管理岗位,感觉换了一个岗位像是换了一份工作一样,又在次充满了干劲。开始新的项目,招纳新的项目成员,虽然都是在做软件开发的事情…

【手把手】分布式定时任务调度解析之Quartz

1、任务调度背景 在业务系统中有很多这样的场景: 1、账单日或者还款日上午 10 点,给每个信用卡客户发送账单通知,还款通知。如何判断客户的账单日、还款日,完成通知的发送? 2、银行业务系统,夜间要完成跑批…

CCF CSP认证——201312

文章目录201312-1 出现次数最多的数201312-2 ISBN号码201312-3 最大的矩形201312-4 有趣的数201312-5 I’m stuck!201312-1 出现次数最多的数 题目链接 数据量较小,且数据范围也比较小。可以直接暴力,通过设置数组记录下标数据出现的次数,最…

C/C++关键字

C/C关键字【1】extern "C"【2】asm【3】关键字auto【4】break语句【5】catch 语句【6】关键字class【7】关键字const【8】#if【9】#pragma once【10】#pragma pack(1)【11】#pragma pack(4)【12】explicit【】 continue语句【13】关键字enum【14】friend【15】goto语…

【springboot进阶】基于starter项目构建(二)构建starter项目-web

目录 一、创建 web-spring-boot-starter 项目 二、添加 pom 文件依赖 三、构建配置 1. rest模板配置 RestTemplateConfig 2. 统一异常处理 BackendGlobalExceptionHandler 3. 统一返回数据结构 4. jwt鉴权处理 5. 请求日志切面处理 WebLogAspect 6. 邮件配置 BackendM…