EventBus3.0 性能提升之添加索引

3DMax高效建模与人工智能:一场颠覆传统创作的效率革命 AI与3DMax的结合,不仅是工具效率的升级,更是一场创作范式的革命。从“手动雕刻”到“智能共生”,设计师的角色正从执行者转向决策者。正如网友所言:“AI不是替代人类,而是赋予凡人以神笔。”在这场变革中,唯有拥抱技术、深耕创意,方能在数字艺术的浪潮中立于潮头。参考文献与工具推荐技术原理:火星时代资讯《人工智能和三维建模》工具实测:哔哩哔哩《tyDiffusion 3dsMax应用》9、Tripo AI官网教育案例:原创论文《人工智能技术介入三维动画课程建设》 阅读详情

EventBus3.0 源码解析 一文中,在分析Subscriber的register()过程中,说到过一个方法方法findUsingReflectionInSingleClass,在该方法的作用是在RunTime期间通过反射获取Subscriber中的SubscriberMethod。

这样就会产生一个问题,在RunTime期间使用反射对程序运行的性能有较大影响。这里我们可以看看EventBus作者提供的一张图:

从上图中我们可以看出,RunTime时反射(EventBus3 No Index)的实现方式是性能最差的。为了避免这样的情况,EventBus3.0中增加了一个新特性:通过在编译期创建索引(SubscriberInfoIndex)以提高程序运行性能

所以,这里主要对EventBus中创建索引相关的功能进行分析。


配置使用索引

关于索引的配置,可以参考下EventBus官方文档:Subscriber Index。
主要就两个步骤:

  1. 使用annotationProcessor并设置arguments
    arguments就是指定的生成的索引的全限定类名
  2. 创建EventBus实例并传入索引的实例

注解处理器EventBusAnnotationProcessor生成索引

在配置annotationProcessor之后,程序在编译期间就可以通过注解处理器生成一个SubscriberInfoIndex类(SubscriberInfoIndex类的名称就是由arguments指定),在该类中就存储了Subscriber以及相关SubscriberMethod。

现在,我们来分析下索引类是如何生成的,也就是EventBus中注解处理器EventBusAnnotationProcessor是如何工作的。
如何对于注解处理器的工作原理不是很清楚的话,可以先看看Java AbstractProcessor实现自定义ButterKnife

process()

   @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
        Messager messager = processingEnv.getMessager();
        try {
            // 1、获取build.gradle中配置的arguments(这个就是在编译后生成类的全限定类名)
            String index = processingEnv.getOptions().get(OPTION_EVENT_BUS_INDEX);
            if (index == null) {
                messager.printMessage(Diagnostic.Kind.ERROR, "No option " + OPTION_EVENT_BUS_INDEX +
                        " passed to annotation processor");
                return false;
            }

            // 省略部分代码

            // 2、获取每个SubSubscriber中所有的SubscribeMethod
            collectSubscribers(annotations, env, messager);
            // 3、获取所有的不需要被执行的SubSubscriber
            checkForSubscribersToSkip(messager, indexPackage);

            if (!methodsByClass.isEmpty()) {
                //4、创建类文件,初始化所有索引
                createInfoIndexFile(index);
            } else {
                messager.printMessage(Diagnostic.Kind.WARNING, "No @Subscribe annotations found");
            }
            writerRoundDone = true;

        } catch (RuntimeException e) {
            // IntelliJ does not handle exceptions nicely, so log and print a message
            e.printStackTrace();
            messager.printMessage(Diagnostic.Kind.ERROR, "Unexpected error in EventBusAnnotationProcessor: " + e);
        }
        return true;
    }

在process()方法中,首先获取SubscriberInfoIndex类的类名index,如何这个index为空的话,注解处理器就会执行结束也就不能生成SubscriberInfoIndex类,所以在build.gradle必须配置arguments。

获取类名后,开始获取所有的Subscriber以及相关SubscriberMethod,这主要通过collectSubscribers()方法完成。

collectSubscribers()

    private void collectSubscribers(Set<? extends TypeElement> annotations, RoundEnvironment env, Messager messager) {
        for (TypeElement annotation : annotations) {
            Set<? extends Element> elements = env.getElementsAnnotatedWith(annotation);
            for (Element element : elements) {
                if (element instanceof ExecutableElement) {
                    ExecutableElement method = (ExecutableElement) element;
                    if (checkHasNoErrors(method, messager)) {
                        // 获取Subscriber类
                        TypeElement classElement = (TypeElement) method.getEnclosingElement();
                        // 存储每个Subscriber中的SubscriberMethod
                        methodsByClass.putElement(classElement, method);
                    }
                } else {
                    messager.printMessage(Diagnostic.Kind.ERROR, "@Subscribe is only valid for methods", element);
                }
            }
        }
    }

collectSubscribers()方法,主要就是遍历获取所有的Subscriber及SubscriberMethod,并且通过methodsByClass储存起来。

methodsByClass是一个ListMap,Key代表一个Subscriber类,value是一个存储该Subscriber所有SubscriberMethod的list集合。

这里我们通过putElement()方法可以看出:


public synchronized void putElement(K key, V value) {
    C collection = map.get(key);
    if (collection == null) {
        collection = createNewCollection();
        map.put(key, collection);
    }
    collection.add(value);
}

collectSubscribers()

通过collectSubscribers()方法获取到所有的Subscriber后,需要对其中一些不可用的Subscriber做一个过滤,例如私有类型或者受保护的类型。

这个方法在一般情况下也不会使用,所以这里就不做过多的介绍了。

createInfoIndexFile()

createInfoIndexFile()方法,就是具体的创建一个索引类,即生成一个Java文件。这里对这部分代码就不做过多说明了。

这里贴出一个实例代码:

package com.zhangke.eventbusdemo;

import org.greenrobot.eventbus.meta.SimpleSubscriberInfo;
import org.greenrobot.eventbus.meta.SubscriberMethodInfo;
import org.greenrobot.eventbus.meta.SubscriberInfo;
import org.greenrobot.eventbus.meta.SubscriberInfoIndex;

import org.greenrobot.eventbus.ThreadMode;

import java.util.HashMap;
import java.util.Map;

/** This class is generated by EventBus, do not edit. */
public class MyEventBusIndex implements SubscriberInfoIndex {
    private static final Map<Class<?>, SubscriberInfo> SUBSCRIBER_INDEX;

    static {
        SUBSCRIBER_INDEX = new HashMap<Class<?>, SubscriberInfo>();

        // 这里有两个Subscriber,每个Subscriber中都有两个SubscriberMethod
        putIndex(new SimpleSubscriberInfo(SecondActivity.class, true, new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("onFirstEvent", FirstEvent.class),
            new SubscriberMethodInfo("onSecond", FirstEvent.class, ThreadMode.MAIN, 1, true),
        }));

        putIndex(new SimpleSubscriberInfo(MainActivity.class, true, new SubscriberMethodInfo[] {
            new SubscriberMethodInfo("onFirstEvent", FirstEvent.class),
            new SubscriberMethodInfo("onSecond", FirstEvent.class, ThreadMode.MAIN, 1, false),
        }));

    }

    private static void putIndex(SubscriberInfo info) {
        SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);
    }

    @Override
    public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {
        SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
        if (info != null) {
            return info;
        } else {
            return null;
        }
    }
}

在该类中声明了一个SUBSCRIBER_INDEX的静态Map集合,并然后通过静态代码块将所有的Subscriber存储在该静态集合中。并且在该类中提供了有一个Override方法getSubscriberInfo()用于获取指定Subscriber中的SubscriberInfo。

@Override
public SubscriberInfo getSubscriberInfo(Class<?> subscriberClass) {
    SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);
    if (info != null) {
        return info;
    } else {
        return null;
    }
}

使用索引

在官方文档中提到,要想使用索引需要使用下面两种方式创建EventBus实例:

1、
EventBus eventBus = EventBus.builder().addIndex(new MyEventBusIndex()).build();

2、
EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
// Now the default instance uses the given index. Use it like this:
EventBus eventBus = EventBus.getDefault();

我们看看addIndex()方法的源码:

    /** Adds an index generated by EventBus' annotation preprocessor. */
    public EventBusBuilder addIndex(SubscriberInfoIndex index) {
        if (subscriberInfoIndexes == null) {
            subscriberInfoIndexes = new ArrayList<>();
        }
        subscriberInfoIndexes.add(index);
        return this;
    }

在该方法中,将SubscriberInfoIndex存储在subscriberInfoIndexes集合中。

那集合subscriberInfoIndexes在什么时候使用呢?
这里我们需要回到register()的过程中的findUsingInfo()方法中,在该方法中有一个方法getSubscriberInfo()在上节中我们不曾提到,这个方法就是用于获取索引中存储的Subscriber信息。

    private SubscriberInfo getSubscriberInfo(FindState findState) {
        if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) {
            SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo();
            if (findState.clazz == superclassInfo.getSubscriberClass()) {
                return superclassInfo;
            }
        }

        // 获取索引中的Subscriber内容
        if (subscriberInfoIndexes != null) {
            for (SubscriberInfoIndex index : subscriberInfoIndexes) {
                SubscriberInfo info = index.getSubscriberInfo(findState.clazz);
                if (info != null) {
                    return info;
                }
            }
        }
        return null;
    }

这样,就通过索引获取到了SubscriberInfo,这样在findUsingInfo()中,findUsingReflectionInSingleClass()方法就不会被调用了。最终的目的(避免反射的使用)也就达到了。

findUsingReflectionInSingleClass()方法就是在RunTime时使用反射获取SubscriberMethod

总结

EventBus3.0中创建索引,目的就是在编译期间通过注解处理器创建Java类,避免在RunTime期间反射的使用以提高程序整体的运行性能。

一文读懂 SAP BTP Application Router 的 Resource Files:从 xs-app.json 到本地开发的默认设置 本文详解SAP BTP中Application Router的资源文件配置与本地开发实践。核心包括:xs-app.json定义路由规则与安全策略,package.json声明依赖与启动脚本,resources/存放静态资源,default-services.json和local-destinations.json用于本地模拟云服务。文章通过真实案例展示如何配置静态资源直出、反向代理后端服务,并强调本地开发时的注意事项与常见问题解决路径。关键配置均提供示例代码,帮助开发者快速实现业务应用的部署与联调。 阅读详情

相关推荐

深度学习优化算法解析(Momentum, RMSProp, Adam)

之前看了很多人介绍网络的优化器optimizer,无奈很多都把简单的东西讲的复杂化了,不容易让人懂,恰好之前看过吴恩达老师的最新的课程,这里结合老师讲的和个人想法写一下,方便别人同时也为自己以后回顾吧。 深度学习的优化算法主要有GD,SGD,Momentum,RMSProp和Adam算法吧,还有诸如Adagrad算法,不过大同小异,理解了前面几个,后面的也就引刃而解了。GD算法,SGD算法以及m

willduan的博客 12万+

EventBus拾遗—索引

EventBus 是 Android 中基于 观察者模式 实现的 发布-订阅事件总线 第三方开源框架。 其优势如下: 轻量级框架,执行效率高 使用简单,工程代码保持简洁优雅 简化了组件之间的通信,将事件的发送者和接收者解耦 一、基础回顾 1.自定义配置 2.订阅方法格式 3.事件的继承 4.避免OOM 二、源码回顾 1. 关键的类 SubscriberMethod: 对订阅方法的相关信息的封装类(Method,...

一杯苦芥的专栏 393

别再手动调参了!用Optuna+PyTorch搞定Transformer时序预测超参数(附完整代码)

本文详细介绍了如何利用Optuna和PyTorch实现Transformer时序预测模型的自动化超参数调优。通过贝叶斯优化技术,显著提升单变量时序预测的效率和准确性,并附有完整代码实现。文章涵盖模型架构设计、数据预处理、Optuna调参实战及生产环境部署建议,为开发者提供一站式解决方案。

weixin_33704234的博客 577

EventBus索引加速探究,积累总结

// EventBusBuidler.java /** Adds an index generated by EventBus’ annotation preprocessor. */ public EventBusBuilder addIndex(SubscriberInfoIndex index) { if (subscriberInfoIndexes == null) { subscriberInfoIndexes = new ArrayList<>(); } subscriberInfo

m0_66264533的博客 605

F28335 DSP ePWM模块实战:从基础配置到电机控制

本文详细解析了TI TMS320F28335 DSP的ePWM模块,从基础概念、寄存器配置到实战应用。通过代码示例,手把手教你如何配置定时中断、生成PWM波形、实现死区保护与故障联防,并最终完成一个可调速、可换向的直流电机控制项目,是掌握F28335电机控制核心技术的实战指南。

g5h6i的博客 1128

LauterBach使用教程

(也就是服务器上编译时候的路径一模一样的路径,选中到工程目录就可以)4.选择自己板子对应的cpu(可以直接界面选择也可以命令行的方式)(cpu里的system setting),我们板子需要sys复位,所以选择sys。注:一般情况下运行状态不可以修改外设寄存器的值,但是可以通过修改配置来修改为运行时可修改(cpu寄存器则不可以)(修改这个配置,运行时也可以查看代码)注意:lauterbach可以使用命令来操作,但是由于本人刚刚使用,目前基本上使用的都是界面的按钮,以后会陆续学习命令行指令和脚本的方式。

wacebb的博客 1万+

EventBus源码---索引优化的使用

搞了4个小时左右,终于把EventBus的索引优化弄明白了。这里的明白是知道怎么使用了,源码的话,我们下篇文章来说。所以这篇文章我们仅从使用上面来说索引优化。有的同学可能会说,使用嘛,即便是没用过,百度一下也就OK了。以下两点,是我要写这篇博客的原因: (1)我问了我身边做Android开发的朋友,他们使用EventBus都没有使用过索引优化,不使用索引优化也没有感觉EventBus慢。既然这样,谁还会去理这个索引优化呢?所以,大家好像都不怎么关心索引优化。我们要想技术上高人一等,就要知道别人所不知道的

qq_32019367的博客 2345

SPH vs Lagrange网格混合建模实战:用LS-DYNA模拟弹丸穿孔效应

本文深入探讨了在LS-DYNA中运用SPH与Lagrange网格混合建模技术,高效模拟超高速碰撞下弹丸穿孔效应的实战方法。通过分析模型分区策略、耦合界面处理及关键参数设置,解决了传统方法在模拟大变形、材料断裂时的网格畸变或计算成本高昂问题,为相关工程仿真提供了兼顾精度与效率的解决方案。

weixin_29211309的博客 109

EventBus 中文文档,android性能优化面试

EventBus 帮您可以处理线程问题:事件可以发布到与发布线程不同的线程中。一个常见的用例是处理 UI 变化。对于 Android,UI 改变必须发生在 UI(main)线程中。另一方面,网络请求或其他任何耗时的任务不得在主线程上运行。EventBus 可以帮助你处理这些问题,并与 UI 线程保持协调(您不必深入到线程转换,比如使用 AsyncTask 等)。在 EventBus 中,您可以使用四种线程模式之一来指定调用事件处理方法的线程。

m0_56169789的博客 861

sentaurus学习笔记(HFET_pGate_GaN仿真)(五)

`(sdedr:define-constant-profile`和`(sdedr:define-constant-profile-region`命令用于定义并应用一个恒定的活性硼掺杂浓度剖面`"ndop_GaN_gate_const"`到氮化镓栅极层上,其值为`NpGaN_gate`。- `"Oxide"`指定了这一层的材料名称(在这里代表氧化层),而`"nucleation"`是这一层在仿真中的标识名称。- `"GaN"`指定了这一层的材料名称,而`"GaN_gate"`是这一层在仿真中的标识名称。

qq_52640792的博客 940

从被秒封到稳过Cloudflare!Canvas/WebGL/WebRTC多维度浏览器指纹隐身全实战

反爬和反反爬,本质上是一场持续的博弈,没有100%的隐身,只有不断升级的伪装。网上很多教程只给了个基础的噪声代码,却没讲透反爬的检测逻辑,导致你用了还是被封。这套方案的核心,不是简单的API重写,而是站在反爬的角度,模拟真实用户的所有特征,保证所有指纹的一致性、合理性、完整性。目前这套方案我用了半年,跑了上千万次请求,稳过国内国外99%的主流反爬平台,没有出现过一次因为指纹关联导致的批量封禁。大家有什么更狠的反爬场景,或者更好的伪装技巧,欢迎评论区一起交流。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1194

EventBus的特性及简单的使用介绍

EventBus是一个用于Android和Java的开源库,使用发布者/订阅者模式(publisher/subscriber pattern)实现松散(loose)耦合(coupling)。EventBus使中央通信仅用几行代码就能解耦类(decouple classes)——简化代码(simplifying the code)、消除依赖(removing dependencies)和加速应用程序...

WindfallSheng的博客 905

【WRF模拟】土地利用类型的确定:最大覆盖法/瓦片法

土地利用类型的确定:最大覆盖法/瓦片法

WW、forever的博客 1529

EventBus3.0性能优化之添加索引(Index)

前言第一次写博客,希望有不足之处多多指教,文中有错误之处也请大家批评指出。关于EventBus3.0的使用我就不说了,网上已经有很多优秀的文章讲解了,主要是说说3.0内关于提升性能的一个东东,就是添加索引. 正文关于EventBus的索引,在EventBus 3.0用法详解中有写道 将你的每一个事件的参数类封装为一个类,然后加入这一段之后即可将EventBus3.0性能提高一倍(项目app

z609933542的博客 8998

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

EventBus索引加速探究

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

2401_84123077的博客 689

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

EventBus3.0——索引的使用

EventBus3.0——索引的使用 相信对于索引这个词大家不会陌生,很多地方都有用到,那么为什么EventBus会引进索引这个东西,大家都知道EventBus的功能是通过反射机制获取观察者(订阅者)方法来实现的,而反射本身对性能的损耗比起一般的方法来说要大很多,具体慢多少,你们可以写一个程序测试下,大概50倍左右(当然对于CPU的运行速度,没有你想象中夸张)。

会飞的鱼~的博客 3211

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

EventBus索引加速探究,干货满满

注释2:判断是否为空,如果不为空,则遍历所有,找到一个和 订阅者相匹配的 SubscriberInfo返回回去。那是什么?怎么来的呢?首先它是一个类型,它是一个列表,里面放的是 “订阅者索引”。它在 EventBus的构造方法中被创建:可以看出它是来自于,而在EventBusBuilder中, 这个对象又是怎么产生的呢,我通过源码,发现它只有一处地方用来操作这个列表:通过addIndex()将往这个列表里面加。再往上找,没有了,addIndex()没有出现在任意一处被调用的地方。

2201_75604341的博客 1151

10倍性能提升:EventBus优化实战指南

你还在为EventBus引发的应用卡顿烦恼?还在纠结如何解决事件分发延迟问题?本文将从源码分析到实战优化,带你全面掌握EventBus性能调优技巧,轻松实现10倍性能提升。读完本文你将获得: - 识别EventBus性能瓶颈的核心方法 - 5个立竿见影的优化技巧 - 基于真实测试数据的性能对比 - 高级特性的正确使用姿势 ## 性能瓶颈深度剖析 EventBus作为Android和Java平台...

gitblog_01018的博客 974

EventBus3.0新特性之Subscriber Index

最近在读EventBus3.0源码,发现了一个问题,EventBus.getDefault().register(this) 这种方式其实还是使用反射机制获取注解属性和方法的,并没有使用到注解处理器。 一 什么是Subscriber Index ...

weixin_36637758的博客 424

EventBus3.0核心机制与Android事件总线优化实践

事件总线是Android开发中实现组件解耦的关键技术,其核心原理基于发布-订阅模式。通过注解处理器和反射机制,EventBus3.0构建了高效的事件分发系统,支持POSTING、MAIN、BACKGROUND和ASYNC四种线程处理模式,满足不同场景下的线程切换需求。在性能优化方面,编译时生成的订阅索引可大幅提升启动速度,避免Android 9.0+的反射限制。结合粘性事件管理和订阅优先级机制,开发者能实现更灵活的业务逻辑控制。对于高频事件场景,建议采用事件合并与对象池技术优化处理效率,同时需注意内存泄漏防

weixin_33947521的博客 493

EventBus索引加速探究,事件分发机制面试题

注释2:将 订阅者对象 和注释1处获取到的FindState对象绑定,代码是这样的:// 这里 subscriberInfo置null注释3:通过来获取这个注释4: 如果subscriberInfo存在,就从 subscriberInfo中获取 @Subscribe方法注释5:如果subscriberInfo不存在,就调用反射+暴力的方法寻找,就是一开始的显然,注释3的获取的东西,可以验证我们有没有开启 索引加速。我们来看看这个方法:if (info!= null) {

2401_84152177的博客 1056

EventBus3.0架构解析与Android事件总线优化实践

事件总线是Android开发中实现组件解耦的核心技术,其通过发布-订阅模式消除组件间的直接依赖。EventBus3.0作为主流实现方案,采用三级缓存机制和编译期注解处理,显著提升事件分发效率至微秒级。在移动端开发场景中,合理的线程模式选择(如MAIN模式处理UI更新)和对象复用技术(如事件池)能有效降低GC压力。针对高频事件处理,可通过预编译订阅索引优化性能,而组件化架构中的中央事件枢纽设计则能实现跨模块通信。本文深入解析粘性事件管理、内存泄漏防范等工程实践要点,为高并发场景提供可靠解决方案。

weixin_30861797的博客 416

EventBus中的SubscriberInfoIndex

EventBus中的注解处理器生成的索引类(SubscriberInfoIndex) 在EventBus源码解析中的findUsingInfo方法中有说到如果没有配置索引类,那么就会调用findUsingReflectionInSingleClass方法,在运行时利用反射来获取所有被@Subscribe注解标注的订阅方法,但这种做法对应用性能会有一定的损耗,所以在3.0后EventBus提供了索引...

JW的博客 420

EventBus之Subscriber Index

Subscriber Index 订阅者索引是EventBus 3的一个新特性。这是一个可选的优化,以加快初始订阅者注册。 Subscriber Index在编译时(build time)使用EventBus注解处理器(annotation processor)创建。虽然不是必须要使用索引,但建议在Android上使用索引以获得最佳性能。 Index Preconditions 注意,只能...

WindfallSheng的博客 912

Android 进阶4:EventBus3.0源码分析

前几篇文章分析了Activity的源码,后来看了看Window以及ViewRoot的相关源码,这些只是还没梳理,真的是视觉疲劳,来一个EventBus源码分析压压惊~。 其实关于EventBus的源码分析,网上也有很多,但是终究是别人的,以前也看过很多遍,但是决定是自己写下来比较好,座右铭:看一遍,不如自己写一遍。 关于EventBus的小总结我们先看下,带着知识点去看源码,然后分析为什么要这么写...

lmq121210的博客 1365
上一篇: EventBus3.0 源码解析
下一篇: UML 类图和时序图
Kerwin zhang
博客等级 码龄12年 21粉丝 28原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值