车载音视频App框架设计

简介

统一播放器提供媒体播放一致性的交互和视觉体验,减少各个媒体应用和场景独自开发的重复工作量,实现媒体播放链路的一致性,减少碎片化的Bug。本文面向应用开发者介绍如何快速接入媒体播放器。

主要功能:

  1. 新设计的统一播放UI组件,视频支持的手势操作,包括左右滑拖动进度、左上下滑调节亮度、右上下滑调节音量、双击暂停/播放,同时对外暴露了长按手势接口应用可以实现类似快进快退功能;
  2. 支持方控、Mini播放器、PSD的播控和状态显示,应用只需要申请媒体中心权限的license即可,支持媒体中心的状态保持和语音控制通道,需要APP中接入对应的接口;
  3. 支持视频行车娱乐限制,非P档播放视频会暂停播放弹框提示;
  4. 使用原生的的media3 1.3.0版本,支持原生的androidx 和framework media session;
  5. 支持音频焦点自管理,包括电话状态的播控也基于音频焦点统一处理;

整体架构图如下

  1. 应用通过配置UI,然后创建MediaController播放媒体;
  2. controler端接入了行车娱乐限制的检测和提示;
  3. service端实现了google原生的media3 session service;
  4. 媒体中心通过mediasession和播放器连接;
  5. 底层使用media3 exoplayer播放和音频焦点管理;

接入流程

1、配置依赖
implementation 'com.max.mediaplayer:uniteplayer:1.x.x

备注:uniteplayer中包含了视频控制UI组件,当只需要修复控制UI组件的bug时,可以更新整体uniteplayer播放器组件,也可以只增加UI组件的依赖,比如:implementation (‘com.max.media:media-video:1.2.0’)。

2、初始化

建议在application创建的时候调用初始化接口:

init(context: Context, isVideo: Boolean, enableMediaCenter: Boolean = false)

参数说明
context应用context
isVideo是否视频应用,视频会初始化车机相关的adapterapi,音乐目前不会初始化
enableMediaCenter需要远程方控、语音控制、mini播放器控制这些能力时设置为true,否则为false,默认为false
3、接入 UI 组件 (视频应用)

这里的UI组件只针对视频应用,音频应用的UI组件在媒体组件库中,参考媒体视频组件。

1)配置PlayerView

在布局中增加FlexPlayerView,视频内容显示和播控UI都在此view中,一般默认配置如下即可:

<com.max.uniteplayer.ui.FlexPlayerView
    android:id="@+id/player_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

其中播控UI是可单独接入的,若需定制,接入见视频组件接入文档。

2)配置视频渲染view

一般情况下不需要特别配置,支持的定制视频显示view参数如下:

比如在上面FlexPlayerView xml中用app:surface_type=“surface_view”

surface_type:surface类型,取值如下,默认是surface_view类型:

<attr name="surface_type" format="enum"> 
     <enum name="none" value="0"/>   
     <enum name="surface_view" value="1"/>  
     <enum name="texture_view" value="2"/>  
     <enum name="spherical_gl_surface_view" value="3"/>  
     <enum name="video_decoder_gl_surface_view" value="4"/>
 </attr>

resize_mode,取值如下,默认fit模式:

  <attr name="resize_mode" format="enum">  
    <enum name="fit" value="0"/>  
    <enum name="fixed_width" value="1"/>
    <enum name="fixed_height" value="2"/> 
    <enum name="fill" value="3"/> 
    <enum name="zoom" value="4"/> 
 </attr>

first_render_delay,首帧显示延迟时长,用于规避首帧渲染慢闪拉伸的问题,int型,单位ms,一舨不需要设置,默认0;

3)配置视频播控View

FlexPlayerView本身对外暴露了两个接口:

接口说明
fun setTitleBarVisible(visible: Boolean)因此视频播放器中顶部title和关闭按钮,一般应用自己实现的可以通过此接口隐藏
fun enableUpDownGesture(enable: Boolean)使能上下滑动,默认播放器是支持的,可以设置false关闭
bindControlView(listener: FlexPlayerView.ControlViewListener)获取视频播控view控制器,提供更多配置能力,比如增加手势监听回调、添加自定义的播控按钮等,具体可以参考视频组件接入文档。
4、使用播放器播放

有3种播放接口,选择其中一个:

1)FlexSimplePlayer

封装的最高层播放接口,内部封装好了原生MediaItem对象,简单的视频播放场景推荐使用此接口:

class FlexSimplePlayer(context: Context?,
    isVideo: Boolean,
    enableParkDetect: Boolean = true,
    enableParkDialog: Boolean = true,
    controllerCallback: FlexControllerCallback? = null)

参数说明:

参数说明
context上下文;
enableParkDetect只针对视频生效,是否启用行车娱乐限制,非驻车档会自动暂停视频播放(默认是强制要求的);
enableParkDialog只针对视频生效,是否弹出行车娱乐限制框,设置为disable后需要应用可以自己实现提示界面;

开始播放:

player.startPlay(context: Context,
        mediaData: List<MediaData>,
        view: FlexPlayerView?,
        listener: FlexMediaListener?,
        mediaCenterData: MediaCenterData? = null)

参数说明:

参数说明
context上下文,注意视频播放要使用activity的context,因为行车娱乐限制需要弹框
mediaData媒体列表,每个媒体item包括url、metadata、mimetiype,其中url是媒体地址,可以是本地、在线点播或直播地址,medadata是media3的原始类型,title和artist字段会显示在mini播放器和PSD上,mimeTypes指定媒体类型,url是对应后缀的无需设置,有些比如优酷投屏中有一个直播url是/m3u8结尾 而不是.m3u8结尾 需要设置mimeTypes = MimeTypes.APPLICATION_M3U8;
view类型为FlexPlayerView,自实现UI的此参数设置为null
listener媒体播放监听回调,具体回调接口后面详细展开,不需要监听设置为null
mediaCenterData媒体中心中需要用的数据,比如应用包名、图标等,具体类型后面详细展开,这里需要注意的是sourceType要设置为6,在媒体中心中对应SourceType.SOURCE_TYPE_ONLINE。
controllerCallback媒体中心回调的方法,包括播放/暂停、上/下曲切换,在此回调中可以实现自定义处理逻辑,并屏蔽底层播放器的响应;

退出界面停止播放,停止播放后会释放所有播放资源:

player.stopPlay()

页面切换的处理建议:

视频应用界面退到后台(onPuse)暂停: player.pause()

视频应用从后台回到前台(onResume): player.play()

更新播放列表:

fun updateMediaItems(mediaData: List<MediaData>)

在已经进入播放状态下,更换播放的视频建议使用该接口,避免重新startPlay()会更慢。

2)FlexMediaController

音频类应用复杂场景建议使用该接口。

FlexSimplePlayer下层的接口,使用该接口需要自己创建MediaItem,mimeType需要调用util接口设置。适合需要自己构建比较复杂的mediaitem场景,另外没有直接提供暂停和播放接口,需要调用成员player的暂停和播放接口。

构造方法解释同FlexSimplePlayer。

开始播放:

fun startPlay(context: Context,
    mediaItems: List<MediaItem>,
    view: FlexPlayerView?,
    listener: FlexMediaListener?,
    customData: MediaCenterData?,
    controllerCallback: FlexControllerCallback? = null)

参数说明:

参数说明
context上下文,注意视频播放要使用activity的context,因为行车娱乐限制需要弹框
mediaItems媒体列表,原生类型,包括媒体url,metadata,mimetype等
view类型为FlexPlayerView,自实现UI的此参数设置为null
listener媒体播放监听回调,具体回调接口后面详细展开,不需要监听设置为null
mediaCenterData媒体中心中需要用的数据,比如应用包名、图标等,具体类型后面详细展开,这里需要注意的是sourceType要设置为6,在媒体中心中对应SourceType.SOURCE_TYPE_ONLINE。
controllerCallback媒体中心回调的方法,包括播放/暂停、上/下曲切换,在此回调中可以实现自定义处理逻辑,并屏蔽底层播放器的响应;

FlexControllerCallback接口:

interface FlexControllerCallback {
    companion object {

        const val KEY_ACTION_TYPE = "actionType"
        const val KEY_CALLBACK_RESULT = "callbackResult"

        const val TYPE_PLAY = 1
        const val TYPE_NEXT = 2
        const val TYPE_PREVIOUS = 3

        const val RESULT_OK = 0
        const val RESULT_BLOCK = 1
    }

    fun onDefaultCallback(bundle: Bundle): Bundle?{
        return Bundle.EMPTY
    }

    fun onPlayAction(): Int?{
        return RESULT_OK
    }

    fun onSeekToNext(): Int?{
        return RESULT_OK
    }

    fun onSeekToPrevious(): Int?{
        return RESULT_OK
    }
}

接口描述:

接口说明
onPlayAction(): Int?媒体中心调用过来的播放/暂停接口
onSeekToNext(): Int?媒体中心调用过来的下一首接口
onSeekToPrevious(): Int?媒体中心调用过来的上一首接口

退出界面停止播放,停止播放后会释放所有播放资源:

player.stopPlay()

页面切换的处理建议:

视频应用界面退到后台(onPuse)暂停: player.player?.pause()

视频应用从后台回到前台(onResume): player.player?.play()

更新播放列表:

fun updateMediaItems(mediaItems: List<MediaItem>)

在已经进入播放状态下,更换播放的视频建议使用该接口,避免重新startPlay()会更慢。

3)FlexExoPlayerController

此接口一般不会用到,前面两个接口默认会启动sessionservice,支持媒体中心的连接,此接口直接返回exoplayer播放器,不会创建mediasession,不支持媒体中心连接,支持视频行车娱乐限制。使用媒体UI组件和播放器需要在应用中自行对接,适用于定制化比较多,不需要远程播放支持的视频播放场景,目前只用在赛道模式。建议优先选用前面两种方式播放。

构造方法解释同FlexSimplePlayer。

fun getExoPlayer(audioFocus: Boolean = false,
 mediaListener: FlexMediaListener? = null): ExoPlayer?

参数和返回值:

参数说明
audioFocus是否打开音频焦点自管理,默认是false。在赛道模式情况存在两个视频同时播的情况,需要设置为false否则因为音频焦点抢占不能同时播放,其他场景建议设置为true;
mediaListener状态回调,同前面两个接口,具体参数后面详细描述;
返回值media3 ExoPlayer对象。
5、状态回调接口

自定义的播放回调接口:

interface FlexMediaListener{

    //player加载完成
    fun onLoadPlayerFinished(player: Player?) {}

    //返回true不会自动播放,需要调用play()后才能播放,默认false
    fun pauseWhenStart(): Boolean {
        return false
    }

    //直接返回player的状态接口,更多复杂场景建议拿player对象处理
    fun onPlaybackStateChange(state: Int){}
    fun onPlayWhenReadyChanged(ready: Boolean, reason: Int) {}
    fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {}

    //播放异常
    fun onPlayerError(errorCode: Int, errorData: Bundle?) {}

    //只针对视频,播放视频时检测到非驻车状态回调,会自动暂停播放
    fun onStartVideoWhenNoPark() {}

    //只针对视频,非驻车播放视频,弹框点击关闭按钮后的回调
    fun onStopVideoWhenNoPark() {}

    //关闭播放页面
    fun onClose(){}

    //退出应用
    fun onExitApp() {}

    //Mote: This is callback from media center, not from player
    fun onSeekToNext(): Boolean {
        return false
    }
    fun onSeekToPrevious(): Boolean {
        return false
    }
}

接口描述:

接口说明
onLoadPlayerFinished(player: Player?)开始播放是异步的调用,此回调表示已完成了到服务端的连接返回了有效的player接口
fun pauseWhenStart(): Boolean开始播放后是否自动暂停,需要用户手动点击播放,默认false
fun onPlaybackStateChange(state: Int) fun onPlayWhenReadyChanged(ready: Boolean, reason: Int) fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int)原生Player接口播放状态变化的透传,state取值:Player.STATE_IDLE:还未开始播放STATE_BUFFERING:缓冲中STATE_READY:准备好播放,结合PlayWhenReady状态来判断,true为播放中,false为暂停STATE_ENDED:播放结束onPlayWhenReadyChanged取值: true为播放中,false为暂停onMediaItemTransition:切歌可以通过这里判断
fun onPlayerError(errorCode: Int, errorData: Bundle?)播放异常,errorCode时原生的错误码,errorData暂时没有用到
fun onStartVideoWhenNoPark()只针对视频,档检测到非P档播放视频时会回调此接口
fun onStopVideoWhenNoPark()只针对视频,非P播放视频弹框后,点击关闭按钮或弹框自动退出时的回调
fun onClose()用户点击左上角关闭按钮
fun onExitApp()退出应用,暂未用到
fun onSeekToNext()方控或PSD切换下一曲操作会回调,返回true表示应用来接管下一曲操作不会调用底层播放器的下一曲接口,返回false底层会调用播放器的下一曲接口, 目前投屏用到
fun onSeekToPrevious()方控或PSD切换上一曲操作会回调,返回true表示应用来接管上一曲操作不会调用底层播放器的上一曲接口,返回false底层会调用播放器的上一曲接口,,投屏用到
6、语音控制

媒体中心语音控制接口,声明支持的语音语义,以及处理语音控制的回调

fun declareVrSemanticsCapability(channelInfo: MCVrChannelInfo?,
 vrSemanticCallback: VrSemanticCallback)

参数说明:

参数说明
channelInfoMCVrChannelInfo类型,具体字段: mediaPackageName: 应用包名 mediaVersion: 应用版本 mediaDescription: 应用描述 channelDataType: 通道类型,一般设置为0 semantics: IntArray 支持的语义数组,MCSemanticsType.CONTROL_PLAY等
vrSemanticCallback语音的回调,具体的实现可参考媒体中心接入文档
7、播放状态保持

媒体中心的状态保持功能可实现应用的自启动(通过媒体中心拉起),首先在开始播放的时候需要在mediacenterdata中设置recoveryIntent;

示例:

        val intent = Intent()
        intent.setPackage("com.max.example")
        intent.action = "com.max.example.action.RecoverService"
        intent.putExtra("type", "StateRecover")

后面在车机重启后,通过如下接口获取之前的播放状态:

fun getRecoveryPlaybackInfo (infoCallback: Consumer<MCPlaybackInfo?>)

其中MCPlaybackInfo类型和媒体中心中的MusicPlaybackInfo对应,通过其中的包名可以判断上一次是否自己播放然后更新媒体中心到迷你播放器,实现重启播放恢复的功能。

8、自定义通道
1)媒体中心通道

媒体中心通道用于更新Mini播放器和PSD状态

接口:FlexMediaController.sendCustomAction(action: Int, bundle: Bundle? = null)

  1. 更新歌词:
    val bd = Bundle()
    bd.putString(Constants.KEY_LYRIC_STRING, "hello lyric")
    mediaController?.sendCustomAction(Constants.ACTION_UPDATE_LYRIC, bd)
  1. 更新播放状态:

用于在非播放状态下强制更新媒体信息到媒体中心。

    mediaController?.sendCustomAction(Constants.ACTION_UPDATE_MEDIACENTER, null)
2)远程MediaSession通道

远程Mediasession主要用于更新RSD的信息。

Androidx原生接口:MediaController.sendCustomCommand(command: SessionCommand, bundle: Bundle)

  1. 设置歌词:
    val bd = Bundle()
    bd.putString("lyrics", lyric)
    bd.putString("lyrics_tr", lyricTr)  //英文歌词
    it.sendCustomCommand(
        SessionCommand(
            Constants.COMMAND_SET_SESSION_EXTRA,
            Bundle.EMPTY
        ), bd
    )
  1. 设置试看点:
    val bd = Bundle()
    bd.putBoolean("isCanTrail", isCanTrail)//true试听歌曲,false非试听歌曲
    bd.putLong("trail_start", start)
    bd.putLong("trail_end", end)
    it.sendCustomCommand(
        SessionCommand(
            Constants.COMMAND_SET_SESSION_EXTRA,
            Bundle.EMPTY
        ), bd
    )
9、更多功能使用原生Player/MediaController接口

有其他更多播放场景的需求,可以通过FlexSimplePlayer/FlexMediaController/player直接拿到media3的原始player对象实现。

注意事项

  1. Media3要求工程的compileSDK>=34,这个改动会影响编译过程,不影响运行时。可能会涉及少量系统接口参数适配否则编译会报错,targetSDK建议不动;
  2. Player的接口调用在主线程进行,对应的状态listener回调也会在主线程中(需要在同一个线程中,否则会报异常);
  3. startPlay()和stopPlay()调用时机需要匹配,比如在onCreateView中调用startPlay() 在onDestoryView中调用stopPlay(),或者在startPlay()之前先调用stopPlay();
  4. 全屏的视频播放,activity的decorView.windowSystemUiVisibility需要设置View.SYSTEM_UI_FLAG_FULLSCREEN,这样行车娱乐限制的弹框会根据全屏的状态隐藏状态栏和docker栏;
  5. 当前版本还不支持mediasession service多进程;

参考Demo

uniteplayerdemo(视频)

音频类可参考杜比播放器和网易云音乐APP等应用,附网易云APP的播放架构:

遗留问题

1、电话中播放控制还未在框架中实现,需要应用来处理;

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

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

相关文章

Windows FFmpeg 开发环境搭建

FFmpeg 开发环境搭建 FFmpeg命令行环境搭建使用FFmpeg官方编译的库Windows编译FFmpeg1. 下载[msys2](https://www.msys2.org/#installation)2. 安装完成之后,将安装⽬录下的msys2_shell.cmd中注释掉的 rem set3. 修改pacman 镜像源并安装依赖4. 下载并编译源码 FFmpeg命令行环境…

【C++】 string类的模拟实现

目录 一、我们先创建三个文件分别为 String.h&#xff08;声明&#xff09;、String.cpp&#xff08;定义&#xff09;、teat.cpp&#xff08;测试&#xff09; 二、成员函数 构造函数与析构函数 &#x1f31f;string() &#x1f31f;string(const char* str) &#x1f…

c++基础(类和对象中)(类的默认成员函数)

目录 一.构造函数&#xff08;类似初始化&#xff09; 1.概念 2.构造函数的特点 二.析构函数&#xff08;类似 销毁对象/空间&#xff09; 三.拷贝构造函数(类似复制粘贴的一种 初始化 ) 1.概念&#xff1a; 2.拷贝构造的特点&#xff1a; 四.赋值运算符重载&#xff08…

【MATLAB实战】基于UNet的肺结节的检测

数据&#xff1a; 训练过程图 算法简介&#xff1a; UNet网络是分割任务中的一个经典模型,因其整体形状与"U"相似而得名,"U"形结构有助于捕获多尺度信息,并促进了特征的精确重建&#xff0c;该网络整体由编码器,解码器以及跳跃连接三部分组成。 编码器由…

数据结构第一讲:复杂度

数据结构第一讲&#xff1a;复杂度 1.数据结构前言1.1什么是数据结构1.2算法 2.算法效率2.1复杂度的概念 3.时间复杂度3.1案例13.2案例23.3案例33.4案例43.5案例53.6案例63.7案例7 4.空间复杂度4.1案例14.2案例2 5.常见复杂度对比6.轮转数组题目分析6.1优化16.2优化2 博客简介&…

走进MongoDB--update和remove操作

操作任务 1.复制集合s&#xff0c;新集合名称为sbak。在sbak中完成以下操作 2.修改学号为1001同学的年龄为20岁 3.所有男同学的文档增加addr属性&#xff0c;值为“hebei” 4.删除wangwu同学的年龄属性 5.修改zhangsi同学的年龄属性为20&#xff0c;如果没有满足条件的则插…

DNS域名解析轮询过程图解

Q1: 先从本地浏览器/系统DNS缓存查找是否有解析记录 Q2:从本地hosts文件查找解析记录 Q3:如果前2步没有找到本地解析记录 hosts也无记录就从本地域名服务器查找 Q4:本地域名服务器区域缓存记录查找 Q5:查找转发器是否有 Q6--Q7:查找根com顶级域名服务器 Q8: 查找test.com…

力扣 字符串章节 344反转字符串

编写一个函数&#xff0c;将输入字符翻转过来,原地修改 思路 字符串用数组的形式存储&#xff0c;数组长度分奇数和偶数两种 如果长度是奇数&#xff0c;循环到str.size()/2&#xff0c;中间值不动 如果长度是偶数&#xff0c;循环到str.size()/2&#xff0c;全部参与反转 …

【简单介绍Gitea】

🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步! Gitea.🍀 Gitea是一个开源的,轻量级的代码托管解决方案,它是…

收到赵健老师的限量签名书,开心

收到赵老师的亲笔签名&#x1f4d6;&#xff0c;开心一下下[愉快]&#xff0c;由外而内&#xff0c;首先是我喜欢的线装书&#xff0c;展开阅读舒适&#xff0c;手感友好&#xff0c;纸张更是很讲究&#xff0c;密度很高也很温润&#xff0c;应该是进口纸&#xff0c;每个对页的…

Linux主机添加ipv6地址

一、添加网卡ipv6地址 通过命令行添加 ip add add 2001:db8:0:1::102/64 dev ens160 通过编辑/etc/sysconfig/network-scripts/目录下的ifcfg-配置文件添加 TYPEEthernet BOOTPROTOdhcp # 或者指定为 "static" 如果你想要静态配置 DEFROUTEyes IPV4_FAILURE_FAT…

Uniapp基础篇(持续更新)

1. Uni-app常用内置组件 view 视图容器 scroll-view 可滚动视图区域&#xff0c;用于区域滚动。需注意在webview渲染的页面中&#xff0c;区域滚动的性能不及页面滚动。 swiper 滑块视图容器。一般用于左右滑动或上下滑动&#xff0c;比如banner轮播图。 image uniapp官方iam…

萝卜快跑无人出租车是有人远程代驾? 客服:没有人操控

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 更多资源欢迎关注 近期“萝卜快跑”无人驾驶网约车相关话题引发网友热议。 有网传图片显示&#xff0c;萝卜快跑机器人智控中心&#xff0c;有真人坐在带有方向盘的屏幕前&#xff1b; 有网友认为所谓的无人网约车&am…

Unty 崩溃问题(Burst 1.8.2)

错误代码&#xff1a; Assertion failed on expression: exception SCRIPTING_NULL UnityEngine.StackTraceUtility:ExtractStackTrace () Unity.Burst.BurstCompiler:SendRawCommandToCompiler (string Unity版本&#xff1a;2021.3.17F1&#xff0c;Burst 1.8.2 表现&…

黑马程序员瑞吉外卖Day6小程序空白无显示

做项目时出现问题之druid连接池报错 报错discard long time none received connection. , jdbcUrl : jdbc:mysql://localhost:3306/sky_take_out?serverTimezoneAsia/Shanghai&useUnicodetrue&characterEncodingutf-8&zeroDateTimeBehaviorconvertToNull&use…

Typescript 实现倒计时功能 useCountdown

效果图 代码块 useCountdown.ts import {onUnmounted, reactive, ref, watch} from "vue";type union = days | hours | minutes | seconds | millisecondsexport type Remains = Record<union, number>;/*** 创建一个倒计时** 用法*/ export const useCount…

“七夕之夜”:艺术家刘兰芳、陶玉玲等相约临沂蒙山沂水大剧院

人海信息网山东讯&#xff08;冯爱云、徐婉桦&#xff09; 近日&#xff0c;记者从北京御龙古今艺术剧院山东分院获悉&#xff0c;由该院承办、中国文艺研究会指导、北京御龙古今艺术剧院主办的2024御龙“七夕之夜”演唱会&#xff0c;将在浪漫的七夕前夜——8月9日晚&#xf…

视频压縮大小不影响画质,视频压缩大小不影响画质的软件

在数字化浪潮推动下&#xff0c;视频制作和分享已成为我们生活的一部分。然而&#xff0c;视频文件体积过大常常让分享和存储变得头疼。今天&#xff0c;我们就来聊聊如何在苹果电脑上压缩视频文件大小&#xff0c;让你的视频瞬间瘦身&#xff01; 方法一、 1.下载并安装视频压…

JavaScript 中怎么看数据返回值

文章目录 前言console.log()1. 输出简单的文本2. 输出变量3. 输出表达式的结果4. 输出对象和数组5. 输出多个参数6. 使用模板字符串7. 输出错误信息 alert()基本用法使用场景注意事项 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 我只知道后端程序跑…

记录些MySQL题集(7)

1. 什么是SQL&#xff1f; SQL 的全称是 Structured Query Language&#xff0c;即结构化查询语言&#xff0c;它是用来与关系型数据库管理系统&#xff08;RDBMS&#xff09;交互的语言&#xff0c;包括从表中获取、更新、插入和删除数据&#xff0c;也就是我们常说的增删改查…