Android最全轻松上手 Android蓝牙基础开发(1),2024年最新android高级工程师面试题及答案

如何做好面试突击,规划学习方向?

面试题集可以帮助你查漏补缺,有方向有针对性的学习,为之后进大厂做准备。但是如果你仅仅是看一遍,而不去学习和深究。那么这份面试题对你的帮助会很有限。最终还是要靠资深技术水平说话。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。建议先制定学习计划,根据学习计划把知识点关联起来,形成一个系统化的知识体系。

学习方向很容易规划,但是如果只通过碎片化的学习,对自己的提升是很慢的。

同时我还搜集整理2020年字节跳动,以及腾讯,阿里,华为,小米等公司的面试题,把面试的要求和技术点梳理成一份大而全的“ Android架构师”面试 Xmind(实际上比预期多花了不少精力),包含知识脉络 + 分支细节

image

在搭建这些技术框架的时候,还整理了系统的高级进阶教程,会比自己碎片化学习效果强太多。

image

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

蓝牙权限

使用蓝牙必须声明权限 BLUETOOTH 才可以执行蓝牙通信。

设置蓝牙

  1. 获取蓝牙适配器

所有的蓝牙 Activity 都是需要 BluetoothAdapter 的。获取 BluetoothAdapter 调用 BluetoothAdapter 的静态方法 getDefaultAdapter() 方法。会返回一个表示设备自身的蓝牙适配器(蓝牙无线装置)的 BluetoothAdapter。

整个系统有一个蓝牙适配器,我们的应用可以通过 BluetoothAdapter 这个对象与之交互。如果 getDefaultAdapter()返回 null 则说明该设备不支持蓝牙

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

if(mBluetoothAdapter == null){

// 说明此设备不支持蓝牙操作

}

  1. 启用蓝牙

需要确认是否已经开启蓝牙isEnabled()。返回 false 则说明蓝牙处于关闭状态。请求启用蓝牙。使用 ACTION_REQUEST_ENABLE 操作 Intent 调用 startActivityForResult()将通过系统设置发出启用蓝牙的请求。也可以通过 mBluetoothAdapter.enable() 直接打开蓝牙。

// 没有开始蓝牙

if(!mBluetoothAdapter.isEnabled()){

Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

startActivityForResult(enableBtIntent,REQUEST_ENBLE_BT);

}

我们的应用也可以选择侦听 ACTION_STATE_CHANGED 广播 Intent。每当蓝牙状态发生变化时,系统会广播此 Intent。此广播包含额外字段 EXTRA_STATE 和 EXTRA_PREVIOUS_STATE 分别表示新的和旧的蓝牙状态。

查找设备

使用 BluetoothAdapter 可以通过设备发现或通过查询配对设备的列表来查找远程蓝牙设备。

设备发现是一个扫描过程,它会搜索局部区域内已启用蓝牙功能的设备,然后请求一些关于各台设备的信息。这个过程也称为发现、查询、扫描。局部区域内的蓝牙设备仅在其当前已启用可检测性时才会响应发现请求。如果设备可以检测到,它将通过共享一些信息(例如设备名称、类及其唯一MAC地址)来响应发现请求。利用此信息,执行发现的设备可以选择发起到被发现设备的连接。

在首次与远程设备建立连接后,将会自动向用户显示配对请求。设备完成配对后,将会保存关于该设备的基本信息(如 设备名称、MAC 地址)。并且可以使用 Bluetooth API 读取这些信息。利用远程设备的已知 Mac 地址可以随时向其发起连接,而不需执行发现操作(假定该设备处于有效范围内)。

被配对和被连接之间存在差别。**被配对意味着两台设备知晓彼此的存在,具有可用于身份验证的共享链路密钥,并且能够与彼此建立加密连接。被连接意味着设备当前共享一个 RFCOMM 通道,并且能够向彼此传输数据。**当前的 Android Bluetooth API 要求对设备进行配对,然后才能建立 RFCOMM 连接(在使用 Bluetooth API 发起加密连接时,会自动执行配对)。Android 设备是默认处于不可检测状态的。

查询配对的设备

在执行设备发现之前,有必要查询已配对的设备集合。用来了解设备是否处于已知状态。通过 getBondedDevices() 来实现,这将返回表示已配对设备的一组 BluetoothDevice 。

例如:我们可以查询所有已配对的设备,然后使用 ArrayAdapter 向用户显示每台设备的名称:

Set pairedDevices = mBlutooothAdapter.getBondedDevices();

if(pairedDevices.size() > 0){

for(BluetoothDevice device:pairedDevices){

// 把名字和地址取出来添加到适配器中

mArrayAdapter.add(device.getName()+“\n”+ device.getAddress());

}

}

要发起连接仅需要知道目标蓝牙设备的 Mac 地址就可以了。

发现设备

发现设备使用 startDiscovery()该进程为异步进程。该方法会立刻返回一个布尔值,指示是否已成功启动发现操作。发现进程通常包含约 12 秒的查询扫描,之后对发现的设备进行扫描,以检索其蓝牙设备的名字。

我们的应用必须针对 ACTION_FOUND Intent 注册一个 BroadcastReceiver,以便接受每台发现的设备的信息。针对每台设备,系统会广播 ACTION_FOUND Intent。这个 Intent 会携带额外的字段 EXTRA_DEVICE 和 EXTRA_CLASS。这两者分别包含 BluetoothDevice 和 BluetoothClass。

// 创建一个接受 ACTION_FOUND 的 BroadcastReceiver

private final BroadcastReceiver mReceiver = new BroadcastReceiver(){

public void onReceive(Context context,Intent intent){

String action = intent.getAction();

// 当 Discovery 发现了一个设备

if(BluetoothDevice.ACTION_FOUND.equals(action)){

// 从 Intent 中获取发现的 BluetoothDevice

BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

// 将名字和地址放入要显示的适配器中

mArrayAdapter.add(device.getName + “\n” + device.getAddress());

}

}

};

// 注册这个 BroadcastReceiver

IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);

registerReceiver(mReiver,filter);

// 在 onDestroy 中 unRegister

注意 执行 discovery 对于蓝牙适配器来说是一个非常繁重的过程,并且会消耗大量资源。在找到要连接的设备后,要确保使用 cancelDiscovery() 来停止发现,然后尝试连接。如果您已经和某台设备进行连接,那么这个时候执行发现操作会大幅度的减少此连接可用的带宽!因此不应该在处于连接状态的时候执行发现操作!

启用可检测性

如果我们希望我们的设备是可以被其他设备检测到的,可以使用 ACTION_REQUEST_DISCOVERABLE 来操作 Intent 调用 startActivityForResult(Intent,int)。这样会通过系统设置发出启用可检测到模式的请求(无需停止我们的应用)。默认情况下,设备会变为可检测状态并且持续 120 秒钟。我们还可以通过 **EXTRA_DISCOVERABLE_DURATION** Intent Extra

**来定义不同的持续时间。可以设置的最大持续时间为 3600 秒。**值为 0 表示始终可以被检测到。任何小于 0 或者大于 3600 的值都会自动设置为 120 秒钟。

例如:

Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);

discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,300);

startActivityForResult(discoverableIntent);

将显示对话框,请求用户允许将设备设为可检测到。如果用户响应为 YES,则设备将变为可检测到并持续指定的时间量。然后您的 Activity 将会收到对 onActivityResult() 回调的调用,其结果代码等于设备可检测到的持续时间。如果用户响应 NO 或者出现错误,结果代码为 RESULT_CANCELED

如果设备没有打开蓝牙,则启用设备可检测性的时候会自动启用蓝牙。

设备将在分配的时间内以静默方式保持可检测到模式。如果我们希望在可检测到模式发生变化时收到通知,可以利用 ACTION_SCAN_MODE_CHANGED Intent 注册 BroadcastReceiver。它将包含额外字段 EXTRA_SCAN_MODE 和 EXTRA_PREVIOUS_SCAN_MODE,两者分别告诉我们新的和旧的扫描模式。每个字段可能包括SCAN_MODE_CONNECTABLE_DISCOVERABLE(可检测到模式)、SCAN_MODE_CONNECTABLE(未处于可检测模式但可以接受连接)、SCAN_MODE_NOE(未处于可检测到模式并且无法连接)

连接设备

要在两台设备上的应用之间创建连接,必须同时实现服务端和客户端机制,因为其中一台设备必须开放服务器套接字,而另一台设备必须发起连接(使用服务器设备的 MAC 地址发起连接)。当服务器和客户端在同一 RFCOMM 通道上分别拥有已连接的 BluetoothSocket 时,二者将被视为彼此连接。在这种情况下每台设备都能获得输入和输出流式传输,并且可以开始传输数据。

服务端和客户端分别以不同的方式来获得 BluetoothSocket 。服务器将在传入连接被接受时收到套接字。客户端将在其打开到服务器的 RFCOMM 通道时收到该套接字。

一种实现方式是自动将每台设备准备为一个服务器,从而使每台设备开发一个服务器套接字并侦听连接。然后任一设备可以发起与另一台设备的连接,并成为客户端。或者其中一台设备可显示“托管”连接并按需开放一个服务器套接字,从而另一台设备则直接发起连接。

在连接之前如果两个设备没有配对,则系统会自动发出配对请求

连接为服务器

当连接两台设备时,其中一台必须保持开发的 BluetoothServerSocket 来充当服务器,用于监听传入的连接请求,在接受了请求后提供一个已经连接的 BluetoothSocket。从 BluetoothServerSocket 连接获取 BluetoothSocket 后就可以调用 close 来关闭这个等待了。

关于 UUID

通用唯一标识符(UUID),用于表示唯一标识信息的字符串ID,128位。可以使用网络上众多的随机 UUID 生成器,然后通过 formString(String) 来初始化一个 UUID。

服务器套接字接受连接的基本过程

  • 通过 listenUsingRfcommWithServiceRecord(String,UUID)获取 BluetoothServerSocket

字符串是我们自己定义的服务的可识别名称,可以直接使用包名。系统会自定将其写入到设备上的新服务发现协议(SDP)数据库条目中。UUID 也在 SDP 中,作为与客户端设备连接协议的匹配规则。只有客户端和这里的UUID 一样了才可以会被连接

  • accept() 侦听连接请求

阻塞调用,将在连接被接受或者发生异常的时候返回,操作成功后,会返回 BluetoothSocket

  • 除非要接受更多的连接,否则调用 close() 来关闭这个监听

这样会释放服务器套接字及其所有资源,但不会关闭已经连接的 BluetoothSocket。与 TCP/IP 不同的是,RFCOMM 一次只允许每个通道有一个已经连接的客户端。

放在子线程中去执行。

例子:

private class AcceptThread extend Thread{

private final BluetoothServerSocket mServerSocket;

public AcceptThread(){

mServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME,MY_UUID);

}

public void run(){

BluetoothSocket socket = null;

while(true){

socket = mServerSocket.accept();

if(socket!=null){

// 自定义方法

manageConnectedSocket(socket);

mServerSocket.close();

break;

}

}

}

public void cancle(){

mServerSocket.close();

}

}

连接为客户端

要想和保持开发服务器套接字的设备建立连接,必须首先要获取该设备的 BluetoothDevice 对象。然后使用这个对象来获取 BluetoothSocket 并发起连接。

客户端连接的基本过程

  • 通过 BluetoothDevice 的 createRfcommSocketToServiceRecord(UUID) 获取 BluetoothSocket 对象

这里的 UUID 要和服务器端的一致

  • 通过 connect() 发起连接

执行此方法后,系统将会在远程设备上执行 SDP 查找,来匹配 UUID。如果查找成功了并且远程设备接受了该连接,它将共享 RFCOMM 通道在连接期间使用。这个时候 connect() 就会返回。这个方法也是阻塞的,如果失败或者超时(12秒之后),将引发异常。

调用 connect() 的时候要确保客户端没有执行发现操作。如果执行了会大幅度降低连接的速度,增加失败的可能性

例子

private class ConnectThread extend Thread{

private BluetoothDevice mDevice;

private BluetoothSocket mSocket;

public ConnectThread(BluetoothSocket device){

mDevice = device;

// 这里的 UUID 需要和服务器的一致

mSocket = device.createRfcommSocketToServiceRecord(My_UUID);

}

public void run(){

// 关闭发现设备

mBluetoothAdapter.cancelDiscovery();

try{

mSocket.connect();

}catch(IOException connectException){

try{

mSocket.close();

}catch(IOException closeException){

return;

}

}

// 自定义方法

manageConnectedSocket(mmSocket);

}

public void cancle(){

try{

mSocket.close();

}cathc(IOException closeException){

}

}

}

更多学习和讨论,欢迎加入我们!

有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。

这里有2000+小伙伴,让你的学习不寂寞~·

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

}cathc(IOException closeException){

}

}

}

[外链图片转存中…(img-96bZH5gA-1715249201174)]

更多学习和讨论,欢迎加入我们!

有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。

这里有2000+小伙伴,让你的学习不寂寞~·

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值