Qt QML调用音乐api

最近在做一个音乐播放器的项目,之前实现了解码播放本地音乐,那怎么获取网络音乐呢?就图个省事直接调用第三方的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的方法,如果后续有新的发现会再和大家分享~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值