直接贴代码了:

ffmpegTest02.cs

    public partial class ffmpegTest02 : FormBase
{
private static readonly string TaskffmpegNETExeFullPath = ConfigurationManager.AppSettings["TaskffmpegNETExeFullPath"]; string _videoFileFullPath = @"D:\Workspace\TestVideo.mp4"; string _othereVideoFileFullPath = @"D:\Workspace\TestVideo{0}.mp4"; string snapshotParentDir = @"D:\Workspace\TestVideoSnapshot"; int exeMoreCrawlSnapshotCount = ; public ffmpegTest02()
{
base.InitForm();
InitializeComponent();
base.InitControls(this.listInfoLog);
} private void OnProgress(object sender, ConversionProgressEventArgs e)
{
ShowAndLog(string.Format("[{0} => {1}]", e.Input.FileInfo.Name, e.Output?.FileInfo.Name), false, null);
ShowAndLog(string.Format("Bitrate: {0}", e.Bitrate), false, null);
ShowAndLog(string.Format("Fps: {0}", e.Fps), false, null);
ShowAndLog(string.Format("Frame: {0}", e.Frame), false, null);
ShowAndLog(string.Format("ProcessedDuration: {0}", e.ProcessedDuration), false, null);
ShowAndLog(string.Format("Size: {0} kb", e.SizeKb), false, null);
ShowAndLog(string.Format("TotalDuration: {0}\n", e.TotalDuration), false, null);
} /// <summary>
/// 此事件短时间(比如:1秒以内)会调用多次
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnData(object sender, ConversionDataEventArgs e)
{
ShowAndLog(string.Format("[从源文件 {0} 到目标文件 {1}],数据 {2}", e.Input.FileInfo.Name, e.Output?.FileInfo.Name, e.Data),
false,
null);
} /// <summary>
/// 此事件短时间(比如:1秒以内)会调用多次
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnDataSimpleShow(object sender, ConversionDataEventArgs e)
{
ShowAndLog(string.Format("[从源文件 {0} 到目标文件 {1}]。", e.Input.FileInfo.Name, e.Output?.FileInfo.Name),
false,
null);
} private void OnComplete(object sender, ConversionCompleteEventArgs e)
{
ShowAndLog(string.Format("从 {0} 到 {1} 处理完成。 ", e.Input.FileInfo.FullName, e.Output?.FileInfo.FullName),
false,
null);
} private void OnError(object sender, ConversionErrorEventArgs e)
{
ShowAndLog(string.Format("[{0} => {1}]: 错误: {2}\n{3}", e.Input.FileInfo.Name, e.Output?.FileInfo.Name, e.Exception.ExitCode, e.Exception.InnerException),
false,
null);
} private IEnumerable<TimeSpan> CreateTimeSpanArray()
{
for (int i = ; i < ; i++)
{
yield return new TimeSpan(, i, );
}
} private ConversionOptions GetConversionOptions(TimeSpan tsItem)
{
return new ConversionOptions
{
Seek = tsItem,
//下面表示3行代码表示需要自定义截图的尺寸
VideoSize = VideoSize.Custom,
CustomWidth = , // 截图的宽度
CustomHeight = , // 截图的高度
FFmpegDrawTextArgs = string.Format("borderw=10:bordercolor=white:fontcolor=#A9A9A8:fontsize=100:fontfile=FreeSerif.ttf:text='{0}\\:{1}\\:{2}':x =(w-text_w-50):y=(h-text_h-50)",
tsItem.Hours.ToString().PadLeft(, ''),
tsItem.Minutes.ToString().PadLeft(, ''),
tsItem.Seconds.ToString().PadLeft(, '')
),
ExtraFFmpegArgs = " -y " // -y 表示目标文件已经存在,则覆盖输出文件
};
} private async void btnStartConvertAndSnapshot_Click(object sender, EventArgs e)
{
string mkvOutputFileFullPath = string.Format(@"D:\Workspace\TestVideo-{0}.mkv", DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"));
string mkvThumbOutputFileFullPath = string.Format(@"{0}\TestVideo-mkv-thumb-{1}.png", snapshotParentDir, DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"));
try
{
var inputFile = new MediaFile(_videoFileFullPath);
var outputFile = new MediaFile(mkvOutputFileFullPath);
var thumbNailFile = new MediaFile(mkvThumbOutputFileFullPath); var ffmpeg = new Engine(TaskffmpegNETExeFullPath);
//ffmpeg.Progress += OnProgress;
//ffmpeg.Data += OnDataSimpleShow;
ffmpeg.Error += OnError;
ffmpeg.Complete += OnComplete;
var output = await ffmpeg.ConvertAsync(inputFile, outputFile);
var thumbNail = await ffmpeg.GetThumbnailAsync(output, thumbNailFile, GetConversionOptions(TimeSpan.FromSeconds()));
var metadata = await ffmpeg.GetMetaDataAsync(output);
Console.WriteLine(metadata.FileInfo.FullName);
Console.WriteLine(metadata);
}
catch (Exception exc)
{
Console.WriteLine(exc);
}
} private async void btnGetVideoInfo_Click(object sender, EventArgs e)
{
ShowAndLog("ffmpeg 准备开始获取,请稍后...", false, null);
Stopwatch globalWatch = Stopwatch.StartNew();
var ffmpeg = new Engine(TaskffmpegNETExeFullPath);
//ffmpeg.Progress += OnProgress;
//ffmpeg.Data += OnDataSimpleShow;
ffmpeg.Error += OnError;
ffmpeg.Complete += OnComplete; var inputFile = new MediaFile(_videoFileFullPath);
MetaData md = await ffmpeg.GetMetaDataAsync(inputFile); ShowAndLog(string.Format("Duration:{0}", md.Duration), false, null);
ShowAndLog(string.Format("VideoData:{0}", JsonHelper.SerializeToJson(md.VideoData)), false, null);
ShowAndLog(string.Format("AudioData:{0}", JsonHelper.SerializeToJson(md.AudioData)), false, null); globalWatch.Stop();
ShowAndLog(string.Format("运行结束!共耗时 {0} 毫秒。", globalWatch.ElapsedMilliseconds), false, null); } private async void btnStartSingleSnapshot_Click(object sender, EventArgs e)
{
ShowAndLog("ffmpeg 准备开始转换,请稍后...", false, null);
Stopwatch globalWatch = Stopwatch.StartNew();
IEnumerable<TimeSpan> timeSpanArray = CreateTimeSpanArray();
var ffmpeg = new Engine(TaskffmpegNETExeFullPath);
//ffmpeg.Progress += OnProgress;
//ffmpeg.Data += OnDataSimpleShow;
ffmpeg.Error += OnError;
ffmpeg.Complete += OnComplete; var inputFile = new MediaFile(_videoFileFullPath); int i = ;
string mkvThumbOutputFileFullPath;
List<string> allThumbFullName = new List<string>();
foreach (TimeSpan tsItem in timeSpanArray)
{
i++;
mkvThumbOutputFileFullPath = string.Format(@"{0}\TestVideo-mp4-thumb-{1}-{2}.jpg", snapshotParentDir, DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss.fff"), i);
allThumbFullName.Add(mkvThumbOutputFileFullPath);
var thumbNailFile = new MediaFile(mkvThumbOutputFileFullPath);
await ffmpeg.GetThumbnailAsync(inputFile, thumbNailFile, GetConversionOptions(tsItem) );
}
ShowAndLog("ffmpeg 转换完成。结果如下:", false, null);
globalWatch.Stop();
ShowAndLog(string.Format("运行结束!共耗时 {0} 毫秒。", globalWatch.ElapsedMilliseconds), false, null);
} private async void btnParelleSyncStartMoreCrawlSnapshot_ClickAsync(object sender, EventArgs e)
{
ShowAndLog("准备开始同步多个 TestVideo{n}.mp4 上截图,请稍后...", false, null);
Stopwatch globalWatch = Stopwatch.StartNew(); for (int i = ; i < exeMoreCrawlSnapshotCount; i++)
{
await CreateSnapshotCoreAsync(i + );
}
ShowAndLog("同步多个 TestVideo{n}.mp4 上截图完成。结果如下:", false, null);
globalWatch.Stop();
ShowAndLog(string.Format("运行结束!共耗时 {0} 毫秒。", globalWatch.ElapsedMilliseconds), false, null);
} private async Task CreateSnapshotCoreAsync(int fileId)
{
IEnumerable<TimeSpan> timeSpanArray = CreateTimeSpanArray();
var ffmpeg = new Engine(TaskffmpegNETExeFullPath);
//ffmpeg.Progress += OnProgress;
//ffmpeg.Data += OnDataSimpleShow;
ffmpeg.Error += OnError;
ffmpeg.Complete += OnComplete; var inputFile = new MediaFile(string.Format(_othereVideoFileFullPath, fileId)); //_videoFileFullPath int i = ;
string mkvThumbOutputFileFullPath;
List<string> allThumbFullName = new List<string>();
foreach (TimeSpan tsItem in timeSpanArray)
{
i++;
mkvThumbOutputFileFullPath = string.Format(@"{0}\TestVideo{1}-mp4-thumb-{2}-{3}.jpg", snapshotParentDir, fileId, DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss.fff"), i);
allThumbFullName.Add(mkvThumbOutputFileFullPath);
var thumbNailFile = new MediaFile(mkvThumbOutputFileFullPath);
await ffmpeg.GetThumbnailAsync(inputFile, thumbNailFile, GetConversionOptions(tsItem));
}
} private async void btnParelleAsyncStartMoreCrawlSnapshot_ClickAsync(object sender, EventArgs e)
{
ShowAndLog("准备开始异步并行多个 TestVideo{n}.mp4 上截图,请稍后...", false, null);
Stopwatch globalWatch = Stopwatch.StartNew(); var tasks = Enumerable.Range(, exeMoreCrawlSnapshotCount).Select(i =>
{
return Task.Run(async () =>
{
await CreateSnapshotCoreAsync(i + );
});
});
await Task.WhenAll(tasks);
ShowAndLog("异步并行多个 TestVideo{n}.mp4 上截图完成。结果如下:", false, null);
globalWatch.Stop();
ShowAndLog(string.Format("运行结束!共耗时 {0} 毫秒。", globalWatch.ElapsedMilliseconds), false, null);
} private async void btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop_Click(object sender, EventArgs e)
{
ShowAndLog("准备开始异步并行多个 TestVideo{n}.mp4 上截图(限制最大异步处理单元),请稍后...", false, null);
Stopwatch globalWatch = Stopwatch.StartNew();
var tasks = Enumerable.Range(, exeMoreCrawlSnapshotCount).ParallelForEachAsync(i =>
{
return Task.Run(async () =>
{
await CreateSnapshotCoreAsync(i + );
});
}, Environment.ProcessorCount);
await Task.WhenAll(tasks);
ShowAndLog("异步并行多个 TestVideo{n}.mp4 上截图(限制最大异步处理单元)完成。结果如下:", false, null);
globalWatch.Stop();
ShowAndLog(string.Format("运行结束!共耗时 {0} 毫秒。", globalWatch.ElapsedMilliseconds), false, null);
}
}

ffmpegTest02.Designer.cs

    partial class ffmpegTest02
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null; /// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
} #region Windows Form Designer generated code /// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btnStartConvertAndSnapshot = new System.Windows.Forms.Button();
this.listInfoLog = new System.Windows.Forms.ListBox();
this.btnStartSingleSnapshot = new System.Windows.Forms.Button();
this.btnGetVideoInfo = new System.Windows.Forms.Button();
this.btnParelleSyncStartMoreCrawlSnapshot = new System.Windows.Forms.Button();
this.btnParelleAsyncStartMoreCrawlSnapshot = new System.Windows.Forms.Button();
this.btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// btnStartConvertAndSnapshot
//
this.btnStartConvertAndSnapshot.Location = new System.Drawing.Point(, );
this.btnStartConvertAndSnapshot.Name = "btnStartConvertAndSnapshot";
this.btnStartConvertAndSnapshot.Size = new System.Drawing.Size(, );
this.btnStartConvertAndSnapshot.TabIndex = ;
this.btnStartConvertAndSnapshot.Text = "1. 开始先把 TestVideo.mp4 转换 mkv,再在第 1 分钟的时候截图";
this.btnStartConvertAndSnapshot.UseVisualStyleBackColor = true;
this.btnStartConvertAndSnapshot.Click += new System.EventHandler(this.btnStartConvertAndSnapshot_Click);
//
// listInfoLog
//
this.listInfoLog.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.listInfoLog.Font = new System.Drawing.Font("宋体", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)()));
this.listInfoLog.FormattingEnabled = true;
this.listInfoLog.HorizontalScrollbar = true;
this.listInfoLog.Location = new System.Drawing.Point(, );
this.listInfoLog.Name = "listInfoLog";
this.listInfoLog.ScrollAlwaysVisible = true;
this.listInfoLog.Size = new System.Drawing.Size(, );
this.listInfoLog.TabIndex = ;
//
// btnStartSingleSnapshot
//
this.btnStartSingleSnapshot.Location = new System.Drawing.Point(, );
this.btnStartSingleSnapshot.Name = "btnStartSingleSnapshot";
this.btnStartSingleSnapshot.Size = new System.Drawing.Size(, );
this.btnStartSingleSnapshot.TabIndex = ;
this.btnStartSingleSnapshot.Text = "2. 不转码,直接在第 1分钟的时候从 TestVideo.mp4 上截图";
this.btnStartSingleSnapshot.UseVisualStyleBackColor = true;
this.btnStartSingleSnapshot.Click += new System.EventHandler(this.btnStartSingleSnapshot_Click);
//
// btnGetVideoInfo
//
this.btnGetVideoInfo.Location = new System.Drawing.Point(, );
this.btnGetVideoInfo.Name = "btnGetVideoInfo";
this.btnGetVideoInfo.Size = new System.Drawing.Size(, );
this.btnGetVideoInfo.TabIndex = ;
this.btnGetVideoInfo.Text = "3. 仅仅获取 TestVideo.mp4 视频的信息";
this.btnGetVideoInfo.UseVisualStyleBackColor = true;
this.btnGetVideoInfo.Click += new System.EventHandler(this.btnGetVideoInfo_Click);
//
// btnParelleSyncStartMoreCrawlSnapshot
//
this.btnParelleSyncStartMoreCrawlSnapshot.Location = new System.Drawing.Point(, );
this.btnParelleSyncStartMoreCrawlSnapshot.Name = "btnParelleSyncStartMoreCrawlSnapshot";
this.btnParelleSyncStartMoreCrawlSnapshot.Size = new System.Drawing.Size(, );
this.btnParelleSyncStartMoreCrawlSnapshot.TabIndex = ;
this.btnParelleSyncStartMoreCrawlSnapshot.Text = "4. 同步多个 TestVideo{n}.mp4 上截图";
this.btnParelleSyncStartMoreCrawlSnapshot.UseVisualStyleBackColor = true;
this.btnParelleSyncStartMoreCrawlSnapshot.Click += new System.EventHandler(this.btnParelleSyncStartMoreCrawlSnapshot_ClickAsync);
//
// btnParelleAsyncStartMoreCrawlSnapshot
//
this.btnParelleAsyncStartMoreCrawlSnapshot.Location = new System.Drawing.Point(, );
this.btnParelleAsyncStartMoreCrawlSnapshot.Name = "btnParelleAsyncStartMoreCrawlSnapshot";
this.btnParelleAsyncStartMoreCrawlSnapshot.Size = new System.Drawing.Size(, );
this.btnParelleAsyncStartMoreCrawlSnapshot.TabIndex = ;
this.btnParelleAsyncStartMoreCrawlSnapshot.Text = "5. 异步并行多个 TestVideo{n}.mp4 上截图";
this.btnParelleAsyncStartMoreCrawlSnapshot.UseVisualStyleBackColor = true;
this.btnParelleAsyncStartMoreCrawlSnapshot.Click += new System.EventHandler(this.btnParelleAsyncStartMoreCrawlSnapshot_ClickAsync);
//
// btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop
//
this.btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop.Location = new System.Drawing.Point(, );
this.btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop.Name = "btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop";
this.btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop.Size = new System.Drawing.Size(, );
this.btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop.TabIndex = ;
this.btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop.Text = "6. 异步并行多个 TestVideo{n}.mp4 上截图(限制最大异步处理单元)";
this.btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop.UseVisualStyleBackColor = true;
this.btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop.Click += new System.EventHandler(this.btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop_Click);
//
// ffmpegTest02
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(, );
this.Controls.Add(this.btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop);
this.Controls.Add(this.btnParelleAsyncStartMoreCrawlSnapshot);
this.Controls.Add(this.btnParelleSyncStartMoreCrawlSnapshot);
this.Controls.Add(this.btnGetVideoInfo);
this.Controls.Add(this.btnStartSingleSnapshot);
this.Controls.Add(this.listInfoLog);
this.Controls.Add(this.btnStartConvertAndSnapshot);
this.Name = "ffmpegTest02";
this.Text = "ffmpegTest02";
this.ResumeLayout(false); } #endregion private System.Windows.Forms.Button btnStartConvertAndSnapshot;
private System.Windows.Forms.ListBox listInfoLog;
private System.Windows.Forms.Button btnStartSingleSnapshot;
private System.Windows.Forms.Button btnGetVideoInfo;
private System.Windows.Forms.Button btnParelleSyncStartMoreCrawlSnapshot;
private System.Windows.Forms.Button btnParelleAsyncStartMoreCrawlSnapshot;
private System.Windows.Forms.Button btnParelleAsyncStartMoreCrawlSnapshotLimitMaxDop;
}

运行结果

图 01

图 02

图 03

图 04

图 05

图 06

图 07

图 08

谢谢浏览!

如何让 FFmpeg 支持异步并行转码、截图等等操作?的更多相关文章

  1. Java Web 中使用ffmpeg实现视频转码、视频截图

    Java Web 中使用ffmpeg实现视频转码.视频截图 转载自:[ http://www.cnblogs.com/dennisit/archive/2013/02/16/2913287.html  ...

  2. windows下使用ffmpeg进行视频转换和截图。

    author:fanfq(xiaoban) Email:fangqing.fan#gmail.comlink:http://fanfq.iteye.com/admin/blogs/655569chan ...

  3. C# 使用 ffmpeg 进行音频转码

    先放一下 ffmpeg 的官方文档以及下载地址: 官方文档:http://ffmpeg.org/ffmpeg.html 下载地址:http://ffmpeg.org/download.html 用 f ...

  4. FFmpeg:视频转码、剪切、合并、播放速调整

    原文:https://fzheng.me/2016/01/08/ffmpeg/ FFmpeg:视频转码.剪切.合并.播放速调整 2016-01-08 前阵子帮导师处理项目 ppt,因为插入视频的格式问 ...

  5. 使用ffmpeg.exe进行转码参数说明

    使用ffmpeg.exe进行转码参数说明 摘自:https://blog.csdn.net/coloriy/article/details/47337641 2015年08月07日 13:04:32  ...

  6. ubuntu系统下安装gstreamer的ffmpeg支持

    当您在安装gstreamer到您的ubuntu系统中时,为了更好地进行流媒体开发,需要安装ffmpeg支持,但一般情况下,直接使用 sudo apt-get install gstreamer0.10 ...

  7. [IBM][CLI Driver] SQL0270N 函数不受支持(原因码:"75")。 SQLSTATE=42997

    db2 update dbm cfg  using FEDERATED  yes 与 自动维护 (AUTO_MAINT) = ON 自动数据库备份 (AUTO_DB_BACKUP) = OFF 自动表 ...

  8. Python3选择支持非ASCII码标识符的缘由

    原文在: PEP 3131 -- Supporting Non-ASCII Identifiers. Python2并不支持非ASCII码标识符. PEP的全称是Python Enhancement ...

  9. API Studio 5.1.2 版本更新:加入全局搜索、支持批量测试API测试用例、读取代码注解生成文档支持Github与码云等

    最近在EOLINKER的开发任务繁重,许久在博客园没有更新产品动态了,经过这些日子,EOLINKER又有了长足的进步,增加了更多易用的功能,比如加入全局搜索.支持批量测试API测试用例.读取代码注解生 ...

随机推荐

  1. 给HttpClient添加请求头(HttpClientFactory)

    前言 在微服务的大环境下,会出现这个服务调用这个接口,那个接口的情况.假设出了问题,需要排查的时候,我们要怎么关联不同服务之间的调用情况呢?换句话就是说,这个请求的结果不对,看看是那里出了问题. 最简 ...

  2. Z从壹开始前后端分离【 .NET Core2.2/3.0 +Vue2.0 】框架之六 || API项目整体搭建 6.1 仓储+服务+抽象接口模式

    本文梯子 本文3.0版本文章 前言 零.完成图中的粉色部分 2019-08-30:关于仓储的相关话题 一.创建实体Model数据层 二.设计仓储接口与其实现类 三.设计服务接口与其实现类 四.创建 C ...

  3. Z从壹开始前后端分离【 .NET Core2.2/3.0 +Vue2.0 】框架之五 || Swagger的使用 3.3 JWT权限验证【必看】

    本文梯子 本文3.0版本文章 前言 1.如何给接口实现权限验证? 零.生成 Token 令牌 一.JWT ——自定义中间件 0.Swagger中开启JWT服务 1:API接口授权策略 2.自定义认证之 ...

  4. java基础(11):接口、多态

    1. 接口 1.1 接口概念 接口是功能的集合,同样可看做是一种数据类型,是比抽象类更为抽象的”类”. 接口只描述所应该具备的方法,并没有具体实现,具体的实现由接口的实现类(相当于接口的子类)来完成. ...

  5. SpringCloud之API网关与服务发现——Cloud核心组件实战入门及原理

    微服务发展历史 单体模式——>服务治理(服务拆分)——>微服务(细分服务)——>Segments(服务网格) 微服务 VS SOA 微服务:模块化.独立部署.异构化 SOA:共同的治 ...

  6. CSS的border-radius 设置圆弧

    现象:将div变为有一定幅度的圆形.椭圆形等 方法:使用css的border-radius 属性进行设置CSS3 border-radius 属性:向 div 元素添加圆角边框: 一:首先建立一个di ...

  7. Tasteless challenges medium WP

    http://chall.tasteless.eu/ 国外的一个靶场,都是单点知识,medium大部分还是比较简单 medium Level 1- Infiltration http://chall. ...

  8. 【转载】Gradle for Android 第四篇( 构建变体 )

    当你在开发一个app,通常你会有几个版本.大多数情况是你需要一个开发版本,用来测试app和弄清它的质量,然后还需要一个生产版本.这些版本通常有不同的设置,例如不同的URL地址.更可能的是你可能需要一个 ...

  9. Android框架Volley使用:Post请求实现

    首先我们在项目中导入这个框架: implementation 'com.mcxiaoke.volley:library:1.0.19' 在AndroidManifest文件当中添加网络权限: < ...

  10. 剑指offer 20:顺时针打印矩阵

    题目描述 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数 ...