字节跳动正式启动2024届秋季校招!这份字节跳动历年校招Android面试真题解析,你确定不收藏?(上)(1)

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注Android)
img

正文

Q:ContentProvider了解多少?

  • 技术点:ContentProvider
  • 思路:ContentProvider功能
  • 参考回答:作为四大组件之一,ContentProvider主要负责存储和共享数据。与文件存储、SharedPreferences存储、SQLite数据库存储这几种数据存储方法不同的是,后者保存下的数据只能被该应用程序使用,而前者可以让不同应用程序之间进行数据共享,它还可以选择只对哪一部分数据进行共享,从而保证程序中的隐私数据不会有泄漏风险。
  • 引申:谈谈ContentProvider底层使用Binder机制原理

Q:Android中提供哪些数据持久存储的方法?

  • 技术点:数据持久化
  • 思路:分条解释每种数据持久存储的特点
  • 参考回答:Android平台实现数据存储的常见几种方式:
    • File 文件存储:写入和读取文件的方法和 Java中实现I/O的程序一样。
    • SharedPreferences存储:一种轻型的数据存储方式,常用来存储一些简单的配置信息,本质是基于XML文件存储key-value键值对数据。
    • SQLite数据库存储:一款轻量级的关系型数据库,它的运算速度非常快,占用资源很少,在存储大量复杂的关系型数据的时可以使用。
    • ContentProvider:四大组件之一,用于数据的存储和共享,不仅可以让不同应用程序之间进行数据共享,还可以选择只对哪一部分数据进行共享,可保证程序中的隐私数据不会有泄漏风险。

Q:Java中的I/O流读写怎么做?

  • 技术点:数据持久化(文件存储)
  • 思路:大致介绍核心类和核心方法
  • 参考回答:和 Java中实现I/O的程序是一样的,Context类中提供了openFileInput()和openFileOutput()方法来打开数据文件里的文件IO流,有关读写涉及的主要方法详见文章学习笔记| AS入门(七) 数据存储篇

Q:SharePreferences适用情形?使用中需要注意什么?

  • 技术点:数据持久化(SharePreferences存储)
  • 参考回答:SharePreferences是一种轻型的数据存储方式,适用于存储一些简单的配置信息,如int、string、boolean、float和long。由于系统对SharedPreferences的读/写有一定的缓存策略,即在内存中有一份该文件的缓存,因此在多进程模式下,其读/写会变得不可靠,甚至丢失数据。
  • 引申:谈谈Android中多进程通信(Binder)

Q:了解SQLite中的事务处理吗?是如何做的?

  • 技术点:数据持久化(SQLite)
  • 参考回答:SQLite在做CRDU操作时都默认开启了事务,然后把SQL语句翻译成对应的SQLiteStatement并调用其相应的CRUD方法,此时整个操作还是在rollback journal这个临时文件上进行,只有操作顺利完成才会更新.db数据库,否则会被回滚。
  • 引申:谈谈如何模仿SQLite中事务的思想更高效进行批量操作

Q:使用SQLite做批量操作有什么好的方法吗?

  • 技术点:数据持久化(SQLite)
  • 思路:模仿SQLite的事务处理
  • 参考回答:使用SQLiteDatabase的beginTransaction()方法开启一个事务,将批量操作SQL语句转化成SQLiteStatement并进行批量操作,结束后endTransaction()

Q:如果现在要删除SQLite中表的一个字段如何做?

  • 技术点:数据持久化(SQLite)
  • 参考回答:SQLite数据库只允许增加表字段而不允许修改和删除表字段,只能采取复制表思想,即创建一个新表保留原表想要的字段、再将原表删除

Q:使用SQLite时会有哪些优化操作?

  • 技术点:数据持久化(SQLite)
  • 思路:列举可优化点
  • 参考回答:
    • 使用事务做批量操作:具体操作见上
    • 及时关闭Cursor,避免内存泄漏
    • 耗时操作异步化:数据库的操作属于本地IO,通常比较耗时,建议将这些耗时操作放入异步线程中处理
    • ContentValues的容量调整:ContentValues内部采用HashMap来存储Key-Value数据,ContentValues初始容量为8,扩容时翻倍。因此建议对ContentValues填入的内容进行估量,设置合理的初始化容量,减少不必要的内部扩容操作
    • 使用索引加快检索速度:对于查询操作量级较大、业务对要求查询要求较高的推荐使用索引

Q:Android中进程和线程的关系?

  • 技术点:进程、线程
  • 参考回答:
    • 形象理解:如果把安卓系统比喻成一片土壤,可以把App看做扎根在这片土壤上的工厂,每个APP一般对应一个进程,那么线程就像是工厂的生产线。其中,主线程好比是主生产线,只有一条,子线程就像是副生产线,可以有很多条。
    • 关系:一个APP一般对应一个进程和有限个线程
      • 一般对应一个进程,当然,可以在AndroidMenifest中给四大组件指定属性android:process开启多进程模式
      • 有限个线程:线程是一种受限的系统资源,不可无限制的产生且线程的创建和销毁都有一定的开销。

Q:为何需要进行IPC?多进程通信可能会出现什么问题?

  • 技术点:多进程通信
  • 思路:讨论多进程通信会出现的问题得出IPC的必要性
  • 参考回答:
  • (1)多进程造成的影响可总结为以下四方面:
    • 静态变量和单例模式失效:由独立的虚拟机造成
    • 线程同步机制失效:由独立的虚拟机造成
    • SharedPreference的不可靠下降:不支持两个进程同时进行读写操作,即不支持并发读写,有一定几率导致数据丢失
    • Application多次创建: Android系统会为新的进程分配独立虚拟机,相当于系统又把这个应用重新启动了一次。
  • (2)需要进程间通信的必要性:所有运行在不同进程的四大组件,只要它们之间需要通过内存在共享数据,都会共享失败。这是由于Android为每个应用分配了独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,这会导致在不同的虚拟机中访问同一个类的对象会产生多份副本。
  • 引申: 谈谈IPC的使用场景

Q:什么是序列化?Serializable接口和Parcelable接口的区别?为何推荐使用后者?

  • 技术点:序列化
  • 参考回答:序列化表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。
    • 应用场景:需要通过Intent和Binder等传输类对象就必须完成对象的序列化过程。
    • 两种方式:实现Serializable/Parcelable接口。不同点如图:

Q:Android中为何新增Binder来作为主要的IPC方式?

  • 技术点:Binder机制
  • 思路:回答Binder优点
  • 参考回答:Binder机制有什么几条优点
    • 传输效率高、可操作性强:传输效率主要影响因素是内存拷贝的次数,拷贝次数越少,传输速率越高。从Android进程架构角度分析:对于消息队列、Socket和管道来说,数据先从发送方的缓存区拷贝到内核开辟的缓存区中,再从内核缓存区拷贝到接收方的缓存区,一共两次拷贝,如图:

而对于Binder来说,数据从发送方的缓存区拷贝到内核的缓存区,而接收方的缓存区与内核的缓存区是映射到同一块物理地址的,节省了一次数据拷贝的过程,如图:

由于共享内存操作复杂,综合来看,Binder的传输效率是最好的。

  • 实现C/S架构方便:Linux的众IPC方式除了Socket以外都不是基于C/S架构,而Socket主要用于网络间的通信且传输效率较低。Binder基于C/S架构 ,Server端与Client端相对独立,稳定性较好。
  • 安全性高:传统Linux IPC的接收方无法获得对方进程可靠的UID/PID,从而无法鉴别对方身份;而Binder机制为每个进程分配了UID/PID且在Binder通信时会根据UID/PID进行有效性检测。

Q:使用Binder进行数据传输的具体过程?

  • 技术点:Binder机制
  • 思路:通过AIDL实现方式解释Binder数据传输的具体过程
  • 参考回答:服务端中的Service给与其绑定的客户端提供Binder对象,客户端通过AIDL接口中的asInterface()将这个Binder对象转换为代理Proxy,并通过它发起RPC请求。客户端发起请求时会挂起当前线程,并将参数写入data然后调用transact(),RPC请求会通过系统底层封装后由服务端的onTransact()处理,并将结果写入reply,最后返回调用结果并唤醒客户端线程。

Q:Binder框架中ServiceManager的作用?

  • 技术点:Binder机制
  • 思路:从Binder框架出发讨论每个元素的作用
  • 参考回答:在Binder框架定义了四个角色:Server,Client,ServiceManager和Binder驱动。其中Server、Client、ServiceManager运行于用户空间,Binder驱动运行于内核空间。关系如图:

  • Server&Client:服务器&客户端。在Binder驱动和Service Manager提供的基础设施上,进行Client-Server之间的通信。
  • ServiceManager服务的管理者,将Binder名字转换为Client中对该Binder的引用,使得Client可以通过Binder名字获得Server中Binder实体的引用。流程如图:

  • Binder驱动
  • 与硬件设备没有关系,其工作方式与设备驱动程序是一样的,工作于内核态。
  • 提供open()mmap()poll()ioctl() 等标准文件操作。
  • 以字符驱动设备中的misc设备注册在设备目录/dev下,用户通过/dev/binder访问该它。
  • 负责进程之间binder通信的建立,传递,计数管理以及数据的传递交互等底层支持。
  • 驱动和应用程序之间定义了一套接口协议,主要功能由ioctl() 接口实现,由于ioctl()灵活、方便且能够一次调用实现先写后读以满足同步交互,因此不必分别调用write()和read()接口。
  • 其代码位于linux目录的drivers/misc/binder.c中。

Q:Android中有哪些基于Binder的IPC方式?简单对比下?

  • 技术点:IPC方式
  • 思路:分析每种IPC方式的优缺点和使用场景的差异
  • 参考回答:

Q:是否了解AIDL?原理是什么?如何优化多模块都使用AIDL的情况?

  • 技术点:AIDL
  • 思路:
  • 参考回答:
    • AIDL(Android Interface Definition Language,Android接口定义语言):如果在一个进程中要调用另一个进程中对象的方法,可使用AIDL生成可序列化的参数,AIDL会生成一个服务端对象的代理类,通过它客户端实现间接调用服务端对象的方法。
    • AIDL的本质是系统提供了一套可快速实现Binder的工具。关键类和方法:
      • AIDL接口:继承IInterface
      • Stub类:Binder的实现类,服务端通过这个类来提供服务。
      • Proxy类:服务器的本地代理,客户端通过这个类调用服务器的方法。
      • asInterface():客户端调用,将服务端的返回的Binder对象,转换成客户端所需要的AIDL接口类型对象。返回对象:
        • 若客户端和服务端位于同一进程,则直接返回Stub对象本身;
        • 否则,返回的是系统封装后的Stub.proxy对象。
      • asBinder():根据当前调用情况返回代理Proxy的Binder对象。
      • onTransact():运行服务端的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法来处理。
      • transact():运行在客户端,当客户端发起远程请求的同时将当前线程挂起。之后调用服务端的onTransact()直到远程请求返回,当前线程才继续执行。
    • 当有多个业务模块都需要AIDL来进行IPC,此时需要为每个模块创建特定的aidl文件,那么相应的Service就会很多。必然会出现系统资源耗费严重、应用过度重量级的问题。解决办法是建立Binder连接池,即将每个业务模块的Binder请求统一转发到一个远程Service中去执行,从而避免重复创建Service。
      • 工作原理:每个业务模块创建自己的AIDL接口并实现此接口,然后向服务端提供自己的唯一标识和其对应的Binder对象。服务端只需要一个Service,服务器提供一个queryBinder接口,它会根据业务模块的特征来返回相应的Binder对像,不同的业务模块拿到所需的Binder对象后就可进行远程方法的调用了。流程如图:

Q:MotionEvent是什么?包含几种事件?什么条件下会产生?

  • 技术点:View触控
  • 参考回答:MotionEvent是手指触摸屏幕锁产生的一系列事件。包含的事件有:
    • ACTION_DOWN:手指刚接触屏幕
    • ACTION_MOVE:手指在屏幕上滑动
    • ACTION_UP:手指在屏幕上松开的一瞬间
    • ACTION_CANCEL:手指保持按下操作,并从当前控件转移到外层控件时会触发

Q:scrollTo()和scrollBy()的区别?

  • 技术点:View滑动
  • 参考回答:scrollBy内部调用了scrollTo,它是基于当前位置的相对滑动;而scrollTo是绝对滑动,因此如果利用相同输入参数多次调用scrollTo()方法,由于View初始位置是不变只会出现一次View滚动的效果而不是多次。
  • 引申:两者都只能对view内容进行滑动,而不能使view本身滑动,且非平滑,可使用Scroller有过渡滑动的效果

Q:Scroller中最重要的两个方法是什么?主要目的是?

  • 技术点:View滑动
  • 思路:从Scroller实现滑动的具体过程出发,
  • 参考回答:Scroller实现滑动的具体过程:
    • 在MotionEvent.ACTION_UP事件触发时调用startScroll()方法,该方法并没有进行实际的滑动操作,而是记录滑动相关量
    • 马上调用invalidate/postInvalidate()方法,请求View重绘,导致View.draw方法被执行
    • 紧接着会调用View.computeScroll()方法,此方法是空实现,需要自己处理逻辑。具体逻辑是:先判断computeScrollOffset(),若为true(表示滚动未结束),则执行scrollTo()方法,它会再次调用postInvalidate(),如此反复执行,直到返回值为false。流程图如下:

其中,最重要的两个方法是startScroll()和computeScroll()

Q:谈一谈View的事件分发机制?

  • 技术点:View事件分发
  • 思路:从分发本质、传递顺序、核心方法展开
  • 参考回答:
    • 事件分发本质:就是对MotionEvent事件分发的过程。即当一个MotionEvent产生了以后,系统需要将这个点击事件传递到一个具体的View上。
    • 点击事件的传递顺序:Activity(Window) -> ViewGroup -> View
    • 三个主要方法:
      • dispatchTouchEvent:进行事件的分发(传递)。返回值是 boolean 类型,受当前onTouchEvent和下级view的dispatchTouchEvent影响
      • onInterceptTouchEvent:对事件进行拦截。该方法只在ViewGroup中有,View(不包含 ViewGroup)是没有的。一旦拦截,则执行ViewGroup的onTouchEvent,在ViewGroup中处理事件,而不接着分发给View。且只调用一次,所以后面的事件都会交给ViewGroup处理。
      • onTouchEvent:进行事件处理。

Q:如何解决View的滑动冲突?

  • 技术点:View滑动冲突
  • 思路:从处理规则和具体实现方法展开讨论
  • 参考回答:
  • (1)处理规则:
    • 对于由于外部滑动和内部滑动方向不一致导致的滑动冲突,可以根据滑动的方向判断谁来拦截事件。
    • 对于由于外部滑动方向和内部滑动方向一致导致的滑动冲突,可以根据业务需求,规定何时让外部View拦截事件何时由内部View拦截事件。
    • 对于上面两种情况的嵌套,相对复杂,可同样根据需求在业务上找到突破点。
  • (2)实现方法:
    • 外部拦截法:指点击事件都先经过父容器的拦截处理,如果父容器需要此事件就拦截,否则就不拦截。具体方法:需要重写父容器的onInterceptTouchEvent方法,在内部做出相应的拦截。
    • 内部拦截法:指父容器不拦截任何事件,而将所有的事件都传递给子容器,如果子容器需要此事件就直接消耗,否则就交由父容器进行处理。具体方法:需要配合requestDisallowInterceptTouchEvent方法。

Q:谈一谈View的工作原理?

  • 技术点:View工作流程
  • 思路:围绕三大流程展开
  • 参考回答:View工作流程简单来说就是,先measure测量,用于确定View的测量宽高,再 layout布局,用于确定View的最终宽高四个顶点的位置,最后 draw绘制,用于将View 绘制到屏幕上。具体过程图见:

  • ViewRoot对应于ViewRootImpl类,它是连接WindowManager和DecorView的纽带。
    * View的绘制流程是从ViewRootperformTraversals开始。
    * performTraversals()依次调用performMeasure()、performLayout()和performDraw()三个方法,分别完成顶级 View的绘制。
    * 其中,performMeasure()会调用measure(),measure()中又调用onMeasure(),实现对其所有子元素的measure过程,这样就完成了一次measure过程;接着子元素会重复父容器的measure过程,如此反复至完成整个View树的遍历。layout和draw同理。

Q:MeasureSpec是什么?有什么作用?

  • 技术点:View工作流程(measure)
  • 思路:从MeasureSpec作用、组成、模式和决定因素展开
  • 参考回答:
    • 作用:通过宽测量值widthMeasureSpec和高测量值heightMeasureSpec决定View的大小
    • 组成:一个32位int值,高2位代表SpecMode(测量模式),低30位代表SpecSize( 某种测量模式下的规格大小)。
    • 三种模式:
      • UNSPECIFIED:父容器不对View有任何限制,要多大有多大。常用于系统内部。
      • EXACTLY(精确模式):父视图为子视图指定一个确切的尺寸SpecSize。对应LyaoutParams中的match_parent具体数值
      • AT_MOST(最大模式):父容器为子视图指定一个最大尺寸SpecSize,View的大小不能大于这个值。对应LayoutParams中的wrap_content
    • 决定因素:值由子View的布局参数LayoutParams父容器的MeasureSpec值共同决定。具体规则见下图:

  • 引申:直接继承View的自定义View需要重写onMeasure()并设置wrap_content时的自身大小,否则效果相当于macth_parent

Q:自定义View/ViewGroup需要注意什么?

  • 技术点:自定义View
  • 参考回答:

Q:onTouch()、onTouchEvent()和onClick()关系?

  • 技术点:View事件分发
  • 参考回答:优先度onTouch()>onTouchEvent()>onClick()。因此onTouchListener的onTouch()方法会先触发;如果onTouch()返回false才会接着触发onTouchEvent(),同样的,内置诸如onClick()事件的实现等等都基于onTouchEvent();如果onTouch()返回true,这些事件将不会被触发。
  • 引申:OnTouchListener、OnClickListener的冲突

Q:SurfaceView和View的区别?

  • 技术点:View、SurfaceView
  • 参考回答:SurfaceView是从View基类中派生出来的显示类,他和View的区别有:
    • View需要在UI线程对画面进行刷新,而SurfaceView可在子线程进行页面的刷新
    • View适用于主动更新的情况,而SurfaceView适用于被动更新,如频繁刷新,这是因为如果使用View频繁刷新会阻塞主线程,导致界面卡顿
    • SurfaceView在底层已实现双缓冲机制,而View没有,因此SurfaceView更适用于需要频繁刷新、刷新时数据处理量很大的页面

Q:invalidate()和postInvalidate()的区别?

  • 技术点:View刷新
  • 参考回答:invalidate()与postInvalidate()都用于刷新View,主要区别是invalidate()在主线程中调用,若在子线程中使用需要配合handler;而postInvalidate()可在子线程中直接调用。

Q:了解哪些Drawable?适用场景?

  • 技术点:res资源
  • 参考回答:BitmapDrawable表示一张图片、NinePatchDrawable可自动地根据所需的宽/高对图片进行相应的缩放并保证不失真、ShapeDrawable表示纯色、有渐变效果的基础几何图形、StateListDrawable表示一个Drawable的集合且每个Drawable对应着View的一种状态、LayerDrawable可通过将不同的Drawable放置在不同的层上面从而达到一种叠加后的效果

Q:mipmap系列中xxxhdpi、xxhdpi、xhdpi、hdpi、mdpi和ldpi存在怎样的关系?

  • 技术点:res资源
  • 参考回答:表示不同密度的图片资源,像素从高到低依次排序为xxxhdpi>xxhdpi>xhdpi>hdpi>mdpi>ldpi,根据手机的dpi不同加载不同密度的图片

Q:dp、dpi、px的区别?

  • 技术点:Android适配
  • 参考回答:
    • px:像素,如分辨率1920x1080表示高为1920个像素、宽为1080个像素
    • dpi:每英寸的像素点,如分辨率为1920x1080的手机尺寸为4.95英寸,则该手机DPI为(1920x1920+ 1080x1080)½/4.95≈445dpi
    • dp:密度无关像素,是个相对值

Q:res目录和assets目录的区别?

  • 技术点:res、assets
  • 参考回答:
    • res/raw中的文件会被映射到R.java文件中,访问时可直接使用资源ID,不可以有目录结构
    • assets文件夹下的文件不会被映射到R.java中,访问时需要AssetManager类,可以创建子文件夹

受文章发表字数限制,题解一共分成上中下篇
彩蛋:

在当下这个碎片化信息环境的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了

很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘

如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。

2017-2020上万页的大厂面试真题

各个模块学习视频:如数据结构与算法

学习宝典

对我们开发者来说,一定要打好基础,随时准备战斗。不论寒冬是否到来,都要把自己的技术做精做深。虽然目前移动端的招聘量确实变少了,但中高端的职位还是很多的,这说明行业只是变得成熟规范起来了。竞争越激烈,产品质量与留存就变得更加重要,我们进入了技术赋能业务的时代。

不论遇到什么困难,都不应该成为我们放弃的理由!

很多人在刚接触这个行业的时候或者是在遇到瓶颈期的时候,总会遇到一些问题,比如学了一段时间感觉没有方向感,不知道该从那里入手去学习,对此我针对Android程序员,我这边给大家整理了一套学习宝典!包括不限于高级UI、性能优化、移动架构师、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

【Android核心高级技术PDF文档,BAT大厂面试真题解析】

【算法合集】

【延伸Android必备知识点】

【Android部分高级架构视频学习资源】

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

d核心高级技术PDF文档,BAT大厂面试真题解析】**

[外链图片转存中…(img-Kwwe3Anz-1713324512827)]

【算法合集】

[外链图片转存中…(img-RJ3eYBWf-1713324512827)]

【延伸Android必备知识点】

[外链图片转存中…(img-sjOvr7tr-1713324512828)]

【Android部分高级架构视频学习资源】

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-pBeAjMnI-1713324512828)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值