最近在做一个音乐播放器的项目,之前实现了解码播放本地音乐,那怎么获取网络音乐呢?就图个省事直接调用第三方的api了,下面码一下我的调用部分的代码:
一、请求URL
首先是发送请求URL,这里用TextField去动态的拼接成完整的请求URL
TextField{
id:searchtxt
......
placeholderText:"输入查找歌曲"
font.pixelSize: 15
leftPadding:50
property string api: "https://xxxxxx/music/xxx?word=" //空参数的请求URL
function search(){
var url=searchtxt.api+encodeURIComponent(searchtxt.text) //将输入字符作为参数拼接成完整URL
netmsc.netmusicrequest(url) //发出带参数url的信号,通知后端处理数据
}
Keys.onReturnPressed: { //Enter后搜索
searchtxt.search()
}
}
二、后端发送请求并处理数据
前端发出带URL的信号,交由c++后端来发送URL请求获取并处理数据
//netmusic.h
#ifndef NETMUSIC_H
#define NETMUSIC_H
#include <QObject>
#include <QNetworkAccessManager>
#include <QNetworkReply>
class NetMusic : public QObject
{
Q_OBJECT
public:
explicit NetMusic(QObject *parent = nullptr);
Q_INVOKABLE void getnetmusic(const QString &url); //用QML发来的url去发送请求
signals:
void netresready(const QVariantList &data); //处理完毕
void neterror(const QString &error); //处理失败
public slots:
void netreplyready(QNetworkReply *reply); //已收到返回的JSON文件,开始处理数据
private:
QNetworkAccessManager *manager; //网络请求管理器
};
#endif // NETMUSIC_H
//netmusic.cpp
#include "netmusic.h"
#include <QDebug>
#include <QVariant>
#include <QVariantList>
#include <QThread>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
NetMusic::NetMusic(QObject *parent)
: QObject{parent}
{
manager=new QNetworkAccessManager(this); //创建网络管理器
connect(manager,&QNetworkAccessManager::finished,this,&NetMusic::netreplyready);
//QNetworkAccessManager::finished(QNetworkReply*)返回QNetworkReply*对象
//manager在完成请求后会发出finished信号,收到后调用netreplyready函数
}
void NetMusic::getnetmusic(const QString &url)
{
QNetworkRequest rq(url); //创建并用url初始化请求对象rq
manager->get(rq); //让manager执行请求
}
void NetMusic::netreplyready(QNetworkReply *reply) //reply是manager请求后返回的对象
{
if(reply->error()!=QNetworkReply::NoError){ //如果请求发生错误
emit neterror(reply->errorString()); //打印错误信息
reply->deleteLater(); //异步销毁reply,以防内存泄漏
return;
}
QByteArray data=reply->readAll(); //读取reply返回的所有数据
reply->deleteLater();
QJsonDocument doc=QJsonDocument::fromJson(data); //将QByteArray转为JSON文档
if(!doc.isObject()){ //如果不是JSON对象
emit neterror("Invalid JSON");
return;
}
QJsonObject obj=doc.object(); //将文档转为键值对{}
QVariantList list;
if(obj.contains("data")&&obj["data"].isArray()){ //确认文档中包含data数组
QJsonArray arr=obj["data"].toArray(); //将键data对应的值转换为数组[]
for(const QJsonValue &val:arr){ //将arr转换为一个对象{}
QJsonObject res=val.toObject(); //将val再次转换为键值对{},以便找值
/*和val一样,但能够通过键值搜索*/
QVariantMap song;
song["id"]=res["id"].toInt();
song["cover"]=res["cover"].toString();
song["title"]=res["song"].toString();
song["author"]=res["singer"].toString();
song["album"]=res["album"].toString();
song["listime"]=res["interval"].toString();
list.append(song);
}
}
qDebug()<<"成功";
emit netresready(list);
}
最后转换的细解:
QJsonObject obj=doc.object();
/*{
"code": 200,
"message": "请求成功!",
"data": [
{ "id":...,
"mid":...,
.......
}
]
}*/
QVariantList list;
if(obj.contains("data")&&obj["data"].isArray()){
QJsonArray arr=obj["data"].toArray();
/*[
{
"id": 111111111,
"mid": "xxxxxxxxxxxxxxxx",
"vid": "xxxxxxxxxxx",
"song": "xxx",
"singer": "xxx",
"cover": "https://xxx/music/photo/xxxx.jpg",
"interval": "x分xx秒",
"singer_list": [...],
"grp": [...]
}
]*/
for(const QJsonValue &val:arr){
/*{
"id": 111111111,
"mid": "xxxxxxxxxxxxxxxx",
"vid": "xxxxxxxxxxx",
"song": "xxx",
"singer": "xxx",
"cover": "https://xxx/music/photo/xxxx.jpg",
"interval": "x分xx秒",
"singer_list": [...],
"grp": [...]
}*/
三、创建多线程
因为发送请求并处理返回数据的时间比较长,很可能会阻塞主线程UI,所以需要创建一个子线程去处理耗时工作,等到处理完成后再通知主线程更新界面
//netmusicinfo.h
#ifndef NETMUSICINFO_H
#define NETMUSICINFO_H
#include <QObject>
#include <QThread>
#include "netmusic.h"
class NetMusicInfo : public QObject
{
Q_OBJECT
public:
explicit NetMusicInfo(QObject *parent = nullptr);
~NetMusicInfo();
signals:
void netmusicrequest(const QString &url);
void netmusicready(const QVariantList &data);
public slots:
void netmusicgot(const QVariantList &data); //数据处理完毕
void netmusicerror(const QString &error);
private:
QThread *nethread;
NetMusic *networker;
};
#endif // NETMUSICINFO_H
//netmusicinfo.cpp
#include "netmusicinfo.h"
#include <QObject>
#include <QVariant>
#include <QVariantList>
#include <QThread>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QJsonDocument>
#include <QJsonObject>
NetMusicInfo::NetMusicInfo(QObject *parent)
: QObject{parent}
{
nethread=new QThread(this);
networker=new NetMusic();
networker->moveToThread(nethread);
connect(nethread,&QThread::finished,networker,&QObject::deleteLater);
connect(this,&NetMusicInfo::netmusicrequest,networker,&NetMusic::getnetmusic);
connect(networker,&NetMusic::netresready,this,&NetMusicInfo::netmusicgot);
connect(networker,&NetMusic::neterror,this,&NetMusicInfo::netmusicerror);
nethread->start();
}
NetMusicInfo::~NetMusicInfo()
{
nethread->quit();
nethread->wait();
}
void NetMusicInfo::netmusicgot(const QVariantList &data) //子线程处理完数据后调用
{
emit netmusicready(data);
}
void NetMusicInfo::netmusicerror(const QString &error)
{
qWarning()<<"请求失败"<<error;
}
四、QML接收数据
在QML中捕获信号携带的data并添加入ListModel
Connections{
target:netmsc //注册的NetMusicInfo类的全局对象
function onNetmusicready(data){
Config.musicdata.clear()
for(let i=0;i<data.length;i++){
Config.musicdata.append(data[i])
}
}
}
这就是目前我使用的调用api的方法,如果后续有新的发现会再和大家分享~
683

被折叠的 条评论
为什么被折叠?



