QT应用编程: 编写低功耗BLE蓝牙调试助手(Android系统APP)

简介: QT应用编程: 编写低功耗BLE蓝牙调试助手(Android系统APP)

一、环境介绍

QT版本: 5.12.6


编译环境: win10 64位


目标系统: Android


完整工程源码下载地址(包含APK文件):  https://download.csdn.net/download/xiaolong1126626497/19051696


想学习QT的Android环境搭建看这里(win10版本): https://blog.csdn.net/xiaolong1126626497/article/details/117254453


                                                         (ubuntu版本): https://blog.csdn.net/xiaolong1126626497/article/details/117256660


想学习QT入门到精通编程的看这里:https://blog.csdn.net/xiaolong1126626497/article/details/116485145


二、功能介绍

本软件是一款BLE蓝牙串口调试助手,支持常规的发送和接收调试,BLE是低功耗类型蓝牙,在智能家居、物联网领域使用较多。BLE低功耗蓝牙一般不能直接使用手机进行连接,手机蓝牙默认都是工作在传统蓝牙模式,无法直接连接BLE低功耗蓝牙信号,需要使用专用的APP配置手机蓝牙模式,方可进行通信。


本软件为了方便工程师在开发产品过程中调试BLE蓝牙,将蓝牙连接过程中的信息全部输出到屏幕上,方便调试错误。  

image.png

image.png

image.png

image.png

image.png

三、核心源码

#include "mainwindow.h"
#include "ui_mainwindow.h"
/*
 * 设置QT界面的样式
*/
void MainWindow::SetStyle(const QString &qssFile) {
    QFile file(qssFile);
    if (file.open(QFile::ReadOnly)) {
        QString qss = QLatin1String(file.readAll());
        qApp->setStyleSheet(qss);
        QString PaletteColor = qss.mid(20,7);
        qApp->setPalette(QPalette(QColor(PaletteColor)));
        file.close();
    }
    else
    {
        qApp->setStyleSheet("");
    }
}
//#蓝牙串口服务
//SerialPortServiceClass_UUID = '{00001101-0000-1000-8000-00805F9B34FB}'
//Service UUID 0xFEE0 主服务
//static const QLatin1String serviceUuid("0000FEE0-0000-1000-8000-00805F9B34FB");
//这个字符串里面的内容就是串口模式的Uuid
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->SetStyle(":/qss/blue.css");     //设置样式表
    this->setWindowTitle("BLE蓝牙调试助手"); //设置标题
    this->setWindowIcon(QIcon(":/wbyq.ico")); //设置图标
    /*1. 实例化蓝牙相关的对象*/
    discoveryAgent = new QBluetoothDeviceDiscoveryAgent();
    localDevice = new QBluetoothLocalDevice();
    /*2. 关联蓝牙设备相关的信号*/
    /*2.1 关联发现设备的槽函数,当扫描发现周围的蓝牙设备时,会发出deviceDiscovered信号*/
    connect(discoveryAgent,
            SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),
            this,
            SLOT(addBlueToothDevicesToList(QBluetoothDeviceInfo))
            );
    /*3. 检查蓝牙的状态,用于设置按钮的初始状态*/
    /*3.1 检查蓝牙是否开启*/
    if(localDevice->hostMode() == QBluetoothLocalDevice::HostPoweredOff)
    {
            //如果蓝牙处于关闭状态
            ui->pushButton_OpenBluetooth->setEnabled(true);   //打开按钮
            ui->pushButton_CloseBluetooth->setEnabled(false); //关闭按钮
    }
    else    //如果蓝牙处于开启状态
    {
            ui->pushButton_OpenBluetooth->setEnabled(false);//打开按钮
            ui->pushButton_CloseBluetooth->setEnabled(true);//关闭按钮
            ui->pushButton_BluetoothScan->setEnabled(true); //设置扫描按钮可用
    }
    /*3.2 设置标签显示本地蓝牙的名称*/
    QString name_info("本机蓝牙:");
    name_info+=localDevice->name();
    ui->label_BluetoothName->setText(name_info);
     ui->pushButton_StopScan->setEnabled(false);      //设置停止扫描蓝牙的按钮不可用
     ui->plainTextEdit_BluetoothInfiShow->setEnabled(false); //设置不可编辑
     m_control=NULL; //初始值
     m_service=NULL;  //初始值
     SendModeSelect=0;
     SendMaxMode=0;
}
MainWindow::~MainWindow()
{
    delete ui;
    delete discoveryAgent;
    delete localDevice;
}
void MainWindow::on_pushButton_OpenBluetooth_clicked()
{
    /*请求打开蓝牙设备*/
    localDevice->powerOn();
    ui->pushButton_OpenBluetooth->setEnabled(false);//打开按钮
    ui->pushButton_CloseBluetooth->setEnabled(true);//关闭按钮
    ui->pushButton_BluetoothScan->setEnabled(true); //设置扫描按钮可用
}
void MainWindow::on_pushButton_CloseBluetooth_clicked()
{
    /*关闭蓝牙设备*/
    localDevice->setHostMode(QBluetoothLocalDevice::HostPoweredOff);
    ui->pushButton_OpenBluetooth->setEnabled(true);//打开按钮
    ui->pushButton_CloseBluetooth->setEnabled(false);//关闭按钮
    ui->pushButton_BluetoothScan->setEnabled(false); //设置扫描按钮不可用
}
void MainWindow::on_pushButton_BluetoothScan_clicked()
{
     /*开始扫描周围的蓝牙设备*/
    discoveryAgent->start();
    ui->comboBox_BluetoothDevice->clear(); //清除条目
    ui->pushButton_BluetoothScan->setEnabled(false); //设置扫描按钮不可用
    ui->pushButton_StopScan->setEnabled(true);     //设置停止扫描按钮可用
}
void MainWindow::on_pushButton_StopScan_clicked()
{
    /*停止扫描周围的蓝牙设备*/
    discoveryAgent->stop();
    ui->pushButton_StopScan->setEnabled(false);     //设置停止扫描按钮不可用
    ui->pushButton_BluetoothScan->setEnabled(true); //设置扫描按钮可用
}
/*当扫描到周围的设备时会调用当前的槽函数*/
void MainWindow::addBlueToothDevicesToList(const QBluetoothDeviceInfo &info)
{
   // QString label = QString("%1 %2").arg(info.name()).arg(info.address().toString());
    QString label = QString("%1 %2").arg(info.address().toString()).arg(info.name());
    ui->comboBox_BluetoothDevice->addItem(label); //添加字符串到comboBox上
}
/*
在说蓝牙设备连接之前,不得不提一个非常重要的概念,就是蓝牙的Uuid,引用一下百度的:
在蓝牙中,每个服务和服务属性都唯一地由"全球唯一标识符" (UUID)来校验。
正如它的名字所暗示的,每一个这样的标识符都要在时空上保证唯一。
UUID类可表现为短整形(16或32位)和长整形(128位)UUID。
他提供了分别利用String和16位或32位数值来创建类的构造函数,提供了一个可以比较两个UUID(如果两个都是128位)的方法,还有一个可以转换一个UUID为一个字符串的方法。
UUID实例是不可改变的(immutable),只有被UUID标示的服务可以被发现。
在Linux下你用一个命令uuidgen -t可以生成一个UUID值;
在Windows下则执行命令uuidgen 。UUID看起来就像如下的这个形式:2d266186-01fb-47c2-8d9f-10b8ec891363。当使用生成的UUID去创建一个UUID对象,你可以去掉连字符。
*/
//发送数据
void MainWindow::on_pushButton_SendData_clicked()
{
    QString text=ui->lineEdit_SendData->text();
    QByteArray array=text.toLocal8Bit();
    /*写入newValue作为特性的值。
     如果操作成功,将发射characteristicWritten()信号;
    低功耗设备: 每次最多写20个字节
    */
      m_service->writeCharacteristic(m_writeCharacteristic[SendModeSelect],array, m_writeMode);
}
//清空收到的数据
void MainWindow::on_pushButton_Clear_clicked()
{
    ui->plainTextEdit_BluetoothInfiShow->setPlainText("");
}
//连接蓝牙
void MainWindow::on_pushButton_ConnectDev_clicked()
{
    QString text = ui->comboBox_BluetoothDevice->currentText();
    int index = text.indexOf(' ');
    if(index == -1) return;
    QBluetoothAddress address(text.left(index));
    QString connect_device="开始连接蓝牙设备:\n";
    connect_device+=ui->comboBox_BluetoothDevice->currentText();
    QMessageBox::information(this,tr("连接提示"),connect_device);
    /*低功耗蓝牙设备*/
    if(m_control!=NULL)
    {
        m_control->disconnectFromDevice(); //断开远程设备
        delete m_control;
        m_control = NULL;
    }
    ui->comboBox_UUID->clear();         //清除显示UUID服务的列表框
    QList<QBluetoothDeviceInfo> info_list=discoveryAgent->discoveredDevices(); //得到扫描的所有设备信息
    for(int i=0;i<info_list.count();i++)
    {
        if(info_list.at(i).address().toString()==text.left(index))
        {
             remoteDevice=info_list.at(i);
             ui->plainTextEdit_BluetoothInfiShow->insertPlainText("连接设备:");
             ui->plainTextEdit_BluetoothInfiShow->insertPlainText(remoteDevice.name());
             ui->plainTextEdit_BluetoothInfiShow->insertPlainText("\n");
             ui->plainTextEdit_BluetoothInfiShow->insertPlainText(remoteDevice.address().toString());
             ui->plainTextEdit_BluetoothInfiShow->insertPlainText("\n");
            break;
        }
   }
    //创建中央角色设备
    m_control = new QLowEnergyController(remoteDevice, this);
    //m_control=QLowEnergyController::createCentral(remoteDevice,this);
    if(m_control==0)
    {
        ui->plainTextEdit_BluetoothInfiShow->insertPlainText("创建中央角色设备失败!\n");
    }
    else
    {
        ui->plainTextEdit_BluetoothInfiShow->insertPlainText("创建中央角色设备成功!\n");
    }
    //每次发现新的服务就会发送此信号
    connect(m_control, SIGNAL(serviceDiscovered(QBluetoothUuid)),this, SLOT(BlueServiceDiscovered(QBluetoothUuid)));
    //正在运行的服务发现完成时发出此信号。
    connect(m_control, SIGNAL(discoveryFinished()),this, SLOT(BlueServiceScanDone()));
    //当控制器成功连接到远程Low Energy设备时,会发出此信号。
     connect(m_control, SIGNAL(connected()),this, SLOT(BlueDeviceConnected()));
    //当控制器从远程低功耗设备断开时发出此信号。
     connect(m_control, SIGNAL(disconnected()),this, SLOT(BlueDeviceDisconnected()));
     //该信号在发生错误时发出。
     connect(m_control, static_cast<void(QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error),
           [=](QLowEnergyController::Error error){
         if(error==QLowEnergyController::NoError)
         {
             ui->plainTextEdit_BluetoothInfiShow->insertPlainText("没有发生错误\n");
         }
         else if(error==QLowEnergyController::UnknownError)
         {
             ui->plainTextEdit_BluetoothInfiShow->insertPlainText("出现未知错误。\n");
         }
          else if(error==QLowEnergyController::UnknownRemoteDeviceError)
         {
             ui->plainTextEdit_BluetoothInfiShow->insertPlainText("无法找到传递给此类构造函数的远程Bluetooth Low Energy设备。\n");
         }
         else if(error==QLowEnergyController::NetworkError)
         {
             ui->plainTextEdit_BluetoothInfiShow->insertPlainText("尝试读取或写入远程设备失败\n");
         }
          else if(error==QLowEnergyController::InvalidBluetoothAdapterError)
         {
             ui->plainTextEdit_BluetoothInfiShow->insertPlainText("传递给此类构造函数的本地蓝牙设备无法找到,或者没有本地蓝牙设备\n");
         }
          else if(error==QLowEnergyController::InvalidBluetoothAdapterError)
         {
             ui->plainTextEdit_BluetoothInfiShow->insertPlainText("尝试连接到远程设备失败。\n");
         }
         else
          ui->plainTextEdit_BluetoothInfiShow->insertPlainText("*****未知错误!******\n");
     });
     //连接到远程蓝牙低功耗设备。
      m_control->connectToDevice();
}
//每次发现新的服务,就会调用该槽函数
void MainWindow::BlueServiceDiscovered(const QBluetoothUuid &gatt)
{
     ui->comboBox_UUID->addItem(gatt.toString()); //添加字符串到comboBox上
     ui->plainTextEdit_BluetoothInfiShow->insertPlainText("\n");
     ui->plainTextEdit_BluetoothInfiShow->insertPlainText(gatt.toString());
}
//帮助提示
void MainWindow::on_pushButton_help_clicked()
{
    QMessageBox::information(this,tr("帮助提示"),"本软件用于BLE4.0蓝牙调试\n"
                                             "不支持HC-05系列2.0版本蓝牙\n"
                                             "如果第一次打开软件界面"
                                             "不适应屏幕关闭应用重新打开即可\n"
                                             "软件作者:DS小龙哥\n"
                                             "BUG反馈:1126626497@qq.com");
}
//默认指定UUID服务
static const QLatin1String serviceUuid("{0000FEE0-0000-1000-8000-00805F9B34FB}");
//正在运行的服务发现完成时发出此信号。
void MainWindow::BlueServiceScanDone()
{
   // ui->plainTextEdit_BluetoothInfiShow->insertPlainText("正在运行的服务发现完成\n");
//    QMessageBox::information(this,tr("帮助提示"),"服务发现完成\n"
//                                             "请选择上方列表中的服务\n"
//                                             "进行连接BLE低功耗蓝牙设备\n");
    /*判断之前有没有连接过*/
    if(m_service!=NULL)
    {
        delete m_service;
        m_service=NULL;
    }
    ui->plainTextEdit_BluetoothInfiShow->insertPlainText("\n选中的服务:");
    ui->plainTextEdit_BluetoothInfiShow->insertPlainText(serviceUuid);
    ui->plainTextEdit_BluetoothInfiShow->insertPlainText("\n");
    /*与设备之间建立服务*/
    m_service=m_control->createServiceObject(QBluetoothUuid(serviceUuid),this);
    if(m_service==NULL)
    {
        ui->plainTextEdit_BluetoothInfiShow->insertPlainText("服务建立失败!\n");
        return;
    }
    else
    {
        ui->plainTextEdit_BluetoothInfiShow->insertPlainText("服务建立成功!\n");
    }
    /*服务状态改变时发出此信号。newState也可以通过state()。*/
    connect(m_service, SIGNAL(stateChanged(QLowEnergyService::ServiceState)),
                this, SLOT(BleServiceServiceStateChanged(QLowEnergyService::ServiceState)));
    /*特性值由事件改变时发出此信号在外设上。 newValue参数包含更新后的值特性*/
    connect(m_service, SIGNAL(characteristicChanged(QLowEnergyCharacteristic,QByteArray)),
                this, SLOT(BleServiceCharacteristicChanged(QLowEnergyCharacteristic,QByteArray)));
    /*当特征读取请求成功返回其值时,发出此信号。*/
     connect(m_service, SIGNAL(characteristicRead(QLowEnergyCharacteristic,QByteArray)),
                this, SLOT(BleServiceCharacteristicRead(QLowEnergyCharacteristic,QByteArray)));
    /*当特性值成功更改为newValue时,会发出此信号。*/
    connect(m_service, SIGNAL(characteristicWritten(QLowEnergyCharacteristic,QByteArray)),
                this, SLOT(BleServiceCharacteristicWrite(QLowEnergyCharacteristic,QByteArray)));
    /*错误信号*/
    connect(m_service, static_cast<void(QLowEnergyService::*)(QLowEnergyService::ServiceError)>(&QLowEnergyService::error),
         [=](QLowEnergyService::ServiceError newErrorr)
    {
        if(QLowEnergyService::NoError == newErrorr)
        {
             ui->plainTextEdit_BluetoothInfiShow->insertPlainText("没有发生错误。\n");
        }
        if(QLowEnergyService::OperationError==newErrorr)
        {
             ui->plainTextEdit_BluetoothInfiShow->insertPlainText("错误: 当服务没有准备好时尝试进行操作!\n");
        }
        if(QLowEnergyService::CharacteristicReadError==newErrorr)
        {
             ui->plainTextEdit_BluetoothInfiShow->insertPlainText("尝试读取特征值失败!\n");
        }
        if(QLowEnergyService::CharacteristicWriteError==newErrorr)
        {
             ui->plainTextEdit_BluetoothInfiShow->insertPlainText("尝试为特性写入新值失败!\n");
        }
        if(QLowEnergyService::DescriptorReadError==newErrorr)
        {
             ui->plainTextEdit_BluetoothInfiShow->insertPlainText("尝试读取描述符值失败!\n");
        }
        if(QLowEnergyService::DescriptorWriteError==newErrorr)
        {
             ui->plainTextEdit_BluetoothInfiShow->insertPlainText(" 尝试向描述符写入新值失败!\n");
        }
        if(QLowEnergyService::UnknownError==newErrorr)
        {
             ui->plainTextEdit_BluetoothInfiShow->insertPlainText("与服务交互时发生未知错误!\n");
        }
    });
    if(m_service->state() == QLowEnergyService::DiscoveryRequired)
    {
        m_service->discoverDetails(); //启动服务发现扫描
    }
    else
        searchCharacteristic();
}
//搜索特性
void MainWindow::searchCharacteristic()
{
    if(m_service)
    {
        QList<QLowEnergyCharacteristic> list=m_service->characteristics();
        qDebug()<<"list.count()="<<list.count();
        //characteristics 获取详细特性
        SendMaxMode=list.count();  //设置模式选择上限
        for(int i=0;i<list.count();i++)
        {
            QLowEnergyCharacteristic c=list.at(i);
            /*如果QLowEnergyCharacteristic对象有效,则返回true,否则返回false*/
            if(c.isValid())
            {
//                返回特征的属性。
//                这些属性定义了特征的访问权限。
               if(c.properties() & QLowEnergyCharacteristic::WriteNoResponse || c.properties() & QLowEnergyCharacteristic::Write)
               // if(c.properties() & QLowEnergyCharacteristic::Write)
                {
                    ui->plainTextEdit_BluetoothInfiShow->insertPlainText("具有写权限!\n");
                    m_writeCharacteristic[i] = c;  //保存写权限特性
                    if(c.properties() & QLowEnergyCharacteristic::WriteNoResponse)
//                        如果使用此模式写入特性,则远程外设不应发送写入确认。
//                        无法确定操作的成功,并且有效负载不得超过20个字节。
//                        一个特性必须设置QLowEnergyCharacteristic :: WriteNoResponse属性来支持这种写模式。
//                         它的优点是更快的写入操作,因为它可能发生在其他设备交互之间。
                        m_writeMode = QLowEnergyService::WriteWithoutResponse;
                    else
                        m_writeMode = QLowEnergyService::WriteWithResponse;
                    //如果使用此模式写入特性,则外设应发送写入确认。
                    //如果操作成功,则通过characteristicWritten()信号发出确认。
                    //否则,发出CharacteristicWriteError。
                    //一个特性必须设置QLowEnergyCharacteristic :: Write属性来支持这种写模式。
                }
                if(c.properties() & QLowEnergyCharacteristic::Read)
                {
                    m_readCharacteristic = c; //保存读权限特性
                }
                //描述符定义特征如何由特定客户端配置。
                m_notificationDesc = c.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
                //值为真
                if(m_notificationDesc.isValid())
                {
                    //写描述符
                    m_service->writeDescriptor(m_notificationDesc, QByteArray::fromHex("0100"));
                  //   m_service->writeDescriptor(m_notificationDesc, QByteArray::fromHex("FEE1"));
                    ui->plainTextEdit_BluetoothInfiShow->insertPlainText("写描述符!\n");
                }
            }
        }
    }
}
//当控制器成功连接到远程Low Energy设备时,会发出此信号。
void MainWindow::BlueDeviceConnected()
{
    ui->plainTextEdit_BluetoothInfiShow->insertPlainText("成功连接设备!\n");
    //启动发现服务Services
    m_control->discoverServices();
//    QList<QBluetoothUuid> uuid_list=m_control->services(); //获取已经查找成功的服务
//    for(int i=0;i<uuid_list.count();i++)
//    {
//        ui->comboBox_UUID->addItem(uuid_list.at(i).toString()); //添加字符串到comboBox上
//    }
//    if(uuid_list.count()<=0)
//    {
//        ui->plainTextEdit_BluetoothInfiShow->insertPlainText("没有查找到UUID服务!\n");
//    }
}
//当控制器从远程低功耗设备断开时发出此信号。
void MainWindow::BlueDeviceDisconnected()
{
    ui->plainTextEdit_BluetoothInfiShow->insertPlainText("成功断开!\n");
}
//当前选中的服务
void MainWindow::on_comboBox_UUID_currentIndexChanged(const QString &arg1)
{
}
//服务状态改变时发出此信号
void MainWindow::BleServiceServiceStateChanged(QLowEnergyService::ServiceState s)
{
    //ui->plainTextEdit_BluetoothInfiShow->insertPlainText("服务状态改变时发出此信号!\n");
    if(s == QLowEnergyService::ServiceDiscovered)  //所有细节都已同步
    {
        ui->plainTextEdit_BluetoothInfiShow->insertPlainText("所有细节都已发现!\n");
        searchCharacteristic();
    }
}
//读取到数据
void MainWindow::BleServiceCharacteristicChanged(const QLowEnergyCharacteristic &c,
                                                 const QByteArray &value)
{
   // ui->plainTextEdit_BluetoothInfiShow->insertPlainText("特性值由事件改变时发出此信号在外设上!\n");
    ui->plainTextEdit_BluetoothInfiShow->insertPlainText(QString(value));
    //移动滚动条到底部
    QScrollBar *scrollbar = ui->plainTextEdit_BluetoothInfiShow->verticalScrollBar();
    if(scrollbar)
    {
        scrollbar->setSliderPosition(scrollbar->maximum());
    }
}
void MainWindow::BleServiceCharacteristicRead(const QLowEnergyCharacteristic &c,
                                              const QByteArray &value)
{
  //  ui->plainTextEdit_BluetoothInfiShow->insertPlainText("当特征读取请求成功返回其值时\n");
    //ui->plainTextEdit_BluetoothInfiShow->insertPlainText(QString(value));
}
void MainWindow::BleServiceCharacteristicWrite(const QLowEnergyCharacteristic &c,
                                               const QByteArray &value)
{
    //ui->plainTextEdit_BluetoothInfiShow->insertPlainText("当特性值成功更改为newValue时!\n");
   ui->plainTextEdit_BluetoothInfiShow->insertPlainText(QString(value));
}
//发送模式
void MainWindow::on_pushButton_SendMode_clicked()
{
    bool ok;
    int data = QInputDialog::getInt(this, tr("获取输入模式"),tr("选择模式:"), 0, 0,SendMaxMode,1, &ok);
    if(ok)
    {
        SendModeSelect=data;
    }
}



目录
相关文章
|
1月前
|
XML Java 数据库
安卓项目:app注册/登录界面设计
本文介绍了如何设计一个Android应用的注册/登录界面,包括布局文件的创建、登录和注册逻辑的实现,以及运行效果的展示。
139 0
安卓项目:app注册/登录界面设计
|
6天前
|
人工智能 自然语言处理 前端开发
用通义灵码,从 0 开始打造一个完整APP,无需编程经验就可以完成
通义灵码携手科技博主@玺哥超carry 打造全网第一个完整的、面向普通人的自然语言编程教程。完全使用 AI,再配合简单易懂的方法,只要你会打字,就能真正做出一个完整的应用。本教程完全免费,而且为大家准备了 100 个降噪蓝牙耳机,送给前 100 个完成的粉丝。获奖的方式非常简单,只要你跟着教程完成第一课的内容就能获得。
|
7天前
|
开发框架 监控 .NET
【Azure App Service】部署在App Service上的.NET应用内存消耗不能超过2GB的情况分析
x64 dotnet runtime is not installed on the app service by default. Since we had the app service running in x64, it was proxying the request to a 32 bit dotnet process which was throwing an OutOfMemoryException with requests >100MB. It worked on the IaaS servers because we had the x64 runtime install
|
16天前
|
小程序 数据挖掘 UED
开发1个上门家政小程序APP系统,都有哪些功能?
在快节奏的现代生活中,家政服务已成为许多家庭的必需品。针对传统家政服务存在的问题,如服务质量不稳定、价格不透明等,我们历时两年开发了一套全新的上门家政系统。该系统通过完善信用体系、提供奖励机制、优化复购体验、多渠道推广和多样化盈利模式,解决了私单、复购、推广和盈利四大痛点,全面提升了服务质量和用户体验,旨在成为家政行业的领导者。
|
2月前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android多线程编程的重要性及其实现方法,涵盖了基本概念、常见线程类型(如主线程、工作线程)以及多种多线程实现方式(如`Thread`、`HandlerThread`、`Executors`、Kotlin协程等)。通过合理的多线程管理,可大幅提升应用性能和用户体验。
120 15
一个Android App最少有几个线程?实现多线程的方式有哪些?
|
13天前
|
机器人
布谷直播App系统源码开发之后台管理功能详解
直播系统开发搭建管理后台功能详解!
|
2月前
|
移动开发 Android开发 数据安全/隐私保护
移动应用与系统的技术演进:从开发到操作系统的全景解析随着智能手机和平板电脑的普及,移动应用(App)已成为人们日常生活中不可或缺的一部分。无论是社交、娱乐、购物还是办公,移动应用都扮演着重要的角色。而支撑这些应用运行的,正是功能强大且复杂的移动操作系统。本文将深入探讨移动应用的开发过程及其背后的操作系统机制,揭示这一领域的技术演进。
本文旨在提供关于移动应用与系统技术的全面概述,涵盖移动应用的开发生命周期、主要移动操作系统的特点以及它们之间的竞争关系。我们将探讨如何高效地开发移动应用,并分析iOS和Android两大主流操作系统的技术优势与局限。同时,本文还将讨论跨平台解决方案的兴起及其对移动开发领域的影响。通过这篇技术性文章,读者将获得对移动应用开发及操作系统深层理解的钥匙。
|
2月前
|
存储 开发工具 Android开发
使用.NET MAUI开发第一个安卓APP
【9月更文挑战第24天】使用.NET MAUI开发首个安卓APP需完成以下步骤:首先,安装Visual Studio 2022并勾选“.NET Multi-platform App UI development”工作负载;接着,安装Android SDK。然后,创建新项目时选择“.NET Multi-platform App (MAUI)”模板,并仅针对Android平台进行配置。了解项目结构,包括`.csproj`配置文件、`Properties`配置文件夹、平台特定代码及共享代码等。
154 2
|
2月前
|
XML Android开发 数据格式
🌐Android国际化与本地化全攻略!让你的App走遍全球无障碍!🌍
在全球化背景下,实现Android应用的国际化与本地化至关重要。本文以一款旅游指南App为例,详细介绍如何通过资源文件拆分与命名、适配布局与方向、处理日期时间及货币格式、考虑文化习俗等步骤,完成多语言支持和本地化调整。通过邀请用户测试并收集反馈,确保应用能无缝融入不同市场,提升用户体验与满意度。
102 3
|
2月前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android应用开发中的多线程编程,涵盖基本概念、常见实现方式及最佳实践。主要内容包括主线程与工作线程的作用、多线程的多种实现方法(如 `Thread`、`HandlerThread`、`Executors` 和 Kotlin 协程),以及如何避免内存泄漏和合理使用线程池。通过有效的多线程管理,可以显著提升应用性能和用户体验。
69 10

推荐镜像

更多
  • qt