两处代码:

在这里插入图片描述

这里注意一点,viewBinding的开启代码是在android{}闭包中的,不要放错地方了,然后点击Sync或者Sync Now。当程序编译完成之后,运行到自己手机上,先确保项目配置这一步没有问题。

二、页面设计


首先改一下主题的颜色,列如标题,改成绿色。在colors.xml中增加:

#2b9247

#00cd66

然后修改style中的样式:

在这里插入图片描述

修改activity_main.xml

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

<RelativeLayout 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:orientation=“vertical”

tools:context=“.MainActivity”>

<ProgressBar

android:id=“@+id/progress_bar”

style=“@style/Widget.AppCompat.ProgressBar.Horizontal”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:indeterminate=“true”

android:visibility=“invisible” />

<androidx.recyclerview.widget.RecyclerView

android:id=“@+id/rv_device”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:layout_below=“@+id/progress_bar”

android:overScrollMode=“never”

android:scrollbars=“none” />

<LinearLayout

android:id=“@+id/lay_no_equipment”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:layout_below=“@+id/progress_bar”

android:gravity=“center”

android:orientation=“vertical”>

<ImageView

android:layout_width=“60dp”

android:layout_height=“60dp”

android:layout_marginBottom=“12dp”

android:src=“@drawable/ic_widgets” />

<TextView

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“空空如也~” />

<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton

android:id=“@+id/fab_add”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_alignParentEnd=“true”

android:layout_alignParentBottom=“true”

android:layout_margin=“20dp”

android:text=“Scanning”

android:textColor=“@color/white”

app:elevation=“6dp”

app:fabSize=“normal”

app:icon=“@drawable/ic_add_white”

app:iconTint=“@color/white” />

这里面有两个图标,代码如下:

ic_widget.xml

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

android:width=“24dp”

android:height=“24dp”

android:alpha=“0.6”

android:viewportWidth=“24.0”

android:viewportHeight=“24.0”>

<path

android:fillColor=“#FF000000”

android:pathData=“M13,13v8h8v-8h-8zM3,21h8v-8L3,13v8zM3,3v8h8L11,3L3,3zM16.66,1.69L11,7.34 16.66,13l5.66,-5.66 -5.66,-5.65z” />

ic_add.xml

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

android:width=“24dp”

android:height=“24dp”

android:viewportWidth=“24.0”

android:viewportHeight=“24.0”>

<path

android:fillColor=“#FFFFFFFF”

android:pathData=“M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z”/>

下面写扫描到的列表适配器布局文件,在layout下新建一个item_bluetooth.xml,里面的代码如下:

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

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

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:background=“@color/white”

android:foreground=“?attr/selectableItemBackground”

android:orientation=“vertical”>

<LinearLayout

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:gravity=“center_vertical”

android:padding=“16dp”>

<ImageView

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:src=“@drawable/ic_bluetooth” />

<LinearLayout

android:layout_width=“0dp”

android:layout_height=“wrap_content”

android:layout_weight=“1”

android:orientation=“vertical”

android:paddingStart=“12dp”>

<TextView

android:id=“@+id/tv_device_name”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:ellipsize=“end”

android:singleLine=“true”

android:text=“设备名称”

android:textColor=“@color/black”

android:textSize=“16sp” />

<TextView

android:id=“@+id/tv_mac_address”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_marginTop=“8dp”

android:ellipsize=“end”

android:singleLine=“true”

android:text=“Mac地址” />

<TextView

android:id=“@+id/tv_rssi”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:text=“信号强度” />

<View

android:layout_width=“match_parent”

android:layout_height=“0.5dp”

android:background=“#EEE” />

这里也有一个蓝牙图标的ic_bluetooth.xml,如下:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

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

android:width=“36dp”

android:height=“36dp”

android:autoMirrored=“true”

android:tint=“@color/green”

android:viewportWidth=“24.0”

android:viewportHeight=“24.0”>

<path

android:fillColor=“@android:color/white”

android:pathData=“M14.58,12.36l1.38,1.38c0.28,0.28 0.75,0.14 0.84,-0.24c0.12,-0.48 0.18,-0.99 0.18,-1.5c0,-0.51 -0.06,-1.01 -0.18,-1.48c-0.09,-0.38 -0.56,-0.52 -0.84,-0.24l-1.39,1.38C14.39,11.85 14.39,12.17 14.58,12.36zM18.72,7.51l-0.05,0.05c-0.25,0.25 -0.3,0.62 -0.16,0.94c0.47,1.07 0.73,2.25 0.73,3.49c0,1.24 -0.26,2.42 -0.73,3.49c-0.14,0.32 -0.09,0.69 0.16,0.94l0,0c0.41,0.41 1.1,0.29 1.35,-0.23c0.63,-1.3 0.98,-2.76 0.98,-4.3c-0.01,-1.48 -0.34,-2.89 -0.93,-4.16C19.83,7.22 19.13,7.1 18.72,7.51zM15,7l-4.79,-4.79C10.07,2.07 9.89,2 9.71,2h0C9.32,2 9,2.32 9,2.71v6.88L5.12,5.7c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L8.59,12l-4.89,4.89c-0.39,0.39 -0.39,1.02 0,1.41h0c0.39,0.39 1.02,0.39 1.41,0L9,14.41v6.88C9,21.68 9.32,22 9.71,22h0c0.19,0 0.37,-0.07 0.5,-0.21L15,17c0.39,-0.39 0.39,-1.02 0,-1.42L11.41,12L15,8.42C15.39,8.03 15.39,7.39 15,7zM11,5.83l1.88,1.88L11,9.59V5.83zM12.88,16.29L11,18.17v-3.76L12.88,16.29z” />

设备扫描页面就差不多了,下面进行这个页面的代码编写。

三、扫描设备


首先想清楚扫描之前要做什么,扫描之后要做什么。扫描之前要判断Android版本,6.0及以上需要动态请求权限,请求之后要判断蓝牙是否打开,蓝牙打开权限也有了就可以点击扫描蓝牙开始扫描了,扫描时显示加载条表示正在扫描,扫描到设备后添加到列表中,页面上渲染出来。当点击一个设备时连接这个设备,然后就是连接设备后的数据交互了,先写现在的业务逻辑。

① 绑定视图

先进行视图绑定,activity_main.xml 对应的就是ActivityMainBinding。由ViewBinding根据布局生成的

//视图绑定

private lateinit var binding: ActivityMainBinding

然后在onCreate中进行绑定

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

binding = ActivityMainBinding.inflate(layoutInflater)

setContentView(binding.root)

}

② 检查Android版本

当进入页面是检查版本

/**

  • Android版本

*/

private fun checkAndroidVersion() =

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) requestPermission() else openBluetooth()

这里的语法就是Kotlin的语法,等价于Java中的如下代码。

private fun checkAndroidVersion() {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

requestPermission()

} else {

openBluetooth()

}

}

当你用Kotlin时间越久你就越觉得Kotlin设计的好,非常的简洁。当然最主要的是多使用Kotlin,作为弱类型语言,代码的阅读需要有一定的Kotlin基础才可以,高阶的写法可读性很差,但是效率很高代码也很简洁。后面我就直接写Kotlin代码,不熟悉的可以留言提问,事先声明我的Kotlin很菜,所以可读性相对来说高一些。

从上面的方法中可以知道逻辑就是Android6.0以上就请求权限,以下就打开蓝牙。这两个方法现在还都没有的,先写打开蓝牙的方法。

③ 打开蓝牙

//默认蓝牙适配器

private var defaultAdapter = BluetoothAdapter.getDefaultAdapter()

/**

  • 打开蓝牙

*/

private fun openBluetooth() = defaultAdapter.let {

if (it.isEnabled) showMsg(“蓝牙已打开,可以开始扫描设备了”) else activityResult.launch(Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE))

}

这个方法中主要就是当蓝牙开发未打开的时候,通过Intent去打开系统蓝牙,注意这一行代码:

activityResult.launch(Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE))

在Android高版本中弃用了startActivityForResult,改用registerForActivityResult。使用此方法需要在onCreate之前进行初始化。

//注册开启蓝牙 注意在onCreate之前注册

private val activityResult =

registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {

if (it.resultCode == Activity.RESULT_OK) showMsg(if (defaultAdapter.isEnabled) “蓝牙已打开” else “蓝牙未打开”)

}

这里的showMsg代码如下:

/**

  • Toast提示

*/

private fun showMsg(msg: String = “权限未通过”) = Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()

④ 请求权限

/**

  • 请求权限

*/

private fun requestPermission() =

PermissionX.init(this).permissions(Manifest.permission.ACCESS_FINE_LOCATION)

.request { allGranted, _, _ -> if (allGranted) openBluetooth() else showMsg() }

初始阶段完成了,最终在onCreate方法中调用

在这里插入图片描述

当权限同意之后就打开蓝牙,如果都打开了就可以开始进行扫描蓝牙的操作了,在扫描之后先要确定蓝牙设备需要什么信息。

⑤ 扫描结果

现在前期的准备工作就做好了,那么下面就是点击扫描按钮进行蓝牙设备的扫描了。

//扫描结果回调

private val scanCallback = object : ScanCallback() {

override fun onScanResult(callbackType: Int, result: ScanResult) {

}

}

看这段代码相对于Java的区别还是很大的,不过返回的结果值是一样的,然后就是触发回调的地方,这里容我一会儿再写这个开始扫描和停止扫描的方法,因为这两个方法牵扯到的内容比较多,需要控制数据、视图、业务逻辑。因此等先把数据展示出来再去进行这个扫描的开始和结束的操作方法的编写。

⑥ 设备适配器编写

首先我们要定义一个设备类,用来存放扫描到的结果,在Kotlin中有一个数据类,来做这个事情,新建一个BleDevice,代码如下:

data class BleDevice(var device:BluetoothDevice, var rssi:Int, var name:String?)

扫描毫无疑问肯定要展示数据在页面上的。然后就需要一个视图来显示数据,之前创建了item的xml文件,现在我们需要写一个适配器去配合这个item的xm去渲染列表数据。

BaseQuickAdapter的使用,之前我是没有通过ViewBinding去进行布局绑定的,都是通过R.layout.item布局文件进行的,那么换成了ViewBinding要怎么操作呢?BaseQuickAdapter的源码中没有提到ViewBinding,倒是提到了DataBinding,很明显这是两回事,因此我们需要自己扩展一下,让BaseQuickAdapter中可以使用ViewBinding,看下面这一段代码:

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

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

override fun convert(holder: BaseViewHolder, item: BleDevice) {

}

}

这是常规的写法,只要传入数据和布局文件的id就可以了,但是现在布局id变成了ViewBinding,因此就需要对这个BaseViewHolder进行一个覆写,这个方式我也是参考了网上博客的内容,

新建一个adapter包,包下新建一个ViewBindingHolder类,里面的代码如下:

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

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

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

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

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

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

Android开发除了flutter还有什么是必须掌握的吗?

相信大多数从事Android开发的朋友们越来越发现,找工作越来越难了,面试的要求越来越高了

除了基础扎实的java知识,数据结构算法,设计模式还要求会底层源码,NDK技术,性能调优,还有会些小程序和跨平台,比如说flutter,以思维脑图的方式展示在下图;

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

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

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

大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**

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

Android开发除了flutter还有什么是必须掌握的吗?

相信大多数从事Android开发的朋友们越来越发现,找工作越来越难了,面试的要求越来越高了

除了基础扎实的java知识,数据结构算法,设计模式还要求会底层源码,NDK技术,性能调优,还有会些小程序和跨平台,比如说flutter,以思维脑图的方式展示在下图;

[外链图片转存中…(img-Lnh6apPQ-1712496171519)]

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

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

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

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐