惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

A
About on SuperTechFans
D
DataBreaches.Net
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
V
Visual Studio Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
B
Blog RSS Feed
Recent Announcements
Recent Announcements
The Register - Security
The Register - Security
S
Secure Thoughts
Y
Y Combinator Blog
The Last Watchdog
The Last Watchdog
L
LINUX DO - 最新话题
V2EX - 技术
V2EX - 技术
腾讯CDC
GbyAI
GbyAI
G
Google Developers Blog
博客园 - 司徒正美
博客园 - 三生石上(FineUI控件)
T
The Exploit Database - CXSecurity.com
T
Threat Research - Cisco Blogs
P
Proofpoint News Feed
Schneier on Security
Schneier on Security
Microsoft Security Blog
Microsoft Security Blog
Jina AI
Jina AI
WordPress大学
WordPress大学
aimingoo的专栏
aimingoo的专栏
MyScale Blog
MyScale Blog
Help Net Security
Help Net Security
K
Kaspersky official blog
P
Privacy & Cybersecurity Law Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
AI
AI
MongoDB | Blog
MongoDB | Blog
Scott Helme
Scott Helme
J
Java Code Geeks
Engineering at Meta
Engineering at Meta
H
Heimdal Security Blog
H
Help Net Security
D
Darknet – Hacking Tools, Hacker News & Cyber Security
云风的 BLOG
云风的 BLOG
Microsoft Azure Blog
Microsoft Azure Blog
S
Security Affairs
TaoSecurity Blog
TaoSecurity Blog
The GitHub Blog
The GitHub Blog
Hacker News: Ask HN
Hacker News: Ask HN
Martin Fowler
Martin Fowler
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Project Zero
Project Zero
T
The Blog of Author Tim Ferriss
Last Week in AI
Last Week in AI

音视频开发进阶

音视频教程-第三节 音视频教程-第二节 真的,AI 可能就是新时代的信息差 充值 Cursor 之后,工作有了哪些变化?🤔 个人'蒸馏'大模型能做哪些有意思的事情 DeepSeek 大模型在 Mac 上的部署和运行 音视频教程-第一节 【WebRTC 专栏】-- Android 开发集成 WebRTC 库的几种方式 【WebRTC 专栏】-- 在 Mac M1 等系列芯片编译和开发 WebRTC-Android 库 Meta Llama3 大模型在 Mac 上的部署和运行 iOS VideoToolBox 解码 HEVC Open-GOP 视频的问题排查 Flutter 状态管理之 InheritedWidget 使用和分析 用 ChatGPT 回答技术问题怎么样 ? 音视频开发系统入门大致路线 UE 4.27 添加自定义 ShadingModel 用 UE4 虚幻引擎做个捏脸小功能~~ UE4 材质练习 之 凹凸贴图偏移的使用 UE4 材质练习系列基础 OpenGL上下文创建以及共享机制 007 | 播放器系列专栏-解析 MP4 文件读取信息 006 | 播放器系列专栏-在 Mac 上查看 MP4 格式信息 干货 | 快速抽取缩略图是怎么练成的? 关于直播、WebRTC、FFmpeg 的那些事 005 | 播放器系列专栏-在 Windows 上查看 MP4 格式信息 将音视频中的花屏、绿屏、黑屏问题一网打尽 关于音视频里面的解码帧率和渲染帧率 004 | 播放器系列专栏-认识MP4视频(下) 003 | 播放器系列专栏-认识MP4视频(上) 入门或者转行音视频,应该要怎么做? H264视频文件如何缩放分辨率 002 | 播放器系列专栏-FFmpeg依赖库的配置 001 | 播放器系列专栏-关于播放器项目的一个小实践 Seek策略以及在有B帧情况下的处理 目前流媒体开发工程师工作内容主要是什么? 一个音视频领域专业问答的小圈子 干货收藏 || Vulkan Game Engine 视频教程 音视频春节假期内卷指南(实操) Vulkan 在 FFmpeg 中的支持 Windows 下 FFmpeg 和 LibX264 的编译和配置 Metal 开发 | 使用 C++ 进行接口调用 音视频开发工作经验分享 || 视频版 FFmpeg 调用 MediaCodec 硬解码到 Surface 上 代码吸猫 | 用 OpenGL 图像渲染的养猫计划 百倍变速--解码到底能不能丢 非参考帧 ?FFmpeg 有话说!!! 老生常谈-FFmpeg 的编译问题轻松搞定 FFmpeg 调用 Android MediaCodec 进行硬解码(附源码) 【WebRTC 专栏】--创建相机预览 Unity Shader 光照基础之 Half Lambert 光照模型 Unity Shader 光照基础之Lambert光照模型 Unity Shader 光照基础内容 Unity Shader 显示一张图片纹理 UnityShader 的基本概念 Unity 物体的基本操作 C++ 模板系列小结07-尾置返回类型 C++ 模板系列小结06-可变参数模板特性 C++ 中的多线程的使用和线程池建设 C++ 模板系列小结05-模板类型作为模板参数 C++ 模板系列小结04-类模板中的成员模板 C++ 模板系列小结03-在模板中指定变量类型 C++ 模板系列小结02-非类型模板参数 C++ 模板系列小结01-函数模板和类模板 从零打造渲染引擎系列01-什么是渲染引擎 iOS开发 - 在 Swift 中去调用 C/C++ 代码 2021 技术新番 - 从零打造渲染引擎系列 iOS 音视频开发的一些基础准备工作 音视频交流群又来啦~~~ 【WebRTC 专栏】WebRTC & Android 开发学习环境搭建~ 【喜大普奔】域名终于备案通过啦 Shader 优化 | OpenGL 绘制网格效果 【音视频连载-011】第二季 FFmpeg 一层一层获取文件信息 KodeLife | Shader 实时编辑预览的强大工具使用实践 推荐几个堪称教科书级别的 Android 音视频入门项目 【音视频连载-010】第二季 FFmpeg 日志打印 【音视频连载-008】基础学习篇-SDL 播放 PCM 音频文件(下) 【音视频连载-007】基础学习篇-SDL 播放 PCM 音频文件(上) 【音视频连载-006】基础学习篇-SDL 播放 YUV 视频文件 【音视频连载-005】基础学习篇-SDL 加载 YUV 文件并显示 【音视频连载-004】基础学习篇-SDL 加载图片并显示 【音视频连载-003】基础学习篇-SDL 消息循环和事件响应 【音视频连载-002】基础学习篇-SDL 创建窗口并显示颜色 【音视频连载-001】基础学习篇- SDL 介绍以及工程配置 LearnOpenGL 源码在 MAC 上的编译与调试 2019 年终总结与回顾 Android NDK 开发的免费技术视频来啦~~ OpenGL 实现视频编辑中的转场效果 OpenGL 实践之贝塞尔曲线绘制 图像库 libjpeg-turbo 编译与实践 图像库 libpng 编译与实践 rust 开发编译 Android 动态库实践 Android NDK 开发 —— 从 Assets 文件夹加载图片并上传纹理 简单易用的图像解码库介绍 —— stb_image 博客图床迁移记 进击的 Vulkan 移动开发之 SwapChain 进击的 Vulkan 移动开发之 Command Buffer 进击的 Vulkan 移动开发之 Instance & Device & Queue 进击的 Vulkan 移动开发(一)之今生前世 Java 显式锁 Lock 与条件队列 C++ 标准容器库小结 一文读懂 YUV 的采样与格式 《OpenGL ES 3.x 游戏开发》碰撞检测之 AABB 包围盒
用 Rxjava 封装 Dialog 以及 RxBinding 实现简要分析
音视频开发进阶 · 2017-12-22 · via 音视频开发进阶

一个专注音视频领域的小圈子

之前有写过一篇文章:用 RxJava 封装回调方法 CallBack。 RxJava 封装回调方法的大体思路就是:使用 Observable 的 create 方法来返回一个 Observable,在 create 方法内给事物设置回调接口,用 Observable 的 onNext 方法来接受回调接口所产生的内容。 这样一来,通过 onNext 方法就把事物的回调方法转换到 Rxjava 对应的事件流里面了,再可以通过其他操作符,如 Map、FlatMap 等对事件流进行相应的转换。 下来展示具体代码的操作,用的是 RxJava 2.x 的版本:

 private Observable<Integer> handleRxJavaDialog() {
        return Observable.create(emitter -> {
            final AlertDialog dialog = new AlertDialog.Builder(mContext)
                    .setMessage("RxJava封装Dialog事件流")
                    .setNegativeButton("取消", (dialog12, which) -> emitter.onNext(which)) 
                    .setPositiveButton("确认", (dialog1, which) -> emitter.onComplete())
                    .create();
            dialog.show();
            // 当被取消订阅,unsubscribed 时调用的方法
            emitter.setCancellable(() -> {
                if (dialog.isShowing()) {
                    dialog.dismiss();
                }
            });
        });
    }

如此封装之后,直接通过 RxJava 的 onNext 方法将事件封装到 RxJava 事件流里面去。

弄到这,想起了一个开源的 RxJava 系列框架:RxBinding,和本文的封装有相同之处。

RxBinding 是用来处理控件异步调用的一个框架,它也已经更新到了 RxJava 2.x 的版本。

在它的源码里对许多控件都进行了封装,可以看到如:RxViewRxTextViewRxSeekBarRxProgressBarRxPopupMenu等等。

它们的使用也是大同小异,比如要对一个 View 封装其点击事件,就可以这样写:

  RxView.clicks(mBtn)
		.subscribe(new Consumer<Object>() {
            @Override
            public void accept(@NonNull Object o) throws Exception {
                Timber.d("RxView");
            }
        });

在代码的前半部分RxView.clicks(mBtn)返回的正好是一个 Observable 对象,然后就可以像平时使用 RxJava 一样添加各种操作符,最后通过 subscribe 进行订阅了。

在 RxView.clicks 的源码中,最后返回的是一个 ViewClickObservable,从名字可见,这个 Observable 专门是用来处理点击事件的,在 RxBinding 中还有很多专门处理其他事件的 Observable,例如:ViewDragObservableViewLongClickObservableViewScrollChangeEventObservable等等,他们的实现方法也都大同小异了。

  @CheckResult @NonNull
  public static Observable<Object> clicks(@NonNull View view) {
    checkNotNull(view, "view == null");
    return new ViewClickObservable(view);
  }

在专门处理各种事件的 Observable 类中,都会有一个实现 Disposable接口和具体事件所对应的接口的 Listener 类,而这个 Listener 类的作用,就是给我们所需要的 View 设置对应事件回调接口的,并且在回调接口中调用 Observable 的 onNext 方法来将事件转换到 RxJava 的事件流中。

	ViewClickObservable(View view) {
    this.view = view;
	}

  @Override protected void subscribeActual(Observer<? super Object> observer) {
    if (!checkMainThread(observer)) {
      return;
    }
    Listener listener = new Listener(view, observer);
	// onSubscribe 设置了 Disposable 接口,当取消订阅时该执行的操作。
    observer.onSubscribe(listener);
    view.setOnClickListener(listener);
  }
// ViewClickObservable 的 Listener 类实现了 OnClickListener 接口
  static final class Listener extends MainThreadDisposable implements OnClickListener {
    private final View view;
    private final Observer<? super Object> observer;

    Listener(View view, Observer<? super Object> observer) {
      this.view = view;
      this.observer = observer;
    }
	// 在 onClick 方法内,调用 onNext 方法,将 onClick 的事件转移到了 RxJava 的事件流里面去了
    @Override public void onClick(View v) {
      if (!isDisposed()) {
        observer.onNext(Notification.INSTANCE);
      }
    }
    // 当被取消订阅时,就设置接口为 null.
    @Override protected void onDispose() {
      view.setOnClickListener(null);
    }
  }

而在开始订阅时,就调用subscribeActual方法来给 View 设置回调接口以便转换事件流。并且还设置了Disposable以便响应当结束订阅时的操作。

这一逻辑和本文上半部分将的有相同之处,核心都是用 onNext 方法转换事件流。

而 RxBinding 则封装的更多了,没有在 create 方法里面进行操作, 而是针对 View 控件不同的事件来生成对应的 Observable 对象,对象里面持有 View 控件的实例,并且也完成了给 View 控件设置回调接口以及取消订阅时的方法。

但毫无疑问,针对 View 控件的事件来生成 Observable 会使得代码的兼容性更强了吧,毕竟大多数控件都有公共事件,而只需要针对这个功能事件写一遍代码就行了,不需要针对每个控件来实现一套代码了。

总结经验,写代码时还是要多想想,谋定而后动!!!

参考

1、http://adelnizamutdinov.github.io/blog/2014/11/23/advanced-rxjava-on-android-popupmenus-and-dialogs/

原创文章,转载请注明来源:    用 Rxjava 封装 Dialog 以及 RxBinding 实现简要分析