一个音乐软件制作记录

administrator 1,867 10
温馨提示

代码里的类库如果我没有给出说明那是一个自带的组件,自己去找。
如果有任何看不懂的部分请下面评论,谢谢支持!我会解释的。

源码已发布:请于文章底部下载源码。

最近好像没啥需要出的教程,那我自己搞一个,一直想搞个音乐app,正好顺便录教程[斜眼笑]

其实做这个app我搞了2年E4A的人也要踩不少坑的,知道你们喜欢看这(别)些(人)玩(的)意(痛)儿(苦),所以我也一并记上[偷笑]玩笑开到这,其实这个应该也有点用,所以才写,自己体会吧。

准备工作

做之前准备一下,确定数据源,做UI构思。

内容源简单,我就有个音乐网站,全免费的,网址是http://music.eeras.cn这个站源码需要得话请到作者博客去找,需要的可以点击下面的按钮去看看:

点击跳转

UI嘛,这个网站本来就带一个手机版,看了一下也不错,如图:

一个音乐软件制作记录

点击查看更多图片

所以UI就搞个类似的好(毕竟是玩玩嘛,像这样的软件拿出去发布也不好吧,尊重版权啊,我们学学练练手不错[笑哭]),上面是个tab切换,这个之前做过,另外主题配色直接黑白,简单粗暴有没有[呲牙]

大体框架设计

按照上面的构思来,我们在可视化那块直接搞这些:

一个音乐软件制作记录

如上图,tab实现就用个类库吧,需要下载可以点下面:

点击下载

一个音乐软件制作记录

这里搞个编辑框留着编写过程中调试的时候输出测试。

另外还有个很重要的东西,如图:

一个音乐软件制作记录

根据我多年的经验(其实就两年啦[小纠结])所谓的material风格在android 5以上系统上要好看不少,另外沉浸模式也要开,下面代码需要这个的支持,注意咯!

一个音乐软件制作记录

这个地方设置主窗口的背景成淡灰色,衬托我们大量采用白色的布局。

UI光这么写肯定不可以的,不好看,代码也要来两下子做个辅助,如图:

一个音乐软件制作记录

上面我尽可能的做了一些注释,另外解释下接口函数这个玩意,这玩意用的是android原生代码,可以实现那些E4A无法实现但android原生代码可以实现的功能,这个学过类库开发或者学过android原生的人可以看得懂。

点击查看我在这里踩的坑

好吧,踩了个坑,总算搞定,上演示:

一个音乐软件制作记录

这个额,还算看的过去[委屈]

分析网页数据调用方法

为了把网页数据调用过来就要分析网页数据调用方法咯,这个就是抓包分析了,分析post之类的。

首先我们软件上布局再做下一步的计划,我打算在“播放列表”添加如图所示几个歌单:

一个音乐软件制作记录

先分析这几个内容的源,我们可以看下post的结果里面有没有和这个相关的内容:

一个音乐软件制作记录

我们在网页按下F12键打开调试,再按F5刷新下网页,内容就出来了,将选项卡切换到如上图所示的XHR选项,里面就是POST内容了,我们打开逐个看,内容如上图Response是我们的返回包,内容可以看到是一个json文本,里面出现了一些曲名,我们发现是如下图所示的表单数据源,这个留着,待会有用。

一个音乐软件制作记录

经过上面的分析,我们并没有发现有歌单封面图片地址的返回包,所以我们猜测这些歌单图片是写在源码里的,我们可以直接取,看调试中img资源监测可以看到这些图片确实是预先写好的:

一个音乐软件制作记录

这个图片我们可以顺利得到它的地址,到现在我们已经拿到歌单的图片了,在软件里面写上去并不难,接下来要实现点击这个图片能加载如下歌单:

一个音乐软件制作记录

这个我们上面已经分析出了它的数据源,现在我们来分析一下这条post的具体内容。

首先,我们切换到刚刚的这个post记录,点击head选项卡,这里展示的是这个post的http头数据,看下里面都有什么好吃的:

一个音乐软件制作记录

这里面有如下几个参数:

Request URL:请求的地址

Cookie:饼干?这个其实是缓存数据,可以用于识别用户,大部分网页在刷新的时候并不要输入账号密码,这个功能一般靠他,简言之一般此饼干是用来记录权限的[饥饿]也不知道是哪个吃货想出来的[笑哭]

另外有个项目:

From Data:这个项目里面记录的是上传的数据,可以看到分别是types:playlist;id:3778678。types一般指的类型,playlist应该是播放列表(我英语渣渣[冷汗]应该是这样的)。id好说,大家都知道,歌单id嘛,id我们等下能用到,因为我们的ui界面上会写出几个歌单的封面,用户点击的时候我们可以通过id知道用户点的是哪个歌单,从而推送正确的歌单列表。

为了验证我们上面的分析是否正确我们可以试试看,直接找个网页版的post调试工具,百度搜就可以了,测试效果如下图:

一个音乐软件制作记录

设计歌单页面

上面我们已经对歌单要用的数据进行了抓包分析,接下来应该将其应用于软件了。

首先要解决的问题还是布局,我打算用垂直滚动框,这样一来我们就能够自由设计我们的列表了。

首先我们来添加一个垂直滚动框,如下图:

一个音乐软件制作记录

然后上面我打算用按钮做出来图片的效果,标签做出标题的效果,就像如下图所示的网页一样:

一个音乐软件制作记录

我们来了解一下垂直滚动框的用法,官方例程库里就有,如下图:

一个音乐软件制作记录

一个音乐软件制作记录

一个音乐软件制作记录

打开垂直滚动框例程,我们可以看到它的代码写法:

第一步:先创建一个变量,按钮型变量?想不到吧[斜眼笑]其实我估计是对象型变量,毕竟java可没有按钮型变量;

第二步:创建一个位于垂直滚动框的按钮,将其赋值给刚刚的按钮型变量;

第三步:让按钮移动到指定的位置,这里的坐标原点应该是垂直滚动框的左上角吧(悄悄告诉你android原生编程里你还可以吧原点坐标设置成任意一个角,很强大,有没有[doge]);

第四步:对齐方式,这个似乎是按钮文字的对齐方式。

第五步:标题,也就是按钮显示的文字信息;

第六步:置组件索引,这玩意是给下面事件监听器做识别的;

第七部:监听事件,我们利用事件监听器来监听按钮按下的动作。

还挺复杂[惊讶]不过要相信自己能行[呲牙]

重点提示

这里添加到垂直滚动框的组件必须在可视化设计中插入,即如果要用到按钮插入垂直滚动框我们就需要在可视化页面画上一个按钮,然后把它藏起来,没错,藏起来[笑哭]如果不这么做你会发现例如上面写的按钮型变量会提示出错。

看完了例程我们自由发挥了[饥饿]

因为按钮等下我们会用在垂直滚动框,而我们之前没有使用按钮,所以我们新建一个。

一个音乐软件制作记录

接下来我们做个歌单封面布局:

关于歌单布局,我又踩了个坑

因为又踩了个坑[委屈]所以做一些调整,最后的代码算法是这样的:

代码太长,点击展开

这里我就没有改动垂直方向的布局方案,只是改动了水平方向上的,这样就可以放下标题了,如下图所示最终效果:

一个音乐软件制作记录

歌单封面OK,接下来歌单内容页,先去写点击事件,点击之后进行post得到数据:

一个音乐软件制作记录

我们先加一个变量,叫取源码命令头,因为我们要多次取源码,这样弄只要一个多线程的组件就能搞定了。

然后我们看一下取到的数据:

一个音乐软件制作记录

因为原json文本太长了我就没放原文(我刚刚尝试放原文,浏览器卡崩溃了[流泪]),上图是格式化的json视图,很显然这样的数据我们没法直接用,我们要对其进行多级处理,首先我们找到我们要取的数据:

一个音乐软件制作记录

我们可以看到我们要取的数据在这个位置(最下面的红框),可以很清楚看到层级关系,这里每一个层级都是json文本,第一层json的键为:playlist,第二层为:tracks,这里需要注意因为这个歌单有200首歌,所以数据上是以数组型出现的,所以代码写法如下:

变量 一次处理 为 文本型 = 子文本替换(结果,"jQuery111308577676114104071_1530350870530(","")
变量 二次处理 为 文本型 = 子文本替换(一次处理,")","")
提示

这里不要用取指定文本2,该函数对大数据文本反应慢,易出错。

原文里面写的是jQuery111308577676114104071_1530350870530({里面是合法json})

这里我们处理掉返回数据的非json部分,将其转化为合法json,下面我们对其解析:

变量 三次处理 为 文本型 = JSON解析(二次处理,"","playlist",1)

我们取出的是playlist键对应的json,下面我们要取的json是一个数组型,所以换一个命令,用一个类库:

一个音乐软件制作记录

然后键入如下指令:

JSON操作_数据处理.取数组内文本值(JSON操作_数据处理.取数组(JSON操作_数据处理.解析(三次处理),"tracks"),0)

我们这里就取出了tracks键下的json,因为它是数组型,所以此次解析完毕返回的将是文本型数组,即文本型()我们将其调试一下看看效果:

一个音乐软件制作记录

编译,安装试试:

一个音乐软件制作记录

如果要取出歌名,写如下代码:

编辑框1.内容 = JSON解析( JSON操作_数据处理.取数组内文本值(JSON操作_数据处理.取数组(JSON操作_数据处理.解析(三次处理),"tracks"),0),"","name" ,1)

我们看下运行效果:

一个音乐软件制作记录

剩下的取图片链接、取音乐id之类的同理了。

上面把整个歌单内容页数据分析大概的理了一遍,现在可以重构一下代码,因为别写别录教程影响思路所以代码我写好了,我把全部代码我发一下,然后带着大家整理思路:

点击查看代码

我们分析一下上面的代码,我就站在用户操作流程的角度剖析代码吧:

首先是用户来点击这些项目:

一个音乐软件制作记录

我们需要在用户点下其中一个项目后加载一个表单,所以我们要加个判断,另外我们如何知道用户点击了项目靠的是事件监听器。所以我们写如下代码:

事件 事件监听器_监听列表.被单击(组件索引 为 整数型)
	判断 组件索引
		分支 0
			取源码命令头 = "取歌单内容"
			多线程_数据用.开始发送网络数据("http://music.eeras.cn/music/api.php?callback=jQuery111308577676114104071_1530350870530","types=playlist&id=3778678","UTF-8")
		分支 1
			取源码命令头 = "取歌单内容"
			多线程_数据用.开始发送网络数据("http://music.eeras.cn/music/api.php?callback=jQuery111308577676114104071_1530350870530","types=playlist&id=3779629","UTF-8")
		分支 2
			取源码命令头 = "取歌单内容"
			多线程_数据用.开始发送网络数据("http://music.eeras.cn/music/api.php?callback=jQuery111308577676114104071_1530350870530","types=playlist&id=4395559","UTF-8")
		分支 3
			取源码命令头 = "取歌单内容"
			多线程_数据用.开始发送网络数据("http://music.eeras.cn/music/api.php?callback=jQuery111308577676114104071_1530350870530","types=playlist&id=64016","UTF-8")
		分支 4
			取源码命令头 = "取歌单内容"
			多线程_数据用.开始发送网络数据("http://music.eeras.cn/music/api.php?callback=jQuery111308577676114104071_1530350870530","types=playlist&id=112504","UTF-8")
		分支 5
			取源码命令头 = "取歌单内容"
			多线程_数据用.开始发送网络数据("http://music.eeras.cn/music/api.php?callback=jQuery111308577676114104071_1530350870530","types=playlist&id=19723756","UTF-8")
		分支 6
			取源码命令头 = "取歌单内容"
			多线程_数据用.开始发送网络数据("http://music.eeras.cn/music/api.php?callback=jQuery111308577676114104071_1530350870530","types=playlist&id=2884035","UTF-8")
	结束 判断
	显示进度对话框("正在加载列表...")
结束 事件

我们分析一下这段,上面判断的是组件的索引,分支 0 的意思是如果组件索引=0 的话我们就加载后面的代码。这里的组件索引写的就是垂直滚动框的歌单封面的两个控件(分别是图片框、标签)的索引,上面的代码我们指定了它的索引,如下代码:

变量 按钮宽高 为 整数型 = 取屏幕宽度() * ( 20 / 78 )
	
	变量 项目1 为 按钮
	项目1 = 创建 按钮 位于 垂直滚动框_列表用
	项目1.移动(按钮宽高 * ( 1 / 5 ) ,按钮宽高 * ( 1 / 5 ),按钮宽高,按钮宽高)
	项目1.图片 = "rgb.jpg"
	项目1.置组件索引(0)
	项目1.绑定事件(事件监听器_监听列表)
	
	变量 项目1标题 为 标签
	项目1标题 = 创建 标签 位于 垂直滚动框_列表用
	项目1标题.移动(按钮宽高 * ( 1 / 5 ) ,按钮宽高 * ( 1 / 5 ) + 按钮宽高,按钮宽高,按钮宽高 * ( 1 / 4 ) )
	项目1标题.标题 = "热歌榜"
	项目1标题.置组件索引(0)
	项目1标题.绑定事件(事件监听器_监听列表)
	项目1标题.对齐方式 = 靠中居中

我们在这段代码里面绑定了组件索引,并且这段代码控制了新歌榜封面的生成。

我们结合这两段代码就能知道我点击新歌榜的封面的时候会加载 分支 0 下的代码,我们分析一下 分支 0
下的代码:

取源码命令头 = "取歌单内容"
多线程_数据用.开始发送网络数据("http://music.eeras.cn/music/api.php?callback=jQuery111308577676114104071_1530350870530","types=playlist&id=3778678","UTF-8")

我们可以看到上面有个 取源码命令头 = "取歌单内容" ,取源码命令头 是一个在代码的第1行申明的一个文本型全局变量,这样写的好处是我们可以知道取源码取完了取得是什么东西的源码,因为我们一个软件显然不会只取一次源码,说白了我们加这个的目的是为了区分取回的源码是干嘛的,我也看过大家写的源码,部分兄弟的源码里有 多线程1、多线程2、多线程3、多线程n... ...通过这个办法就可以只用一个多线程搞定多次取源码了。其实这个我之前的教程里讲过的。

然后是第二句里面写到了 多线程_数据用.开始发送网络数据("http://music.eeras.cn/music/api.php?callback=jQuery111308577676114104071_1530350870530","types=playlist&id=3778678","UTF-8") 这一句,这一句就是取得歌单的网络数据源码,取回的是json,上面数据分析的时候我说过的,然后值得注意的是我哪里创建的7个歌单都是这一个接口,也就是 http://music.eeras.cn/music/api.php?callback=jQuery111308577676114104071_1530350870530 这一段,区分歌单的是id,也就是id=3778678,types=playlist&id=3778678 这一句就是昨天写的post参数了,分开就是types=playlist、id=3778678两个参数。

上面这一句判断就可以搞定数据源了,我们点击其中一个歌单封面接下来就要构建歌单项目的列表了,如下代码:

        变量 记次 为 整数型
	变量 歌单项目高 为 整数型
	变量 歌单顶边 为 整数型
	变量 三次处理 为 文本型
事件 多线程_数据用.发送网络数据完毕(结果 为 文本型)
	判断 取源码命令头
		分支  "取歌单内容"
			歌单顶边 = 0
			变量 一次处理 为 文本型 = 子文本替换(结果,"jQuery111308577676114104071_1530350870530(","")'[1]
			变量 二次处理 为 文本型 = 子文本替换(一次处理,")","") '[1]和这一句处理掉返回数据中非json的部分,得到合法json
			三次处理 = JSON解析(二次处理,"","playlist",1)'这一句取出上面得到的json,取出包含的json,得到包含歌单信息的json
			
			歌单项目高 = 垂直滚动框_列表用.高度 / 10
			垂直滚动框_列表用.清空组件()
			图片下载器_公用.初始化下载引擎(R.icon,R.icon,R.icon,0,真)
			变量循环首 记次 = 0 至 JSON操作_数据处理.取数组内成员数(JSON操作_数据处理.取数组(JSON操作_数据处理.解析(三次处理),"tracks")) - 1
				创建歌单()
				歌单顶边 = 歌单顶边 + 歌单项目高 + 1
			变量循环尾
			关闭进度对话框()
			页面状态 = "歌单展示"
	结束 判断
结束 事件

这一段就是紧接着判断那段之后执行的,在判断那段代码运行到多线程.发送网络数据结束时被调用。首先被执行的是:

变量 一次处理 为 文本型 = 子文本替换(结果,"jQuery111308577676114104071_1530350870530(","")'[1]
变量 二次处理 为 文本型 = 子文本替换(一次处理,")","") '[1]和这一句处理掉返回数据中非json的部分,得到合法json
三次处理 = JSON解析(二次处理,"","playlist",1)'这一句取出上面得到的json,取出包含的json,得到包含歌单信息的json

这里就是对刚刚上面返回的json进行处理了,上面有注释,自己看吧[得意]

json你们看着我的代码处理分析一下应该没问题了,只要记住json的话一堆黏在一起就把它一个一个的分开,如果是一坨数组的话我们就把它当数组处理。

接下来我们就把刚刚摆着歌单封面的桌子(垂直滚动框)清空,摆上歌单内容列表,所以代码来一句 垂直滚动框_列表用.清空组件() 然后我们的歌单内容列表是要加载图片的,我们可视化设计画上一个图片下载器,我们这里要初始化,所以有了 图片下载器_公用.初始化下载引擎(R.icon,R.icon,R.icon,0,真)

这段代码最后会循环加载过程 创建歌单(),这里值得注意的是如下这句代码:

变量循环首 记次 = 0 至 JSON操作_数据处理.取数组内成员数(JSON操作_数据处理.取数组(JSON操作_数据处理.解析(三次处理),"tracks")) - 1
	创建歌单()
	歌单顶边 = 歌单顶边 + 歌单项目高 + 1
变量循环尾

这里我们主要是进行了一个循环命令,利用记次这个变量来监控,一开始我们令它=0,然后取得歌单的项目数,让它加载数=歌单项目数,因为是从0开始的,所以结束应该是 JSON操作_数据处理.取数组内成员数(JSON操作_数据处理.取数组(JSON操作_数据处理.解析(三次处理),"tracks")) - 1 注意-1。

接着代码里展示了资源获取方法以及布局实现算法,大家对着源码研究吧。

这里我们测试过,出现了一个小问题:因为一次加载了200项,所以我们在这里加载会非常卡,所以我们还要优化加载过程,让它一次载入20项。我还是放一张此次测试的截图吧:

一个音乐软件制作记录

怎么样?看起来还顺眼吧?只是看了代码的你们肯定明白这个屏幕上的每一个像素都是算好了的,做项目用心搞就可以了,不要太逼着自己配色啊配背景图啊,随意透着不随意就好了。

有人可能想问我后面那个三点状图标哪搞的?其实那是我截屏了某个软件然后抠出来的[笑哭]才不想ps自己画呢,多麻烦,况且我电脑还很卡[流泪]如果你们要在下面了:

点击查看隐藏内容

因为我这种写法,每次匹配200项,如果每一项都加载写真的话会很卡,因为这些写真都是高清图片,加载很占时间也很耗流量,因为太卡,所以我们无奈把它取消了,现在是这样的:

一个音乐软件制作记录

这样一来,可以将原本十秒加载出来缩短一些。

好了,下面的步骤就是构建播放按钮、控制按钮、歌词、写真之类的,这个算起来略微麻烦,原理同上面的布局一样,代码做一下算法布局。素材我们还是从小米音乐抠图[笑哭]

我来说一下歌词吧,歌词这一块麻烦一点,我是用的标签和时钟来构建的,效果如下图:

一个音乐软件制作记录

我们可以做到歌词跟着进度滚动,实现原理大概为:

我们取到歌词文本,是如下这样的:

点击查看歌词文本

可以看到,源数据已经标出了时间,我们用时钟逐秒扫描,然后讲合适的歌词标出来,下一句歌词匹配那就下滚一下。代码大致为:

点击查看代码

这里只粘贴了部分代码,这样写是有缺陷的,调整播放进度歌词没法切换,所以,我还需要改这些代码。

上面的歌词处理模块存在缺陷,所以抽空重写了这个模块,现在歌词这块没有什么BUG了,源码也将公开在下面。

这个软件就开发到这里吧,最后一次开源搜索写好了,还有些小bug我也不准备搞了,主要是这个项目并非运营项目,只是作为练手,就写到这也可以防止某些人拿去卖钱(这就是为什么淘宝上卖的游戏服务端基本不会十全十美的[偷笑])

第三次开源

从第3次开源开始我还是写点记录吧,省得自己都不知道更新了什么[流汗]

本次开源更新内容:

再次更新歌词算法,修复第三次开源未发现bug一个

完成播放切换从正在播放可以切换出来到歌单重选歌曲

完成单曲循环的开发

下次开源预报:

完成列表循环

可能会完成搜索模块

另外感谢来自@天朝渣渣 提供的版本,此版本已完成搜索、循环,但bug多,也有研究价值,大家可以在下面下载。在这里也希望更多人能参与开发,谢谢!

第四次开源

这是最后一次更新(除非哪天我还有兴致搞[笑哭])最近都比较忙,是时候做个了结了。

下载区

点击下载第一次开源源码 点击下载第二次开源源码 点击下载@天朝渣渣提供的版本 点击下载第三次开源源码 点击下载第四次开源源码

 

打赏
发表评论
表情 图片 链接 代码

  1. F
    F Lv 1

    求发源码

  2. 鱼柒childe
    鱼柒childe Lv 1

    看完了,学到了新的写法,写的不错,新建变量 取源码命令头这种写法新颖

  3. 分享君
    分享君 Lv 1

    辛苦了 大佬

  4. 诺言
    诺言 Lv 1

    博主里的

    变量 一次处理 为 文本型 = 子文本替换(结果,"jQuery111308577676114104071_1530350870530(","")
    变量 二次处理 为 文本型 = 子文本替换(一次处理,")","")

    这个完全没必要。。。

    POST访问的Url
    由 :http://music.eeras.cn/music/api.php?callback=jQuery111308577676114104071_1530350870530

    改为 http://music.eeras.cn/music/api.php

    即可!!

分享
微信
微博
QQ