Android 蓝牙开发(扫描设备、绑定、解绑,腾讯T2大佬手把手教你

Kotlin版 蓝牙开发 (扫描设备、绑定、解绑)

  • 前言

    • 运行效果图
  • 正文

    • ① 配置项目
  • ② 布局和样式

  • ③ 编码

    • 1. 通知栏样式修改
  • 2. 蓝牙设备列表适配器编写

  • 3. 权限请求

  • 4. 初始化蓝牙

  • 5. 扫描蓝牙

  • 6. 广播接收器

  • 7. 显示蓝牙设备信息

  • ④ 源码

前言

===============================================================

之前写了一个蓝牙的小Demo,看的人还是有一些的,也有人私信我说,在学Kotlin,能不能出一版Kotlin的博客讲述这个蓝牙开发,这个想法还是不错的,不过就怕写了没有人看,因为在国内Kotlin是受众群体确实比较少,当然了也是有大的方向在往这边推动的,但是小公司依然不会去用Kotlin,如果你看不惯我这个说法也不要告诉我。我只是把这个博客当成是笔记而已,如果能在写作的时候帮助到别人也是乐意的,不能就自勉吧。

运行效果图


在这里插入图片描述

扫描蓝牙设备

在这里插入图片描述

如果你对上面的效果图感觉满意,那么可以往下面看了,不满意就不浪费你查看其它文章的时间了。

正文

===============================================================

当然还是新创建一个项目,名为MyBluetooth-Kotlin,为了区分我之前写的Java版的项目。

在这里插入图片描述

选择语言为Kotlin,然后点击Finish完成项目的创建。第一次创建Kotlin项目花费的时间会比较长,耐心等待。

创建好了之后你看到的第一个页面应该是这样的。

在这里插入图片描述

没错,这就是Kotlin语言的Android项目,和Java还是有区别的,建议了解了Kotlin的语法再看文章会比较好,当然你也可以对照我写的Android 蓝牙开发(扫描设备、绑定、解绑)Java版来看,我尽量保持差不多的业务逻辑流程来编写项目。

① 配置项目


在工程的build.gradle中,添加如下依赖

maven { url “https://jitpack.io” }

添加位置如下图所示:

在这里插入图片描述

然后是在app下的build.gradle中添加依赖库

compileOptions {//指定使用的JDK1.8

sourceCompatibility = 1.8

targetCompatibility = 1.8

}

//Google Material控件,以及迁移到AndroidX下一些控件的依赖

implementation ‘com.google.android.material:material:1.2.0’

//RecyclerView最好的适配器,让你的适配器一目了然,告别代码冗余

implementation ‘com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30’

//权限请求框架

implementation ‘com.tbruyelle.rxpermissions2:rxpermissions:0.9.4@aar’

implementation ‘io.reactivex.rxjava2:rxandroid:2.0.2’

implementation “io.reactivex.rxjava2:rxjava:2.0.0”

添加位置如下图所示:

在这里插入图片描述

现在工程和app模块的build.gradle就修改完成了,直接Sync同步一下,同步之后你添加的依赖库才能使用。

然后配置AndroidManifest.xml文件

添加位置如下图所示:

在这里插入图片描述

然后改动colors.xml中系统默认的颜色

在这里插入图片描述

这两个颜色会影响到你的状态栏。

然后是styles.xml文件

在这里插入图片描述

上面不涉及到代码,所以Java和Kotlin中的资源文件配置是差不多的。

② 布局和样式


图片资源

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

当然里面的一些其他的图标请到我的源码里面去拿,我就不一一贴出来了

在drawable下创建一个名为progressbar.xml的样式文件,代码如下:

<?xml version="1.0" encoding="utf-8"?>

<rotate

android:drawable=“@drawable/icon_loading”

android:fromDegrees=“0.0”

android:pivotX=“50.0%”

android:pivotY=“50.0%”

android:toDegrees=“360.0” />

修改activity_main.xml布局文件,代码如下:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:app=“http://schemas.android.com/apk/res-auto”

xmlns:tools=“http://schemas.android.com/tools”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:fitsSystemWindows=“true”

android:orientation=“vertical”

tools:context=“.MainActivity”>

<androidx.appcompat.widget.Toolbar

android:elevation=“3dp”

android:id=“@+id/toolbar”

android:layout_width=“match_parent”

android:layout_height=“?attr/actionBarSize”

android:background=“@color/colorPrimary”

app:layout_constraintEnd_toEndOf=“parent”

app:layout_constraintLeft_toLeftOf=“parent”

app:layout_constraintTop_toTopOf=“parent”>

<TextView

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_gravity=“center”

android:text=“我的蓝牙”

android:textColor=“#000”

android:textSize=“18sp” />

</androidx.appcompat.widget.Toolbar>

<View

android:layout_width=“match_parent”

android:layout_height=“1dp”

android:background=“#EEEEEE” />

<LinearLayout

android:id=“@+id/loading_lay”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:gravity=“center”

android:visibility=“gone”>

<ProgressBar

android:layout_width=“@dimen/dp_40”

android:layout_height=“@dimen/dp_40”

android:indeterminate=“true”

android:indeterminateDrawable=“@drawable/progressbar” />

<TextView

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“扫描中…” />

<androidx.recyclerview.widget.RecyclerView

android:id=“@+id/rv”

android:background=“#FFF”

android:layout_width=“match_parent”

android:layout_height=“0dp”

android:layout_weight=“1” />

<View

android:layout_width=“match_parent”

android:layout_height=“1dp”

android:background=“#EEEEEE” />

<TextView

android:id=“@+id/scan_devices”

android:layout_width=“match_parent”

android:layout_height=“50dp”

android:background=“?android:attr/selectableItemBackground”

android:gravity=“center”

android:text=“扫描蓝牙” />

在layout下创建列表展示的item的布局文件,名为item_device_list.xml

在这里插入图片描述

代码如下:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”

android:orientation=“vertical”

android:id=“@+id/item_device”

android:background=“?android:attr/selectableItemBackground”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”>

<LinearLayout

android:gravity=“center_vertical”

android:padding=“12dp”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”>

<ImageView

android:id=“@+id/iv_device_type”

android:src=“@mipmap/icon_bluetooth”

android:layout_width=“30dp”

android:layout_height=“30dp”/>

<TextView

android:id=“@+id/tv_name”

android:paddingLeft=“12dp”

android:textSize=“16sp”

android:text=“设备名称”

android:textColor=“#000”

android:layout_width=“0dp”

android:layout_weight=“1”

android:layout_height=“wrap_content”/>

<TextView

android:gravity=“right”

android:id=“@+id/tv_bond_state”

android:text=“绑定状态”

android:layout_width=“0dp”

android:layout_weight=“1”

android:layout_height=“wrap_content”/>

<View

android:background=“#EBEBEB”

android:layout_marginLeft=“54dp”

android:layout_width=“match_parent”

android:layout_height=“1dp”/>

③ 编码


一切准备工作都已经就绪了,下面就进入编码环节,前面的内容其实和Kotlin的关系都不大,下面上正菜,Kotlin相比于Java来说的优势就是简洁,这一点会在下面的编码过程中体现。

1. 通知栏样式修改

首先修改状态栏的文字颜色,如果你现在运行这个项目在手机上时,你会发现状态栏是白色的背景以及白色的文字。如下图所示:

在这里插入图片描述

这样的用户体验是很不好的,而在Android6.0以后支持设置高亮状态栏样式。在之前我写Java版的时候特别弄了一个工具类,里面有针对性状态栏的一些样式和颜色改动,但实际上我只用了其中的一个方法,为了一个方法而去写一个工具类显然多此一举了。所以在Kotlin中我想到了更简单的办法,直接在MainActivity中修改状态栏样式。

代码如下:

//设置亮色状态栏模式 systemUiVisibility在Android11中弃用了,可以尝试一下。

window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or

View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR

放在onCreate方法中,然后运行。

在这里插入图片描述

是不是立竿见影,这个效果一行代码解决问题还不用写工具类,完全调用系统的方法,请注意我是Android10.0版本的手机,也是我自己用的手机。

下面写列表的适配器,因为你扫描蓝牙肯定会是一个列表,既然是一个列表那么肯定要有适配器。

2. 蓝牙设备列表适配器编写

创建一个adapter包,包下创建一个DeviceAdapter.kt文件,如下所示

在这里插入图片描述

DeviceAdapter的代码如下:

package com.llw.bluetooth.adapter

import android.bluetooth.BluetoothClass

import android.bluetooth.BluetoothClass.Device.*

import android.bluetooth.BluetoothClass.Device.Major.*

import android.bluetooth.BluetoothDevice

import android.widget.ImageView

import android.widget.TextView

import com.chad.library.adapter.base.BaseQuickAdapter

import com.chad.library.adapter.base.BaseViewHolder

import com.llw.bluetooth.R

/**

  • 蓝牙设备适配器

*/

class DeviceAdapter(layoutResId: Int, data: MutableList?) :

BaseQuickAdapter<BluetoothDevice, BaseViewHolder>(layoutResId, data) {

override fun convert(helper: BaseViewHolder?, item: BluetoothDevice?) {

val tvName = helper!!.getView(R.id.tv_name)

val icon = helper.getView(R.id.iv_device_type)

//根据设备类型设置图标

getDeviceType(item!!.bluetoothClass.majorDeviceClass, icon)

tvName.text = if (item.name == null) “无名” else item.name

//蓝牙设备绑定状态判断

val tvState = helper!!.getView(R.id.tv_bond_state)

tvState.text = when (item.bondState) {

10 -> “未配对”

11 -> “正在配对…”

12 -> “已配对”

else -> “未配对”

}

//添加item点击事件

helper.addOnClickListener(R.id.item_device)

}

/**

  • 根据类型设置图标

  • @param type 类型码

  • @param icon 图标

*/

private fun getDeviceType(type: Int, icon: ImageView) {

when (type) {

AUDIO_VIDEO_HEADPHONES,//耳机

AUDIO_VIDEO_WEARABLE_HEADSET,//穿戴式耳机

AUDIO_VIDEO_HANDSFREE,//蓝牙耳机

AUDIO_VIDEO //音频设备

-> icon.setImageResource(R.mipmap.icon_headset)

COMPUTER //电脑

-> icon.setImageResource(R.mipmap.icon_computer)

PHONE //手机

-> icon.setImageResource(R.mipmap.icon_phone)

HEALTH //健康类设备

-> icon.setImageResource(R.mipmap.icon_health)

AUDIO_VIDEO_CAMCORDER, //照相机录像机

AUDIO_VIDEO_VCR //录像机

-> icon.setImageResource(R.mipmap.icon_vcr)

AUDIO_VIDEO_CAR_AUDIO //车载设备

-> icon.setImageResource(R.mipmap.icon_car)

AUDIO_VIDEO_LOUDSPEAKER //扬声器

-> icon.setImageResource(R.mipmap.icon_loudspeaker)

AUDIO_VIDEO_MICROPHONE //麦克风

-> icon.setImageResource(R.mipmap.icon_microphone)

AUDIO_VIDEO_PORTABLE_AUDIO //打印机

-> icon.setImageResource(R.mipmap.icon_printer)

AUDIO_VIDEO_SET_TOP_BOX //音频视频机顶盒

-> icon.setImageResource(R.mipmap.icon_top_box)

AUDIO_VIDEO_VIDEO_CONFERENCING //音频视频视频会议

-> icon.setImageResource(R.mipmap.icon_meeting)

AUDIO_VIDEO_VIDEO_DISPLAY_AND_LOUDSPEAKER //显示器和扬声器

-> icon.setImageResource(R.mipmap.icon_tv)

AUDIO_VIDEO_VIDEO_GAMING_TOY //游戏

-> icon.setImageResource(R.mipmap.icon_game)

AUDIO_VIDEO_VIDEO_MONITOR //可穿戴设备

-> icon.setImageResource(R.mipmap.icon_wearable_devices)

else -> icon.setImageResource(R.mipmap.icon_bluetooth)

}

}

/**

  • 刷新适配器

*/

fun changeBondDevice() {

notifyDataSetChanged()

}

}

代码讲解:

class DeviceAdapter(layoutResId: Int, data: MutableList?) :

BaseQuickAdapter<BluetoothDevice, BaseViewHolder>(layoutResId, data)

首先看这个类,在Kotlin继承和实现都是通过 :(英文下的冒号)来操作的,而Java中继承是extends,实现是implements。在上面的代码中DeviceAdapter继承了BaseQuickAdapter,这一点和Java的相似,如下图所示

在这里插入图片描述

而Kotlin的语法可以让你把构造方法的参数作为类参数使用,这样解释不知道是不是对的,这里传了一个布局id和数据源。

然后重写里面convert方法

override fun convert(helper: BaseViewHolder?, item: BluetoothDevice?) {

val tvName = helper!!.getView(R.id.tv_name)

val icon = helper.getView(R.id.iv_device_type)

getDeviceType(item!!.bluetoothClass.majorDeviceClass, icon)

tvName.text = if (item.name == null) “无名” else item.name

//蓝牙设备绑定状态判断

val tvState = helper!!.getView(R.id.tv_bond_state)

tvState.text = when (item.bondState) {

10 -> “未配对”

11 -> “正在配对…”

12 -> “已配对”

else -> “未配对”

}

//添加item点击事件

helper.addOnClickListener(R.id.item_device)

}

在代码中你会看到 !!? 这个你就不明所以了,因为Java中是没有的,这里解释一下,首先是Kotlin对于空安全做了处理, !! 表示当前对象不会空的情况下执行,而 ? 表示当前对象可以为空。

val tvName = helper!!.getView(R.id.tv_name)

val icon = helper.getView(R.id.iv_device_type)

而这两行代码,可以看到,第一行我给了!!,第二行没有给,这是因为在Kotlin中只要一开始做了处理之后后面就可以不用再次处理,当然你加上!!也没有问题。val 表示不可变量,而通过Kotlin的类型推导机制,tvName此时代表的就是一个通过R.id.tv_name实例化之后的TextView。

//根据设备类型设置图标

getDeviceType(item!!.bluetoothClass.majorDeviceClass, icon)

这行代码调用getDeviceType方法,传入两个参数,这两个参数都已经做了非空的处理,所以在getDeviceType的里面就不用在做空处理了。下面看这个方法的代码:

/**

  • 根据类型设置图标

  • @param type 类型码

  • @param icon 图标

*/

private fun getDeviceType(type: Int, icon: ImageView) {

when (type) {

AUDIO_VIDEO_HEADPHONES,//耳机

AUDIO_VIDEO_WEARABLE_HEADSET,//穿戴式耳机

AUDIO_VIDEO_HANDSFREE,//蓝牙耳机

AUDIO_VIDEO //音频设备

-> icon.setImageResource(R.mipmap.icon_headset)

COMPUTER //电脑

-> icon.setImageResource(R.mipmap.icon_computer)

PHONE //手机

-> icon.setImageResource(R.mipmap.icon_phone)

HEALTH //健康类设备

-> icon.setImageResource(R.mipmap.icon_health)

AUDIO_VIDEO_CAMCORDER, //照相机录像机

AUDIO_VIDEO_VCR //录像机

-> icon.setImageResource(R.mipmap.icon_vcr)

AUDIO_VIDEO_CAR_AUDIO //车载设备

-> icon.setImageResource(R.mipmap.icon_car)

AUDIO_VIDEO_LOUDSPEAKER //扬声器

-> icon.setImageResource(R.mipmap.icon_loudspeaker)

AUDIO_VIDEO_MICROPHONE //麦克风

-> icon.setImageResource(R.mipmap.icon_microphone)

AUDIO_VIDEO_PORTABLE_AUDIO //打印机

-> icon.setImageResource(R.mipmap.icon_printer)

AUDIO_VIDEO_SET_TOP_BOX //音频视频机顶盒

-> icon.setImageResource(R.mipmap.icon_top_box)

AUDIO_VIDEO_VIDEO_CONFERENCING //音频视频视频会议

-> icon.setImageResource(R.mipmap.icon_meeting)

AUDIO_VIDEO_VIDEO_DISPLAY_AND_LOUDSPEAKER //显示器和扬声器

-> icon.setImageResource(R.mipmap.icon_tv)

AUDIO_VIDEO_VIDEO_GAMING_TOY //游戏

-> icon.setImageResource(R.mipmap.icon_game)

AUDIO_VIDEO_VIDEO_MONITOR //可穿戴设备

-> icon.setImageResource(R.mipmap.icon_wearable_devices)

else -> icon.setImageResource(R.mipmap.icon_bluetooth)

}

}

其实就是条件分支,根据不同的条件做不同的事情,在Java中使用switch/case,而在Kotlin中使用when。when的语法结构更加的简洁明了,通过 -> 代替了 : ,冒号前面是条件,冒号后面是执行业务。而当多个条件对应一个执行业务时,条件之间用英文逗号隔开,一行代码完成一个条件分支,很简洁,但是不要忘了加上else,这是标准写法,你不加也没事,就如同你写switch/case不加default一样。相信这么一解释你已经理解了when的基本用法了,当然还有很多其他的用法由于业务的原因无法展示,自行百度吧。

tvName.text = if (item.name == null) “无名” else item.name

这行代码等同于

if (item.getName() == null) {

helper.setText(R.id.tv_name, “无名”);

} else {

helper.setText(R.id.tv_name, item.getName());

}

这么一看是不是觉得Kotlin的语法很简单,它允许你的返回值一致的判断进行直接赋值,比如这里判断设备名称为空则显示无名二字,不为空则显示设备名,这两个返回都是String类型,而tvName.text设置的就是String类型,所以就有了上面的简洁代码,有点像三目运算符。

//蓝牙设备绑定状态判断

val tvState = helper!!.getView(R.id.tv_bond_state)

tvState.text = when (item.bondState) {

10 -> “未配对”

11 -> “正在配对…”

12 -> “已配对”

else -> “未配对”

}

//添加item点击事件

helper.addOnClickListener(R.id.item_device)

这几行代码也没有什么好讲解的了,都讲过了,这也是when的另一种使用方法,可以直接赋值使用。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

总结

Android架构学习进阶是一条漫长而艰苦的道路,不能靠一时激情,更不是熬几天几夜就能学好的,必须养成平时努力学习的习惯。所以:贵在坚持!

上面分享的字节跳动公司2020年的面试真题解析大全,笔者还把一线互联网企业主流面试技术要点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

就先写到这,码字不易,写的很片面不好之处敬请指出,如果觉得有参考价值的朋友也可以关注一下我

①「Android面试真题解析大全」PDF完整高清版+②「Android面试知识体系」学习思维导图压缩包阅读下载,最后觉得有帮助、有需要的朋友可以点个赞

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

625c.png)

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-3HcH3rE1-1712148776733)]

总结

Android架构学习进阶是一条漫长而艰苦的道路,不能靠一时激情,更不是熬几天几夜就能学好的,必须养成平时努力学习的习惯。所以:贵在坚持!

上面分享的字节跳动公司2020年的面试真题解析大全,笔者还把一线互联网企业主流面试技术要点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

就先写到这,码字不易,写的很片面不好之处敬请指出,如果觉得有参考价值的朋友也可以关注一下我

①「Android面试真题解析大全」PDF完整高清版+②「Android面试知识体系」学习思维导图压缩包阅读下载,最后觉得有帮助、有需要的朋友可以点个赞

[外链图片转存中…(img-mqkpfd1w-1712148776733)]

[外链图片转存中…(img-EgnVGX9B-1712148776733)]

[外链图片转存中…(img-wjZlLg7x-1712148776733)]

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

  • 16
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
这里是一份使用Vue 3和TypeScript实现设备功能的代码示例: ```typescript <template> <div> <h2>设备</h2> <form @submit.prevent="onSubmit"> <div class="form-group"> <label for="deviceId">设备ID:</label> <input type="text" id="deviceId" v-model="deviceId" class="form-control" required> </div> <div class="form-group"> <label for="userId">用户ID:</label> <input type="text" id="userId" v-model="userId" class="form-control" required> </div> <button type="submit" class="btn btn-primary">{{ binding ? '' : '' }}</button> </form> <div v-if="message" class="alert alert-info">{{ message }}</div> </div> </template> <script lang="ts"> import { defineComponent } from 'vue'; interface Binding { deviceId: string; userId: string; } export default defineComponent({ data() { return { deviceId: '', userId: '', binding: false, message: '' } }, methods: { async onSubmit() { try { const binding: Binding = { deviceId: this.deviceId, userId: this.userId }; if (this.binding) { // 发送请求 await this.unbindDevice(binding); this.message = `设备${binding.deviceId}已`; } else { // 发送请求 await this.bindDevice(binding); this.message = `设备${binding.deviceId}已`; } this.deviceId = ''; this.userId = ''; } catch (error) { console.error(error); this.message = error.message; } }, async bindDevice(binding: Binding) { // 发送请求 // ... }, async unbindDevice(binding: Binding) { // 发送请求 // ... } } }); </script> ``` 这个组件包含一个表单,用户可以在表单中输入设备ID和用户ID。当用户点击“”按钮时,组件将发送一个请求,并将消息显示为“设备”。当用户点击“”按钮时,组件将发送一个请求,并将消息显示为“设备”。 组件使用了一个名为`Binding`的接口来表示设备请求中的数据。组件还包含了两个异步方法,`bindDevice`和`unbindDevice`,它们负责发送请求。这些方法可以根据具体的需求进行实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值