Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Python下的毫秒级延迟RTSP|RTMP播放器技术探究和AI视觉算法对接

Python下的毫秒级延迟RTSP|RTMP播放器技术探究和AI视觉算法对接

原创
作者头像
音视频牛哥
发布于 2025-03-07 10:05:56
发布于 2025-03-07 10:05:56
12900
代码可运行
举报
运行总次数:0
代码可运行

​引言

十年前,大牛直播SDK发布了跨平台的RTMP、RTSP毫秒级低延迟播放器,随着AI的爆发式普及和发展,加之大多视觉算法分析,都是用在Python下,Python下对视频流延迟的要求越来越高,本文将深入解析基于Python实现的RTSP/RTMP播放器,探讨其代码结构、实现原理以及优化策略,先看使用场景:

实时监控与安防预警

  • 交通监控:在城市交通管理中,通过低延迟播放器实时获取各个路口和路段的监控视频,交通管理人员可以及时查看路况,如是否有拥堵、事故等,并做出相应决策,如调整信号灯时长、派遣交警疏导等。
  • 安防监控:在小区、商场、工厂等场所,安防人员需要实时监控各个区域的情况,低延迟播放器能让他们及时发现异常行为、人员闯入等安全隐患,迅速采取措施。
  • 工业监控:在工业生产中,对生产设备、生产线等进行实时监控,以便及时发现设备故障、生产异常等情况,减少停机时间和损失。

视频会议与远程协作

  • 远程办公:在远程办公场景下,低延迟播放器可以用于实时获取远程同事的视频画面和音频,实现面对面般的沟通效果,提高远程协作的效率。
  • 在线教育:教师可以通过低延迟播放器实时播放教学视频,学生能够及时看到教师的讲解和演示,增强在线学习的互动性和实时性。

智能视频分析与处理

  • 体育赛事直播:在体育赛事直播中,低延迟播放器可以实时获取比赛画面,配合视频分析算法,实现对比赛情况的实时分析,如运动员的动作识别、球队战术分析等。
  • 医疗手术直播:在医疗领域,低延迟播放器可以用于实时获取手术室的视频画面,供远程专家进行实时指导,提高手术的成功率和安全性。

Python下的RTMP、RTSP播放器延迟可以做到多低?以大牛直播SDK的Windows平台RTMP推送模块采集毫秒计数器窗口,然后推RTMP流到NGINX服务器,Python播放器拉流播放,整体延迟如下:

听说图片信服力不够?那就看视频:

代码结构与功能概述

实际上,几年前就有一些开发者自己基于我们的Windows播放器SDK提供的接口,实现了Python下的低延迟播放,这个时候我们官方发布Python的demo,实际上一点儿也不意外,或者说本身难度也不大,因为底层都还是调了C接口,只是根据Python的调用规范做了下接口的转换,下面,我们从代码结构和功能这块,针对Python下的播放器实现,做个大概的说明:

类结构

整个播放器基于VideoPlayer类构建,它封装了播放器的核心逻辑和功能。其中,__init__方法初始化了播放器的各种属性和组件,包括用户界面(UI)元素、回调函数、事件队列等。

核心功能

  • 播放控制 :通过toggle_play方法实现播放与停止的切换。在播放过程中,调用init_common_sdk_param方法初始化SDK参数,设置缓冲区大小、渲染模式等,并通过SetRenderWindow将视频渲染窗口与GUI界面的画布关联起来。在停止播放时,调用StopPlay方法,并清除帧队列以确保线程安全退出。
代码语言:python
代码运行次数:0
运行
AI代码解释
复制
# SmartPlayerPythonDemo.py
# Created by daniusdk.com
# WeChat: xinsheng120
def start_playback(self):
	if not self.player_handle or not self.player_handle.value:
		self.update_status("play handle is None")
		return

	print(f"start_playback")

	self.init_common_sdk_param()

	hwnd = ctypes.c_void_p(self.canvas.winfo_id())
	print(f"Canvas hwnd: 0x{hwnd.value:x}")
	if self.smart_player_sdk_api.SetRenderWindow(self.player_handle, hwnd) != NTBaseCodeDefine.NT_ERC_OK:
		self.update_status("设置渲染窗口失败")
		return

	# 设置硬解码
	if self.hardware_decode.get():
		self.smart_player_sdk_api.SetH264HardwareDecoder(self.player_handle, 1 if self.is_support_h264_hardware_decoder else 0, 0)
		self.smart_player_sdk_api.SetH265HardwareDecoder(self.player_handle, 1 if self.is_support_h265_hardware_decoder else 0, 0)

	self.smart_player_sdk_api.SetAudioVolume(self.player_handle, int(self.volume_scale.get()))

	if self.smart_player_sdk_api.StartPlay(self.player_handle) != NTBaseCodeDefine.NT_ERC_OK:
		self.update_status("开始播放失败")
		return

	if self.is_enable_frame_callback:
		# 启动帧处理线程
		self.stop_event.clear()
		self.frame_thread = threading.Thread(target=self.process_frames, daemon=True)
		self.frame_thread.start()

	self.is_playing = True
	self.play_btn.config(text="停止")
	self.update_status("正在播放...")

def stop_playback(self):
	if not self.player_handle or not self.player_handle.value:
		return

	self.smart_player_sdk_api.StopPlay(self.player_handle)
	self.is_playing = False
	self.play_btn.config(text="播放")
	self.update_status("已停止")
  • 硬件解码 :根据设备支持情况,通过SetH264HardwareDecoderSetH265HardwareDecoder方法启用硬件解码,以提高播放性能。
代码语言:python
代码运行次数:0
运行
AI代码解释
复制
# 设置硬解码
if self.hardware_decode.get():
	self.smart_player_sdk_api.SetH264HardwareDecoder(self.player_handle, 1 if self.is_support_h264_hardware_decoder else 0, 0)
	self.smart_player_sdk_api.SetH265HardwareDecoder(self.player_handle, 1 if self.is_support_h265_hardware_decoder else 0, 0)
  • 录像功能 :通过start_recordingstop_recording方法实现录像功能。在录像前,需要配置录像参数,如文件名规则、保存目录等。
代码语言:python
代码运行次数:0
运行
AI代码解释
复制
def toggle_record(self):
	if not self.is_recording:
		self.start_recording()
	else:
		self.stop_recording()

def start_recording(self):
	if not self.player_handle or not self.player_handle.value:
		self.update_status("play handle is None")
		return

	# 确保记录配置已初始化
	if self.record_config is None:
		messagebox.showinfo("提示", "请先配置录像参数")
		self.show_record_config()  # 打开配置对话框
		return

	print(f"start_recording")

	self.init_common_sdk_param()

	# 设置录像参数
	ruler = NT_SP_RecorderFileNameRuler()
	ruler.type_ = 0
	if self.record_config is not None:
		ruler.file_name_prefix_ = self.record_config["file_prefix"].encode()
		ruler.append_date_ = 1 if self.record_config["is_append_date"] else 0
		ruler.append_time_ = 1 if self.record_config["is_append_time"] else 0

	self.smart_player_sdk_api.SetRecorderDirectoryW(
		self.player_handle,
		ctypes.c_wchar_p(self.record_config["dir_path"])
	)
	self.smart_player_sdk_api.SetRecorderFileNameRuler(self.player_handle, byref(ruler))
	self.smart_player_sdk_api.SetRecorderVideo(self.player_handle,
		c_int(1 if self.record_config["is_record_video"] else 0))
	self.smart_player_sdk_api.SetRecorderAudio(self.player_handle,
		c_int(1 if self.record_config["is_record_audio"] else 0))

	if self.smart_player_sdk_api.StartRecorder(self.player_handle) == NTBaseCodeDefine.NT_ERC_OK:
		self.is_recording = True
		self.record_btn.config(text="停止录像")
		self.update_status("录像中...")
	else:
		self.update_status("启动录像失败")

def stop_recording(self):
	if not self.player_handle or not self.player_handle.value:
		return

	print(f"stop_recording Player handle: 0x{self.player_handle.value:x}")

	self.smart_player_sdk_api.StopRecorder(self.player_handle)
	self.is_recording = False
	self.record_btn.config(text="录像")
	self.update_status("录像已停止")
  • 截图功能 :通过capture_image方法调用SDK的CaptureImage接口实现截图,并通过回调函数处理截图结果。
代码语言:python
代码运行次数:0
运行
AI代码解释
复制
def capture_image(self):
	if not self.player_handle or not self.player_handle.value:
		return

	filename = f"capture_{datetime.now().strftime('%Y%m%d%H%M%S')}.png"

	# 定义回调函数
	def capture_callback(handle, user_data, result, file_name):
		status = "成功" if result == NTBaseCodeDefine.NT_ERC_OK else "失败"
		self.capture_queue.put((result, file_name.decode('utf-8') if file_name else filename))

	# 创建回调对象并保持引用
	self.capture_image_cb = CAPTURE_IMAGE_CALLBACK(capture_callback)

	# 调用SDK接口
	ret = self.smart_player_sdk_api.CaptureImage(
		self.player_handle,
		filename.encode('utf-8'),
		None,
		self.capture_image_cb)

	if ret != NTBaseCodeDefine.NT_ERC_OK:
		self.update_status("截图请求发送失败")

实现原理与关键技术

视频播放原理

大牛直播SDK的Python下的RTMP、RTSP播放器通过调用智能播放器SDK的StartPlay方法开始播放。在播放过程中,SDK会通过回调函数向帧队列中推送视频帧数据。帧处理线程从队列中获取帧数据,并将其转换为图像格式供UI界面显示。

回调机制

  • 事件回调 :事件回调函数用于处理各种播放事件,如连接状态变化、缓冲进度更新等。通过SetEventCallBack设置事件回调函数,事件信息将被传递到主线程进行处理。
  • 视频帧回调 :视频帧回调函数用于接收视频帧数据。在回调函数中,将视频帧数据转换为字节流并存入帧队列,以供后续处理和显示。
  • 录像回调 :录像回调函数用于处理录像状态变化,如新文件生成、文件完成等。通过SetRecorderCallBack设置录像回调函数,录像信息将被传递到主线程进行处理。

UI界面设计

UI界面基于Tkinter构建,包括视频画布、控制按钮、输入框等组件。通过pack方法和grid方法对组件进行布局和定位,实现了一个简洁直观的用户界面。

优化与扩展策略

性能优化

  • 硬件加速 :充分利用硬件解码功能,提高视频解码效率。
  • 异步线程处理 :通过多线程技术异步处理视频帧数据,避免阻塞主线程,提高播放流畅度。
  • 缓冲区管理 :合理设置缓冲区大小和超时时间,以平衡播放质量和网络延迟

功能扩展

  • 添加音量调节滑块 :通过scale控件实现音量调节功能,用户可以实时调整播放音量。
  • 改进录像回调处理 :在录像回调函数中添加更多处理逻辑,如自动分割文件、上传录像文件等。
  • 支持更多视频格式 :通过扩展SDK接口或添加新的解码器,支持更多视频格式的播放。

Python播放器技术优势

1. 低延迟性

低延迟播放器通过优化数据处理和传输过程,实现了更低的延迟。这对于需要实时交互的应用场景非常重要,如监控、互动式直播、视频会议等。观众可以几乎实时地观看直播内容、参与互动,大大提升了实时性和互动性体验。

2. 高兼容性和灵活性

RTSP和RTMP协议支持多种媒体格式和编码方式,具有很强的兼容性。无论是常见的H.264、H.265视频编码格式,还是AAC、PCMA、PCMU等音频编码格式,低延迟播放器都能很好地支持,能够适应不同设备和系统的需求。

3. 支持多种网络环境

低延迟播放器能够适应不同的网络环境,包括TCPUDP传输方式。TCP保证了传输的可靠性,适用于对数据准确性要求较高的场景;UDP则具有较低的延迟和较高的传输效率,适用于对实时性要求较高的场景。此外,播放器还支持自适应调整播放策略,如在网络带宽不足时自动降低视频的分辨率或帧率,以保证视频的流畅播放。

4. 硬件加速

现代播放器通常利用硬件加速来提高播放性能。这可以通过使用专用的硬件解码器和图形加速器来实现,以加快解码和渲染过程,从而降低延迟。例如,在解码过程中,采用高效的解码算法,充分利用硬件加速功能,如GPU加速,以快速处理大量的音视频数据。

5. 高效的缓冲管理

低延迟播放器通过有效的缓存管理来减少延迟。它会使用较小的缓冲区,并采用动态缓冲策略,使缓存保持最小化,从而减少播放器响应时间。同时,支持设置缓冲时间,以应对网络抖动等不稳定情况,确保播放的流畅性。

6. 快速起播

低延迟播放器致力于实现快速的起播时间。它可以使用预加载技术,提前缓存部分音视频数据,并在用户点击播放时立即开始播放,从而缩短起播延迟。

7. 支持多实例播放

低延迟播放器支持多实例播放,适用于需要同时监控多个视频源的场景。这不仅满足了不同用户的需求,还保证了低延迟性能。

8. 功能丰富

Python下的RTMP、RTSP播放器,实际上还是调用的C接口的,所以Windows平台播放器支持的功能,Python下依然支持,完善的功能,覆盖了95%以上的使用场景。

如何实现AI视觉算法对接?

大牛直播SDK做Python下的低延迟RTMP、RTSP播放器,除了常规播放外,更多的是为了方便做Python下的视觉算法对接处理。

一、回调函数的实现

定义回调函数 在播放器的代码中,定义一个回调函数来接收YUV或RGB数据。例如:

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
def video_frame_callback(self, handle, user_data, status, frame):
    if not frame:
        return
 
    frame_data = frame.contents
    if frame_data.format_ == NT_SP_E_VIDEO_FRAME_FORMAT.NT_SP_E_VIDEO_FRAME_FORMAT_YUV420P.value:
        # 处理YUV420P数据
        yuv_data = bytes(ctypes.cast(frame_data.plane0_, ctypes.POINTER(ctypes.c_ubyte * frame_data.size_)).contents)
        self.process_yuv_frame(yuv_data, frame_data.width_, frame_data.height_)
    elif frame_data.format_ == NT_SP_E_VIDEO_FRAME_FORMAT.NT_SP_E_VIDEO_FRAME_FORMAT_RGB24.value:
        # 处理RGB24数据
        rgb_data = bytes(ctypes.cast(frame_data.plane0_, ctypes.POINTER(ctypes.c_ubyte * frame_data.size_)).contents)
        self.process_rgb_frame(rgb_data, frame_data.width_, frame_data.height_)

注册回调函数 在播放器初始化时,将回调函数注册到播放器SDK中:

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
self.frame_cb = VIDEO_FRAME_CALLBACK(self.video_frame_callback)
self.smart_player_sdk_api.SetVideoFrameCallBack(self.player_handle,
                           NT_SP_E_VIDEO_FRAME_FORMAT.NT_SP_E_VIDEO_FRAME_FORMAT_YUV420P.value,
                           None, self.frame_cb)

二、视觉算法的对接

YUV数据的处理

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
def process_yuv_frame(self, yuv_data, width, height):
    # 将YUV数据转换为numpy数组
    yuv_array = np.frombuffer(yuv_data, dtype=np.uint8).reshape((height * 3 // 2, width))
 
    # 调用视觉算法
    result = self.visual_algorithm.process_yuv(yuv_array)
 
    # 在主线程更新UI
    self.root.after(0, self.update_visual_result, result) 

RGB数据的处理

如果视觉算法需要RGB数据,可以将YUV数据转换为RGB数据,或者直接使用回调函数中的RGB数据:

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
def process_rgb_frame(self, rgb_data, width, height):
    # 将RGB数据转换为numpy数组
    rgb_array = np.frombuffer(rgb_data, dtype=np.uint8).reshape((height, width, 3))
 
    # 调用视觉算法
    result = self.visual_algorithm.process_rgb(rgb_array)
 
    # 在主线程更新UI
    self.root.after(0, self.update_visual_result, result)

视觉算法的实现

定义一个视觉算法类,包含处理YUV和RGB数据的方法:

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
class VisualAlgorithm:
    def process_yuv(self, yuv_array):
        # 在这里实现视觉算法对YUV数据的处理
        pass
 
    def process_rgb(self, rgb_array):
        # 在这里实现视觉算法对RGB数据的处理
        pass

三、在播放器中集成视觉算法

初始化视觉算法 在播放器的初始化方法中,创建视觉算法的实例:

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
def __init__(self, root):
    # 其他初始化代码
    self.visual_algorithm = VisualAlgorithm()
 

更新视觉结果 定义一个方法来在UI上更新视觉算法的结果:

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
def update_visual_result(self, result):
    # 在这里更新UI以显示视觉算法的结果
    pass

通过以上步骤,我们可以轻松将YUV或RGB数据回调与视觉算法对接,在播放器中实现视觉算法的功能。

结论

基于Python实现的RTSP/RTMP播放器具有简单易用、功能丰富、可扩展性强等特点。通过对代码结构和实现原理的深入解析,可以帮助开发者更好地理解和优化播放器,毫秒级的播放体验和解码后yuv或rgb数据回调模式,提高了实时直播场景下,Python环境下AI算法处理的效率,以上抛砖引玉,感兴趣的开发者,可以单独跟我沟通探讨。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【Android 组件化】路由组件 ( 生成 Root 类记录模块中的路由表 )
注解处理器 为每个 Module 模块生成一个路由表 , 该模块下凡是被 @Route 标注的路由节点都在该路由表中维护 ;
韩曙亮
2023/03/29
2.6K0
【Android 组件化】路由组件 ( 生成 Root 类记录模块中的路由表 )
【Android 组件化】路由组件 ( 使用 JavaPoet 生成路由表类 )
在 【Android 组件化】路由组件 ( 构造路由表中的路由信息 ) 博客中解析了注解的节点及注解属性 , 将路由信息封装在了 RouteBean 中 ;
韩曙亮
2023/03/29
6380
【Android 组件化】路由组件 ( 使用 JavaPoet 生成路由表类 )
【Android 组件化】路由组件 ( 组件间共享的服务 )
路由除了支持 Activity 之外 , 还要支持 组件间共享的服务 如 工具类 , 逻辑功能 等 ;
韩曙亮
2023/03/29
8860
【Android 组件化】路由组件 ( 组件间共享的服务 )
【Android 组件化】路由组件 ( 运行时获取 注解处理器 生成的路由表 )
最后 , 考虑 instant run 的情况 , 可能存在多个 APK 文件 , 如果有多个 , 也一并放入路径字符串集合中 ;
韩曙亮
2023/03/29
4100
【Android 组件化】路由组件 ( 构造路由表中的路由信息 )
在【Android 组件化】路由组件 ( 注解处理器参数选项设置 ) 博客中在注解处理器中 , 获取了在 build.gradle 中设置的参数 ;
韩曙亮
2023/03/29
5870
【Android 组件化】路由组件 ( 构造路由表中的路由信息 )
【Android 组件化】路由组件 ( 路由组件结构 )
在之前博客 【Android 组件化】使用 Gradle 实现组件化 ( 组件 / 集成模式下的 Library Module 开发 ) 的组件化项目中 , 可能涉及到跨 Module 的调用 , 如在 library1 模块中打开 library2 模块中的 Activity 界面 , 或调用其它 Module 中的功能 ;
韩曙亮
2023/03/29
4650
【Android 组件化】路由组件 ( 路由组件结构 )
【Android 组件化】路由组件 ( 注解处理器获取被注解的节点 )
在 【Android 组件化】路由组件 ( 路由组件结构 ) 博客中介绍了组件化中的 " 路由组件 " , 分为 " 自定义注解模块 " , " 注解处理器模块 " , " 依赖库模块 " 3 个模块 ;
韩曙亮
2023/03/29
3830
【Android 组件化】路由组件 ( 注解处理器获取被注解的节点 )
【Android 组件化】使用 ARoute 实现组件化 ( ARoute 初始化 及 界面跳转 源码分析 )
引入了 ARoute 的应用 , 一般会在主应用的 Application 中的 onCreate 方法中初始化 ARoute ;
韩曙亮
2023/03/29
1.2K0
【Android 组件化】使用 ARoute 实现组件化 ( ARoute 初始化 及 界面跳转 源码分析 )
Android组件化专题 - 路由框架原理
在路由框架之前,我们先了解什么是APT,并实践ButterKnife绑定findById的小功能。为什么先要讲解apt,因为路由的实现apt是核心的代码.看下面链接 APT 实践。
用户3045442
2018/09/11
1.7K0
Android组件化专题 - 路由框架原理
【Android 组件化】使用 ARoute 实现组件化 ( 完整组件化项目框架 )
使用 ARouter 第三方库实现组件化 : https://github.com/alibaba/ARouter
韩曙亮
2023/03/29
2.5K0
【Android 组件化】使用 ARoute 实现组件化 ( 完整组件化项目框架 )
【Android 组件化】路由组件 ( 注解处理器中使用 JavaPoet 生成代码 )
在 【Android 组件化】路由组件 ( 注解处理器获取被注解的节点 ) 博客中 声明了 支持的注解类型 , 并在 Activity 中使用了注解 , 在 注解处理器 中检测出来使用注解的 类节点 TypeElement ;
韩曙亮
2023/03/29
5040
【Android 组件化】路由组件 ( 注解处理器中使用 JavaPoet 生成代码 )
【Android 组件化】路由组件 ( 注解处理器参数选项设置 )
在 【Android 组件化】路由组件 ( 注解处理器中使用 JavaPoet 生成代码 ) 博客中在注解处理器中 , 简单的使用了 JavaPoet 生成了 Java 代码 ;
韩曙亮
2023/03/29
3440
【Android 组件化】路由组件 ( 注解处理器参数选项设置 )
APP路由框架与组件化简析
前端开发经常遇到一个词:路由,在Android APP开发中,路由还经常和组件化开发强关联在一起,那么到底什么是路由,一个路由框架到底应该具备什么功能,实现原理是什么样的?路由是否是APP的强需求呢?与组件化到底什么关系,本文就简单分析下如上几个问题。
看书的小蜗牛
2021/06/21
8490
APP路由框架与组件化简析
【Android 组件化】路由组件 ( 页面跳转参数依赖注入 )
在 组件化 中 , 使用 路由组件 进行界面跳转时 , 涉及到参数的传递 , 传递过去的参数需要在目的地 Activity 的 onCreate 方法中 , 调用 getIntent().getXxxExtra() 获取到传递的值 ;
韩曙亮
2023/03/29
9150
“终于懂了” 系列:组件化框架 ARouter 完全解析(一) 原理详解
在我之前的组件化文章《“终于懂了” 系列:Android组件化,全面掌握!》中,提到为了实现组件化要解决的几个问题点,其中 页面跳转、组件间通信 的问题是使用了 ARouter 这个框架来解决的。ARouter确实是专门用于做组件化改造,官方是这么介绍的:
胡飞洋
2022/11/08
3.3K0
“终于懂了” 系列:组件化框架 ARouter 完全解析(一) 原理详解
“终于懂了” 系列:组件化框架 ARouter 完全解析(二)APT技术
在上一篇《“终于懂了” 系列:组件化框架 ARouter 完全解析(一) 原理详解》中,详细介绍了ARouter的核心原理。其中提到了“帮助类”的概念,也就是在运行时生成 用于帮助填充WareHouse路由元信息的类,这里就涉及到了APT技术。那么本篇就对这一技术点进行介绍,并详细分析ARouter中是如何使用APT来生成帮助类的。
胡飞洋
2022/11/08
1.8K0
“终于懂了” 系列:组件化框架 ARouter 完全解析(二)APT技术
【Android 组件化】使用 Gradle 实现组件化 ( 组件 / 集成模式下的 Library Module 开发 )
在 1 个 Android 应用中只能存在 1 个 Application 类 , 但是组件化开发时 , 如果 Library 模块动态修改成 Application 模块 , 还想自己定义一个 Application 类 , 这里参考上一篇博客 【Android 组件化】使用 Gradle 实现组件化 ( 组件模式与集成模式切换 ) 三、使用 sourceSets 配置组件模式下使用的清单文件 章节 , 使用 sourceSets 资源配置 , 配置 Java 代码 ;
韩曙亮
2023/03/29
7620
【Android 组件化】使用 Gradle 实现组件化 ( 组件 / 集成模式下的 Library Module 开发 )
Android 组件化 —— 路由设计最佳实践
Android原生已经支持AndroidManifest去管理App跳转,为什么要有路由库,这可能是大部分人接触到Android各种Router库不太明白的地方,这里我讲一下我的理解
Anymarvel
2018/10/22
1.7K0
Android 组件化 —— 路由设计最佳实践
Android项目解耦--路由框架ARouter源码解析
上一篇文章Android项目解耦--路由框架ARouter的使用讲述了ARouter在项目中的使用,这边文章主要对ARouter的源码进行学习和分析。
静默加载
2020/05/29
1.1K0
Android 组件化(二)注解与注解处理器、组件通讯
  在上一篇文章中,我们完成了组件的创建、gradle统一管理、组件模式管理和切换,那么这一篇文章,我们需要做的就是组件之间的通讯了。
晨曦_LLW
2022/11/21
6950
Android 组件化(二)注解与注解处理器、组件通讯
推荐阅读
【Android 组件化】路由组件 ( 生成 Root 类记录模块中的路由表 )
2.6K0
【Android 组件化】路由组件 ( 使用 JavaPoet 生成路由表类 )
6380
【Android 组件化】路由组件 ( 组件间共享的服务 )
8860
【Android 组件化】路由组件 ( 运行时获取 注解处理器 生成的路由表 )
4100
【Android 组件化】路由组件 ( 构造路由表中的路由信息 )
5870
【Android 组件化】路由组件 ( 路由组件结构 )
4650
【Android 组件化】路由组件 ( 注解处理器获取被注解的节点 )
3830
【Android 组件化】使用 ARoute 实现组件化 ( ARoute 初始化 及 界面跳转 源码分析 )
1.2K0
Android组件化专题 - 路由框架原理
1.7K0
【Android 组件化】使用 ARoute 实现组件化 ( 完整组件化项目框架 )
2.5K0
【Android 组件化】路由组件 ( 注解处理器中使用 JavaPoet 生成代码 )
5040
【Android 组件化】路由组件 ( 注解处理器参数选项设置 )
3440
APP路由框架与组件化简析
8490
【Android 组件化】路由组件 ( 页面跳转参数依赖注入 )
9150
“终于懂了” 系列:组件化框架 ARouter 完全解析(一) 原理详解
3.3K0
“终于懂了” 系列:组件化框架 ARouter 完全解析(二)APT技术
1.8K0
【Android 组件化】使用 Gradle 实现组件化 ( 组件 / 集成模式下的 Library Module 开发 )
7620
Android 组件化 —— 路由设计最佳实践
1.7K0
Android项目解耦--路由框架ARouter源码解析
1.1K0
Android 组件化(二)注解与注解处理器、组件通讯
6950
相关推荐
【Android 组件化】路由组件 ( 生成 Root 类记录模块中的路由表 )
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验