MediaPlayer音频与视频的播放介绍

作者:向阳逐梦

Android多媒体中的——MediaPlayer,我们可以通过这个API来播放音频和视频该类是Androd多媒体框架中的一个重要组件,通过该类,我们可以以最小的步骤来获取,解码和播放音视频。

它支持三种不同的媒体来源:

  • 本地资源
  • 内部的URI,比如你可以通过ContentResolver来获取
  • 外部URL(流)对于Android所支持的的媒体格式列表

1.相关方法详解

1)获得MediaPlayer实例:

可以直接new或者调用create方法创建:

MediaPlayer mp = new MediaPlayer();
MediaPlayer mp = MediaPlayer.create(this, R.raw.test);  //无需再调用setDataSource` </pre>

另外create还有这样的形式:create(Context context, Uri uri, SurfaceHolder holder) 通过Uri和指定 SurfaceHolder 【抽象类】 创建一个多媒体播放器。

2)设置播放文件:

//①raw下的资源:
MediaPlayer.create(this, R.raw.test);

//②本地文件路径:
mp.setDataSource("/sdcard/test.mp3");

//③网络URL文件:
mp.setDataSource("http://www.xxx.com/music/test.mp3");

另外setDataSource()方法有多个,里面有这样一个类型的参数:FileDescriptor,在使用这个API的时候,需要把文件放到res文件夹平级的assets文件夹里,然后使用下述代码设置DataSource:

AssetFileDescriptor fileDescriptor = getAssets().openFd("rain.mp3");
m_mediaPlayer.setDataSource(fileDescriptor.getFileDescriptor(),fileDescriptor.getStartOffset(), fileDescriptor.getLength());

3)其他方法

  • getCurrentPosition( ):得到当前的播放位置
  • getDuration() :得到文件的时间
  • getVideoHeight() :得到视频高度
  • getVideoWidth() :得到视频宽度
  • isLooping():是否循环播放
  • isPlaying():是否正在播放
  • pause():暂停
  • prepare():准备(同步)
  • prepareAsync():准备(异步)
  • release() :释放MediaPlayer对象
  • reset():重置MediaPlayer对象
  • seekTo(int msec) :指定播放的位置(以毫秒为单位的时间)
  • setAudioStreamType(int streamtype) :指定流媒体的类型
  • setDisplay(SurfaceHolder sh) :设置用SurfaceHolder来显示多媒体
  • setLooping(boolean looping) :设置是否循环播放
  • setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener) :网络流媒体的缓冲监听
  • setOnCompletionListener(MediaPlayer.OnCompletionListener listener) :网络流媒体播放结束监听
  • setOnErrorListener(MediaPlayer.OnErrorListener listener) :设置错误信息监听
  • setOnVideoSizeChangedListener(MediaPlayer.OnVideoSizeChangedListener listener) :视频尺寸监听
  • setScreenOnWhilePlaying(boolean screenOn) :设置是否使用SurfaceHolder显示
  • setVolume(float leftVolume, float rightVolume) :设置音量
  • start():开始播放
  • stop():停止播放

2.使用代码示例

示例一:使用MediaPlayer播放音频:

运行效果图

关键代码

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private Button btn_play;
    private Button btn_pause;
    private Button btn_stop;
    private MediaPlayer mPlayer = null;
    private boolean isRelease = true;   //判断是否MediaPlayer是否释放的标志

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bindViews();
    }

    private void bindViews() {
        btn_play = (Button) findViewById(R.id.btn_play);
        btn_pause = (Button) findViewById(R.id.btn_pause);
        btn_stop = (Button) findViewById(R.id.btn_stop);

        btn_play.setOnClickListener(this);
        btn_pause.setOnClickListener(this);
        btn_stop.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_play:
                if(isRelease){
                    mPlayer = MediaPlayer.create(this,R.raw.fly);
                    isRelease = false;
                }
                mPlayer.start();   //开始播放
                btn_play.setEnabled(false);
                btn_pause.setEnabled(true);
                btn_stop.setEnabled(true);
                break;
            case R.id.btn_pause:
                mPlayer.pause();     //停止播放
                btn_play.setEnabled(true);
                btn_pause.setEnabled(false);
                btn_stop.setEnabled(false);
                break;
            case R.id.btn_stop:
                mPlayer.reset();     //重置MediaPlayer
                mPlayer.release();   //释放MediaPlayer
                isRelease = true;
                btn_play.setEnabled(true);
                btn_pause.setEnabled(false);
                btn_stop.setEnabled(false);
                break;
        }
    }
}

注意事项:

播放的是res/raw目录下的音频文件,创建MediaPlayer调用的是create方法,第一次启动播放前不需要再调用prepare(),如果是使用构造方法构造的话,则需要调用一次prepare()方法!另外贴下官方文档中,从其他两种途径播放音频的示例代码:

本地Uri

Uri myUri = ....; // initialize Uri here
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(getApplicationContext(), myUri);
mediaPlayer.prepare();
mediaPlayer.start();

外部URL

String url = "http://........"; // your URL here
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(url);
mediaPlayer.prepare(); // might take long! (for buffering, etc)
mediaPlayer.start();

Note:假如你通过一个URL以流的形式播放在线音频文件,该文件必须可以进行渐进式下载

示例二:使用MediaPlayer播放视频

MediaPlayer主要用于播放音频,没有提供图像输出界面,所以我们需要借助其他的组件来显示MediaPlayer播放的图像输出,我们可以使用用SurfaceView来显示,下面我们使用SurfaceView来写个视频播放的例子:

运行效果图

实现代码

布局文件:activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="5dp">

    <SurfaceView
        android:id="@+id/sfv_show"
        android:layout_width="match_parent"
        android:layout_height="300dp" />

    <Button
        android:id="@+id/btn_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="开始" />

    <Button
        android:id="@+id/btn_pause"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="暂停 " />

    <Button
        android:id="@+id/btn_stop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="终止" />
    
</LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener, SurfaceHolder.Callback {

    private MediaPlayer mPlayer = null;
    private SurfaceView sfv_show;
    private SurfaceHolder surfaceHolder;
    private Button btn_start;
    private Button btn_pause;
    private Button btn_stop;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bindViews();
    }

    private void bindViews() {
        sfv_show = (SurfaceView) findViewById(R.id.sfv_show);
        btn_start = (Button) findViewById(R.id.btn_start);
        btn_pause = (Button) findViewById(R.id.btn_pause);
        btn_stop = (Button) findViewById(R.id.btn_stop);

        btn_start.setOnClickListener(this);
        btn_pause.setOnClickListener(this);
        btn_stop.setOnClickListener(this);

        //初始化SurfaceHolder类,SurfaceView的控制器
        surfaceHolder = sfv_show.getHolder();
        surfaceHolder.addCallback(this);
        surfaceHolder.setFixedSize(320, 220);   //显示的分辨率,不设置为视频默认

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_start:
                mPlayer.start();
                break;
            case R.id.btn_pause:
                mPlayer.pause();
                break;
            case R.id.btn_stop:
                mPlayer.stop();
                break;
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        mPlayer = MediaPlayer.create(MainActivity.this, R.raw.lesson);
        mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        mPlayer.setDisplay(surfaceHolder);    //设置显示视频显示在SurfaceView上
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {}

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mPlayer.isPlaying()) {
            mPlayer.stop();
        }
        mPlayer.release();
    }
}

代码很简单,布局有个SurfaceView,然后调用getHolder获得一个SurfaceHolder对象,在这里完成SurfaceView相关的设置,设置了显示的分辨率以及一个Callback接口,重写了SurfaceView创建时,发生变化时,以及销毁时的三个方法!然后按钮控制播放以及暂停而已。

示例三:使用VideoView播放视频

除了使用MediaPlayer + SurfaceView播放视频的方式,我们还可以使用VideoView来直接播放视频,我们稍微改点东西就可以实现视频播放!运行效果和上面的一致,就不贴了,直接上代码!

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private VideoView videoView;
    private Button btn_start;
    private Button btn_pause;
    private Button btn_stop;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bindViews();
    }
    
    private void bindViews() {
        videoView = (VideoView) findViewById(R.id.videoView);
        btn_start = (Button) findViewById(R.id.btn_start);
        btn_pause = (Button) findViewById(R.id.btn_pause);
        btn_stop = (Button) findViewById(R.id.btn_stop);

        btn_start.setOnClickListener(this);
        btn_pause.setOnClickListener(this);
        btn_stop.setOnClickListener(this);
        
        //根据文件路径播放
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            videoView.setVideoPath(Environment.getExternalStorageDirectory() + "/lesson.mp4");
        }

        //读取放在raw目录下的文件
        //videoView.setVideoURI(Uri.parse("android.resource://com.jay.videoviewdemo/" + R.raw.lesson));
        videoView.setMediaController(new MediaController(this));
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_start:
                videoView.start();
                break;
            case R.id.btn_pause:
                videoView.pause();
                break;
            case R.id.btn_stop:
                videoView.stopPlayback();
                break;
        }
    }
}

这里给大家推荐一套相关《音视频开发核心知识点笔记》,相信可以给大家提供一些帮助,有需要的朋友们也可以下载下来随时查漏补缺:https://qr18.cn/Ei3VPD

音视频初级入门

音视频初级入门主要是接触Android多媒体展示相关的API,通过单独的列举和使用这些API,对Android音视频处理有一个基本的轮廓,虽然知识点相对来说是比较散的,但是点成线、线成面,基本的基础掌握了,通过学习Android音视频核心的API将音视频的流程串联起来,这样对于音视频的了解和控制就不仅仅局限于最外层的API了,而是能够通过相对底层的方式来加深对Android 音视频开发的认知。

  • Android 音视频开发(一):通过三种方式绘制图片
  • Android 音视频开发(二):使用 AudioRecord 采集音频PCM并保存到文件
  • Android 音视频开发(三):使用 AudioTrack 播放PCM音频
  • Android 音视频开发(四):使用 Camera API 采集视频数据
  • Android 音视频开发(五):使用 MediaExtractor 和 MediaMuxer API 解析和封装 mp4 文件
  • Android 音视频开发(六):MediaCodec API 详解
  • Android 音视频开发(七):音视频录制流程总结 ……

音视频中级进阶:OpenSL ES 学习:https://qr18.cn/Ei3VPD

学习 Android 平台 OpenSL ES API,了解 OpenSL 开发的基本流程,使用OpenSL播放PCM数据,并了解相关API的简单使用

  • Android OpenSL ES 开发:Android OpenSL 介绍和开发流程说明
  • Android OpenSL ES 开发:使用 OpenSL 播放 PCM 数据
  • Android OpenSL ES 开发:Android OpenSL 录制 PCM 音频数据
  • Android OpenSL ES 开发:OpenSL ES利用SoundTouch实现PCM音频的变速和变调

这一部分主要是动手实践,积累实战经验,可以试试给自己定以下目标:

  • 使用 OpenGL 显示一张图片

  • GLSurfaceviw 绘制 Camera 预览画面及实现拍照 使用OpenGL ES

  • 完成视频的录制,并实现视频水印效果

  • Android OpenGL ES 开发(一): OpenGL ES 介绍

  • Android OpenGL ES 开发(二): OpenGL ES 环境搭建

  • Android OpenGL ES 开发(三): OpenGL ES 定义形状

  • Android OpenGL ES 开发(四): OpenGL ES 绘制形状

  • Android OpenGL ES 开发(五): OpenGL ES 使用投影和相机视图

  • Android OpenGL ES 开发(六): OpenGL ES 添加运动效果

  • Android OpenGL ES 开发(七): OpenGL ES 响应触摸事件

  • Android OpenGL ES 开发(八): OpenGL ES 着色器语言GLSL

  • Android OpenGL ES 开发(九): OpenGL ES 纹理贴图

  • Android OpenGL ES 开发(十):通过GLES20与着色器交互

  • ……

音视频高级探究

  • 深入学习音视频编码,如H.264,AAC,研究使用开源编解码库,如x.264,JM 等
  • 深入研究音视频相关的网络协议,如 rtmp,hls,以及封包格式,如:flv,mp4
  • 深入学习一些音视频领域的开源项目,如 webrtc,ffmpeg,ijkplayer,librtmp 等等
  • 将 ffmpeg 库移植到 Android 平台,结合上面积累的经验,编写一款简易的音视频播放器
  • 将 x264 库移植到 Android 平台,结合上面积累的经验,完成视频数据 H264 软编功能
  • 将 librtmp 库移植到 Android 平台,结合上面积累的经验,完成 Android RTMP 推流功能

音视频编解码技术:https://qr18.cn/Ei3VPD

  • 音视频编解码技术(一):MPEG-4/H.264 AVC 编解码标准 音
  • 视频编解码技术(二):AAC 音频编码技术
  • ……

流媒体协议

  • 流媒体协议(一):HLS 协议
  • 流媒体协议(二):RTMP协议
  • ……

多媒体文件格式

  • 多媒体文件格式(一):MP4 格式
  • 多媒体文件格式(二):FLV 格式
  • 多媒体文件格式(三):M3U8 格式
  • 多媒体文件格式(四):TS 格式
  • 多媒体文件格式(五):PCM / WAV 格式 ……

FFmpeg 学习:https://qr18.cn/Ei3VPD

  • FFmpeg命令行工具学习(一):查看媒体文件头信息工具ffprobe
  • FFmpeg命令行工具学习(二):播放媒体文件的工具ffplay
  • FFmpeg命令行工具学习(三):媒体文件转换工具ffmpeg
  • FFmpeg命令行工具学习(四):FFmpeg 采集设备
  • FFmpeg命令行工具学习(五):FFmpeg 调整音视频播放速度
  • ……

  • FFmpeg 学习(一):FFmpeg 简介
  • FFmpeg 学习(二):Mac下安装FFmpeg
  • FFmpeg 学习(三):将 FFmpeg 移植到 Android平台
  • FFmpeg 学习(四):FFmpeg API 介绍与通用 API 分析
  • FFmpeg 学习(五):FFmpeg 编解码 API 分析
  • FFmpeg 学习(六):FFmpeg 核心模块 libavformat 与 libavcodec 分析
  • ……

  • FFmpeg 结构体学习(一):AVFormatContext 分析
  • FFmpeg 结构体学习(二):AVStream 分析
  • FFmpeg 结构体学习(三):AVPacket 分析
  • FFmpeg 结构体学习(四):AVFrame 分析
  • FFmpeg 结构体学习(五):AVCodec 分析
  • FFmpeg 结构体学习(六):AVCodecContext 分析
  • FFmpeg 结构体学习(七):AVIOContext 分析
  • FFmpeg 结构体学习(八):FFMPEG中重要结构体之间的关系
  • ……

  • FFmpeg 开发之 AVFilter 使用流程总结
  • FFmpeg 过时 Api 汇总整理
  • ……

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/88805.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Talk | 上海交通大学官同坤:识别任意文本,隐式注意力与字符间蒸馏在文本识别中的应用

本期为TechBeat人工智能社区第525期线上Talk&#xff01; 北京时间8月23日(周三)20:00&#xff0c;上海交通大学博士生—官同坤的Talk已准时在TechBeat人工智能社区开播&#xff01; 他与大家分享的主题是: “隐式注意力与字符间蒸馏在文本识别中的应用”&#xff0c;分享了识别…

使用docker-maven-plugin插件构建镜像并推送至私服Harbor

前言 如下所示&#xff0c;建议使用 Dockerfile Maven 插件&#xff0c;但该插件也停止维护更新了。因此先暂时使用docker-maven-plugin插件。 一、开启Docker服务器的远程访问 1.1 开启2375远程访问 默认的dokcer是不支持远程访问的&#xff0c;需要加点配置&#xff0c;开…

bh002- Blazor hybrid / Maui 保存设置快速教程

1. 建立工程 bh002_ORM 源码 2. 添加 nuget 包 <PackageReference Include"BootstrapBlazor.WebAPI" Version"7.*" /> <PackageReference Include"FreeSql" Version"*" /> <PackageReference Include"FreeSql.…

MyBatis分页插件PageHelper的使用及特殊字符的处理

目录 一、PageHelper简介 1.什么是分页 2.PageHelper是什么 3.使用PageHelper的优点 二、PageHelper插件的使用 原生limit查询 1. 导入pom依赖 2. Mybatis.cfg.xml 配置拦截器 3. 使用PageHelper进行分页 三、特殊字符的处理 1.SQL注入&#xff1a; 2.XML转义&#…

【Linux】【驱动】第一个相对完整的驱动编写

【Linux】【驱动】第一个相对完整的驱动编写 续1.驱动部分的代码2 app 代码3 操作相关的代码 续 这个章节会讲述去直接控制一个GPIO&#xff0c;高低电平。 因为linux不允许直接去操作寄存器&#xff0c;所以在操作寄存器的时候就需要使用到函数&#xff1a;ioremap 和iounma…

线性代数的学习和整理10:各种特殊类型的矩阵(草稿-----未完成 建设ing)

目录 1 图形化分类 1.1对称矩阵 1.2 梯形矩阵 1.3 三角矩阵 1.3.1 上三角矩阵 1.4 对角线矩阵 2 按各自功能分 2.1 等价矩阵 2.2 增广矩阵 2.3 伴随矩阵 2.4 正交矩阵 2.5 正交矩阵 2.6 相似矩阵 1 图形化分类 1.1对称矩阵 1.2 梯形矩阵 1.3 三角矩阵 1.3.1 上…

【ARM-Linux】项目,语音刷抖音项目

文章目录 所需器材装备操作SU-03T语音模块配置代码&#xff08;没有用wiring库&#xff0c;自己实现串口通信&#xff09;结束 所需器材 可以百度了解以下器材 orangepi-zero2全志开发板 su-03T语音识别模块 USB-TTL模块 一个安卓手机 一根可以传输的数据线 装备操作 安…

windows Etcd的安装与使用

一、简介 etcd是一个分布式一致性键值存储&#xff0c;其主要用于分布式系统的共享配置和服务发现。 etcd由Go语言编写 二、下载并安装 1.下载地址&#xff1a; https://github.com/coreos/etcd/releases 解压后的目录如下&#xff1a;其中etcd.exe是服务端&#xff0c;e…

C语言弯道超车必做好题锦集(编程题)

目录 前言&#xff1a; 1.计算日期到天数转换 2.尼科彻斯定理 3.密码检查 4.图片整理 5.寻找数组的中心下标 6.字符个数统计 7.多数元素 前言&#xff1a; 编程想要学的好&#xff0c;刷题少不了&#xff0c;我们不仅要多刷题&#xff0c;还要刷好题&#xff01;为此我…

C# .aspx网页获取RFID读卡器HTTP协议提交的访问文件Request获得卡号、机号,Response回应驱动读卡器显示响声

本示例使用的设备&#xff1a;RFID网络WIFI无线TCP/UDP/HTTP可编程二次开发读卡器POE供电语音-淘宝网 (taobao.com) 服务端代码&#xff1a; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.…

iptables的使用规则

环境中为了安全要限制swagger的访问&#xff0c;最简单的方式是通过iptables防火墙设置规则限制。 在测试服务器中设置访问swagger-ui.html显示如下&#xff0c;区分大小写&#xff1a; iptables设置限制访问9783端口的swagger字段的请求&#xff1a; iptables -A INPUT -p t…

Python可视化工具库实战

Matplotlib Matplotlib 是 Python 的可视化基础库&#xff0c;作图风格和 MATLAB 类似&#xff0c;所以称为 Matplotlib。一般学习 Python 数据可视化&#xff0c;都会从 Matplotlib 入手&#xff0c;然后再学习其他的 Python 可视化库。 Seaborn Seaborn 是一个基于 Matplo…

Vue 中 diff 算法原理

一、Diff 概念 Vue 基于虚拟 DOM 做更新。diff 算法的核心就是比较两个虚拟节点的差异&#xff0c;返回一个 patch 对象&#xff0c;这个对象的作用就是存储两个节点不同的地方&#xff0c;最后用 patch 里记录的信息进行更新真实DOM。 diff 算法的在很多场景下都有应用&#…

计算机竞赛 地铁大数据客流分析系统 设计与实现

文章目录 1 前言1.1 实现目的 2 数据集2.2 数据集概况2.3 数据字段 3 实现效果3.1 地铁数据整体概况3.2 平均指标3.3 地铁2018年9月开通运营的线路3.4 客流量相关统计3.4.1 线路客流量排行3.4.2 站点客流量排行3.4.3 入站客流排行3.4.4 整体客流随时间变化趋势3.4.5 不同线路客…

6.oracle中listagg函数使用

1. 作用 可以实现行转列&#xff0c;将多列数据聚合为一列&#xff0c;实现数据的压缩 2. 语法 listagg(measure_expr&#xff0c;delimiter) within group ( order by order_by_clause); 解释&#xff1a; measure_expr可以是基于任何列的表达式 delimiter分隔符&#xff0c…

创建harbor仓库并进行一些操作

文章目录 前言一、使用mysql:5.6和 owncloud 镜像&#xff0c;构建一个个人网盘。二、安装搭建私有仓库 Harbor1、安装docker-compse2、安装harbor 3、修改配置文件4、运行脚本5 登入harbor仓库总结 前言 本篇文章需要完成的以下几个操作&#xff1a; 使用mysql:5.6和 ownclo…

爬虫逆向实战(二十)--某99网站登录

一、数据接口分析 主页地址&#xff1a;某99网站 1、抓包 通过抓包可以发现登录接口是AC_userlogin 2、判断是否有加密参数 请求参数是否加密&#xff1f; 通过查看“载荷”可以发现txtPassword和aws是加密参数 请求头是否加密&#xff1f; 无响应是否加密&#xff1f; 无…

【Git版本控制工具使用---讲解一】

Git版本控制工具使用 安装设置用户名签名和邮箱Git常用的命令 初始化本地库查看本地状态Git 命令添加暂存区提交本地库查看版本信息修改文件版本穿梭 安装 首先根据自身电脑的配置选择性的安装是32位的还是64位的Git版本控制工具 我这边安装的是64位的 以下是我安装的时候的过…

C语言:选择+编程(每日一练Day8)

目录 选择题&#xff1a; 题一&#xff1a; 题二&#xff1a; 题三&#xff1a; 题四&#xff1a; 题五&#xff1a; 编程题&#xff1a; 题一&#xff1a;字符个数统计 思路一&#xff1a; 题二&#xff1a;多数元素 思路一&#xff1a; 本人实力有限可能对一些…

事件捕获和事件冒泡

事件捕获和事件冒泡与事件流有关系。 以下代码&#xff0c;点击 aa &#xff0c;控制台会打印什么呢&#xff1f; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content&q…