<?xml version="1.0" encoding="utf-8" ?><rss version="2.0"><channel><title><![CDATA[hunter800421的专栏]]></title><description><![CDATA[]]></description><link>https://blog.youkuaiyun.com/foolish0421</link><language>zh-cn</language><generator>https://blog.youkuaiyun.com/</generator><copyright><![CDATA[Copyright &copy; foolish0421]]></copyright><item><title><![CDATA[Android Unit Test]]></title><link>https://blog.youkuaiyun.com/foolish0421/article/details/131992917</link><guid>https://blog.youkuaiyun.com/foolish0421/article/details/131992917</guid><author>foolish0421</author><pubDate>Sat, 29 Jul 2023 11:30:33 +0800</pubDate><description><![CDATA[测试金字塔（如图 2 所示）说明了应用应如何包含三类测试（即小型、中型和大型测试）：小型测试是指单元测试，用于验证应用的行为，一次验证一个类。中型测试是指集成测试，用于验证模块内堆栈级别之间的互动或相关模块之间的互动。大型测试是指端到端测试，用于验证跨越了应用的多个模块的用户操作流程。沿着金字塔逐级向上，从小型测试到大型测试，各类测试的保真度逐级提高，但维护和调试工作所需的执行时间和工作量也逐级增加。因此，您编写的单元测试应多于集成测试，集成测试应多于端到端测试。。]]></description><category></category></item><item><title><![CDATA[客户端日志打印规范]]></title><link>https://blog.youkuaiyun.com/foolish0421/article/details/126313479</link><guid>https://blog.youkuaiyun.com/foolish0421/article/details/126313479</guid><author>foolish0421</author><pubDate>Sat, 13 Aug 2022 01:46:04 +0800</pubDate><description><![CDATA[/ 正例：重写toString()方法，将实体类转换为JSON字符串@Override}]]></description><category></category></item><item><title><![CDATA[iOS播放/渲染/解析MIDI]]></title><link>https://blog.youkuaiyun.com/foolish0421/article/details/124850263</link><guid>https://blog.youkuaiyun.com/foolish0421/article/details/124850263</guid><author>foolish0421</author><pubDate>Thu, 19 May 2022 12:30:53 +0800</pubDate><description><![CDATA[什么是MIDI
MIDI：乐器数字接口, Musical Instrument Digital Interface。
MIDI 是计算机能理解的乐谱，计算机和电子乐器都可以处理的乐器格式。
MIDI 不是音频信号，不包含 pcm buffer。
通过音序器 sequencer，结合音频数据 / 乐器 ，播放 MIDI Event 数据
（ 通过音色库 SoundFont，播放乐器的声音。iOS上一般称sound bank ）。
通过 AVAudioEngine/AVAudioSequencer 播放
连接 ]]></description><category></category></item><item><title><![CDATA[【Android】AudioRecord::getMinBufferSize源码分析]]></title><link>https://blog.youkuaiyun.com/foolish0421/article/details/124631478</link><guid>https://blog.youkuaiyun.com/foolish0421/article/details/124631478</guid><author>foolish0421</author><pubDate>Sat, 07 May 2022 17:05:43 +0800</pubDate><description><![CDATA[Android，音频，AudioRecord]]></description><category></category></item><item><title><![CDATA[sqlite锁机制和greenDAQ多线程]]></title><link>https://blog.youkuaiyun.com/foolish0421/article/details/106319066</link><guid>https://blog.youkuaiyun.com/foolish0421/article/details/106319066</guid><author>foolish0421</author><pubDate>Sun, 24 May 2020 18:52:53 +0800</pubDate><description><![CDATA[锁
Android和iOS都是采用的sqlite作为默认数据库。在有并发业务的场景下，数据库需要提供锁机制来保证数据一致。sqlite3提供了五种级别的锁：未加锁(UNLOCKED)、共享 (SHARED)、保留 (RESERVED)、未 决(PENDING) 和排它(EXCLUSIVE)。SQLite 使用锁逐步上升机制，为了写数据库，连接需要逐级地获得排它锁，以最大限度的保证并发性。
事务
事务是与锁紧密关联的概念。SQLite有三种不同的事务，DEFERRED、 MMEDIATE和EXCLUSIVE，]]></description><category></category></item><item><title><![CDATA[XMPP的优点和不足]]></title><link>https://blog.youkuaiyun.com/foolish0421/article/details/105747489</link><guid>https://blog.youkuaiyun.com/foolish0421/article/details/105747489</guid><author>foolish0421</author><pubDate>Sat, 25 Apr 2020 11:59:42 +0800</pubDate><description><![CDATA[XMPP概览
3月份刚换了工作，入职之后新东家让我负责IM SDK的维护和重构工作。想起8年前曾经也搞过一段时间IM，当时是基于XMPP协议做的二次开发。时间又过了将近十年，时代在发展，技术在进步，如今可以考虑重新研究一下xmpp协议，毕竟这是唯一开源的IM协议，它山之石可以攻玉。

XMPP的特点
闲言少叙，书归正传，我们先来看看xmpp的一些基本特点。
xmpp官方对xmpp的定义是：“XMP...]]></description><category></category></item><item><title><![CDATA[基于kafka和prometheus的无线APM报警系统设计和实现]]></title><link>https://blog.youkuaiyun.com/foolish0421/article/details/102970362</link><guid>https://blog.youkuaiyun.com/foolish0421/article/details/102970362</guid><author>foolish0421</author><pubDate>Fri, 08 Nov 2019 11:43:36 +0800</pubDate><description><![CDATA[基于kafka和prometheus的无线APM报警系统设计和实现
移动APP是当下的主流。公司有很多业务线，有大量的APP。为了能够实现对这些APP性能的监控，为无线开发、测试人员提供性能诊断和分析工具，公司自行开发了无线APM系统。
我们的APM系统设计是这样的
![avatar][apmbase64]
无线APM系统通过移动端的SDK收集性能数据并上报到无线服务后端。各业务方可以通过无线控制...]]></description><category></category></item><item><title><![CDATA[argus-apm-main中的task(2) —— Activity Task]]></title><link>https://blog.youkuaiyun.com/foolish0421/article/details/87381771</link><guid>https://blog.youkuaiyun.com/foolish0421/article/details/87381771</guid><author>foolish0421</author><pubDate>Fri, 15 Feb 2019 19:31:38 +0800</pubDate><description><![CDATA[argus-apm-main中的task(2) —— Activity Task
Activity Task实现对Activity的性能监控。我们在“开始”一篇里提到过，Activity的性能采集实现方式有两种，Instrumentation和AOP，而ActivitTask的start方法主要就做了一个判断：如果使能了ApmTask.FLAG_COLLECT_ACTIVITY_INSTRUMEN...]]></description><category></category></item><item><title><![CDATA[argus-apm-main中的task(1) —— FpsTask]]></title><link>https://blog.youkuaiyun.com/foolish0421/article/details/87351946</link><guid>https://blog.youkuaiyun.com/foolish0421/article/details/87351946</guid><author>foolish0421</author><pubDate>Fri, 15 Feb 2019 12:08:30 +0800</pubDate><description><![CDATA[argus-apm-main中的task(1) —— FpsTask
argus-apm-main中定义和实现了各个具体的监控task，包括Activity，网络，fps等等。这里我们先从fps作为例子入手分析。
FpsTask类
FpsTask类定义了fps监控的task，相当于是fps task的入口。先来看一下这个类的代码。
public class FpsTask extends Base...]]></description><category></category></item><item><title><![CDATA[360 Argus APM 源码分析（4）—— argus-apm-okhttp源码分析]]></title><link>https://blog.youkuaiyun.com/foolish0421/article/details/87295477</link><guid>https://blog.youkuaiyun.com/foolish0421/article/details/87295477</guid><author>foolish0421</author><pubDate>Thu, 14 Feb 2019 20:15:46 +0800</pubDate><description><![CDATA[argus-apm-okhttp源码分析

OkHttp3Aspect类
OkHttp3Aspect类是OKHTTP3的切面文件。

@Aspect
public class OkHttp3Aspect {

    @Pointcut(&quot;call(public okhttp3.OkHttpClient build())&quot;)
    public void build() {

    }

  ...]]></description><category></category></item><item><title><![CDATA[360 Argus APM 源码分析（3）—— argus-apm-aop源码分析]]></title><link>https://blog.youkuaiyun.com/foolish0421/article/details/87205938</link><guid>https://blog.youkuaiyun.com/foolish0421/article/details/87205938</guid><author>foolish0421</author><pubDate>Wed, 13 Feb 2019 20:39:06 +0800</pubDate><description><![CDATA[argus-apm-aop源码分析
argus-apm-aop主要实现了面向Activity的切面和面向HttpClient和URLConnection的切片。阅读代码需要有AOP和aspectj的基础知识。

TraceActivity
TraceActivity类实现对Activity（还有Application）的切面。

@Aspect
public class TraceActivity...]]></description><category></category></item><item><title><![CDATA[Android多媒体框架（7）—— stagefright中MediaMuxer源码分析]]></title><link>https://blog.youkuaiyun.com/foolish0421/article/details/86775364</link><guid>https://blog.youkuaiyun.com/foolish0421/article/details/86775364</guid><author>foolish0421</author><pubDate>Fri, 08 Feb 2019 15:33:35 +0800</pubDate><description><![CDATA[stagefright中MediaMuxer源码分析

私有属性定义
MediaMuxer.h中定义了一些类的属性：

const OutputFormat mFormat;
    sp&amp;amp;lt;MediaWriter&amp;amp;gt; mWriter;
    Vector&amp;amp;lt; sp&amp;amp;lt;MediaAdapter&amp;amp;gt; &amp;amp;gt; mTrackList;  // Each track has its...]]></description><category></category></item><item><title><![CDATA[Android多媒体框架（6）—— MediaMuxer的jni代码分析]]></title><link>https://blog.youkuaiyun.com/foolish0421/article/details/86775062</link><guid>https://blog.youkuaiyun.com/foolish0421/article/details/86775062</guid><author>foolish0421</author><pubDate>Fri, 08 Feb 2019 14:25:55 +0800</pubDate><description><![CDATA[MediaMuxer的jni代码分析
jni方法的定义
MediaMuxer jni方法的定义在frameworks/base/media/jni/android_media_MediaMuxer.cpp中。
static const JNINativeMethod gMethods[] = {

    { &amp;quot;nativeAddTrack&amp;quot;, &amp;quot;(J[Ljava/lang/String;[Lja...]]></description><category></category></item><item><title><![CDATA[Android多媒体框架（5）—— MediaMuxer.jara源码分析]]></title><link>https://blog.youkuaiyun.com/foolish0421/article/details/86772321</link><guid>https://blog.youkuaiyun.com/foolish0421/article/details/86772321</guid><author>foolish0421</author><pubDate>Thu, 07 Feb 2019 17:38:42 +0800</pubDate><description><![CDATA[MediaMuxer.jara源码分析
音视频通过Codec（编码器）编码之后，还需要经过MediaMuxer（混合器）“混合”。混合器在framework的实现就是MediaMuxer类。MediaMuxer中又个内部类OutputFormat：
public static final class OutputFormat {
80        /* Do not change these v...]]></description><category></category></item><item><title><![CDATA[Android多媒体框架（4）—— AMessage，AHandler和ALooper源码分析]]></title><link>https://blog.youkuaiyun.com/foolish0421/article/details/86763119</link><guid>https://blog.youkuaiyun.com/foolish0421/article/details/86763119</guid><author>foolish0421</author><pubDate>Mon, 04 Feb 2019 13:59:09 +0800</pubDate><description><![CDATA[AMessage源码分析
AMessage继承自RefBase类,它有AHandler和ALooper的成员mHandler和mLooper，并且ALooper还是它的友元。成员变量mWhat是消息id，成员变量mTarget指明消息的handler（只用于调试）。成员函数setWhat和setTarget分别设置这两个属性。
void AMessage::setWhat(uint32_t wha...]]></description><category></category></item><item><title><![CDATA[Android多媒体框架（3）—— libstagefright中MediaCodec源码分析]]></title><link>https://blog.youkuaiyun.com/foolish0421/article/details/86759605</link><guid>https://blog.youkuaiyun.com/foolish0421/article/details/86759605</guid><author>foolish0421</author><pubDate>Sun, 03 Feb 2019 15:26:48 +0800</pubDate><description><![CDATA[libstagefright中MediaCodec源码分析
和前两篇一样，我们按照MediaCodec的各个状态来分析libstagefright中MediaCodec的源代码。

configure
首先我们看一下configure在libstagefright中MediaCodec中的定义：


438status_t MediaCodec::configure(
439        con...]]></description><category></category></item><item><title><![CDATA[Android 多媒体框架（2）—— android_media_MediaCodec.cpp源码分析]]></title><link>https://blog.youkuaiyun.com/foolish0421/article/details/86720019</link><guid>https://blog.youkuaiyun.com/foolish0421/article/details/86720019</guid><author>foolish0421</author><pubDate>Thu, 31 Jan 2019 18:05:58 +0800</pubDate><description><![CDATA[android_media_MediaCodec.cpp源码分析
这里我们来分析和MediaCodec.java对应的native层类：android_media_MediaCodec.cpp的源代码。
在该类的最后，我们会看到这样的代码：
static const JNINativeMethod gMethods[] = {
1881    { &quot;native_release&quot;, &quot;()V&quot;, ...]]></description><category></category></item><item><title><![CDATA[360 Argus APM 源码分析（2）—— argus-apm-gradle源码分析]]></title><link>https://blog.youkuaiyun.com/foolish0421/article/details/86633030</link><guid>https://blog.youkuaiyun.com/foolish0421/article/details/86633030</guid><author>foolish0421</author><pubDate>Thu, 24 Jan 2019 20:48:21 +0800</pubDate><description><![CDATA[argus-apm-gradle源码分析
argus-apm-gradle工程定义了一个gradle plugin，主要有以下两个作用：

支持AOP编程，方便ArgusAPM能够在编译期织入一些性能采集的代码；
通过Gradle插件来管理依赖库，使用户接入ArgusAPM更简单。

argus-apm-gradle使用kotlin语言开发。这里我们假定大家已经熟悉gradle plugin的开发...]]></description><category></category></item><item><title><![CDATA[360 apm框架Argus源码解析（1）——开始]]></title><link>https://blog.youkuaiyun.com/foolish0421/article/details/86616915</link><guid>https://blog.youkuaiyun.com/foolish0421/article/details/86616915</guid><author>foolish0421</author><pubDate>Wed, 23 Jan 2019 20:15:20 +0800</pubDate><description><![CDATA[开始
先看一个简单的代码示例，演示如何集成360 Argus APM：
public class ArgusAPMApplication extends Application {
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
   ...]]></description><category></category></item><item><title><![CDATA[Android多媒体框架（1）——MediaCodec.java源代码分析]]></title><link>https://blog.youkuaiyun.com/foolish0421/article/details/86379035</link><guid>https://blog.youkuaiyun.com/foolish0421/article/details/86379035</guid><author>foolish0421</author><pubDate>Sat, 12 Jan 2019 22:02:22 +0800</pubDate><description><![CDATA[概述
MediaCodec勇于访问底层的编解码器，是Android底层多媒体支持框架的一部分。它可以操作三种数据：压缩后的，原始的音频数据，以及原始的视频数据。
MediaCodec以异步的方式处理数据，会用到一组输入和输出缓冲区，后文会详细介绍。MediaCodec有内部类BufferInfo来描述缓冲区。
BufferInfo的代码如下：
public final static class B...]]></description><category></category></item></channel></rss>