眼花缭乱的UI,蓝牙位于何方

2024-06-20 21:38

本文主要是介绍眼花缭乱的UI,蓝牙位于何方,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

我们在前面已经分析了Android启动中涉及蓝牙的各个方面,今天我们着重来看看,在蓝牙打开之前,我们能看到的蓝牙UI有哪些,这些UI又是如何实现的。

1settingsUI的分析

         首先,最常见的也是我们通常情况下最新看到的,它就是Settings中蓝牙的显示代码,具体的图片如下:

1,默认settings中的界面

这个界面的实现是在这个文件中:/packages/apps/Settings/res/xml/settings_headers.xml。它采用的是preference-headers来实现的,这样的实现好处就在于可以匹配不同的屏幕,比如padphone。我们来看一下,你就会发现其实还是蛮简单的:

<preference-headersxmlns:android="http://schemas.android.com/apk/res/android"><!--这个就是那个“无线和网络”五个字了 --><!-- WIRELESS and NETWORKS --><header android:title="@string/header_category_wireless_networks" />
<!--这个是wifi --> <!-- Wifi --><headerandroid:id="@+id/wifi_settings"android:fragment="com.android.settings.wifi.WifiSettings"android:title="@string/wifi_settings_title"android:icon="@drawable/ic_settings_wireless" />
<!--这个是bluetooth --> <!-- Bluetooth --><headerandroid:id="@+id/bluetooth_settings"
<!—-这里的fragment是比较重要的-->android:fragment="com.android.settings.bluetooth.BluetoothSettings"android:title="@string/bluetooth_settings_title"android:icon="@drawable/ic_settings_bluetooth2" />
……

要显示这个preference-headers,需要重新实现 onBuildHeaders回调方法,毫无疑问,肯定是实现过了,我们来看一下具体的代码:

 @Overridepublic void onBuildHeaders(List<Header> headers) {if(UNIVERSEUI_SUPPORT){loadHeadersFromResource(R.xml.settings_headers_uui, headers);}else{
//load的preference-headers xml文件loadHeadersFromResource(R.xml.settings_headers, headers);}//这个会根据支持的features来决定是否需要把一些list去除掉updateHeaderList(headers);mHeaders = headers;}

这样来看,这个preference-headers的显示还是比较简单的,细心的同学会发现,上面header只有titleicon啊,我们在界面上还有一个开关,这里怎么没有啊?呵呵,好问题,其实上面的代码并不是真正的UI上的显示代码,真正的UI显示代码在哪里呢,我们来慢慢看。

我们知道settings其实最终调用的是setListAdapter,那么这个地方是如何实现的呢?我们来看源码:

  public void setListAdapter(ListAdapter adapter) {if (mHeaders == null) {mHeaders = new ArrayList<Header>();// When the saved state provides the list of headers, onBuildHeaders is not called// Copy the list of Headers from the adapter, preserving their orderfor (int i = 0; i < adapter.getCount(); i++) {mHeaders.add((Header) adapter.getItem(i));}}// Ignore the adapter provided by PreferenceActivity and substitute ours instead
//重点要关注这里,看HeaderAdapter是如何构建的super.setListAdapter(new HeaderAdapter(this, mHeaders));}

来看一下HeaderAdapter的构造

 public HeaderAdapter(Context context, List<Header> objects) {super(context, 0, objects);mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);// Temp Switches provided as placeholder until the adapter replaces these with actual// Switches inflated from their layouts. Must be done before adapter is set in super
//从注释来看,这里只是占位而已,后面会被layout中的内容真正地覆盖的,我们后面会详细分析mWifiEnabler = new WifiEnabler(context, new Switch(context));
//这里就是要构造我们的BluetoothEnabler了,这个在1.1中进行分析,这里可以理解为蓝牙那边的一些初始化,那边的分析会陷入进去比较多,若是想从整体上先理解,请跳过1.1,直接看后面1.2的内容mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));}

1.1 BluetoothEnabler的分析

BluetoothEnabler主要是用来管理蓝牙的on off的开关的。

public BluetoothEnabler(Context context, Switch switch_) {mContext = context;mSwitch = switch_;//local bluetooth manager就是在bluetooth api上面提供一个简单的接口//详见1.1.1分析LocalBluetoothManager manager = LocalBluetoothManager.getInstance(context);if (manager == null) {// Bluetooth is not supportedmLocalAdapter = null;mSwitch.setEnabled(false);} else {mLocalAdapter = manager.getBluetoothAdapter();}
//加入对ACTION_STATE_CHANGED和ACTION_AIRPLANE_MODE_CHANGED的action的处理mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);mIntentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
//btwifi的conexist是否被置位。若是没有,意味着wifi和bt只能有一个,则需要加一些action的处理if (SystemProperties.get("ro.btwifi.coexist", "true").equals("false")) {mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);mIntentFilter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);mSupportBtWifiCoexist = false;}}

1.1.1 LocalBluetoothManager的分析

local bluetooth manager就是在bluetooth api上面提供一个简单的接口。也就是说他是封装在bluetooth提供的api之上的。

public static synchronized LocalBluetoothManager getInstance(Context context) {if (sInstance == null) {//调用LocalBluetoothAdapter,调用api得到对应的bluetooth adapterLocalBluetoothAdapter adapter = LocalBluetoothAdapter.getInstance();if (adapter == null) {return null;}// This will be around as long as this process is//得到整个应该的生命周期,所以运行够长时间Context appContext = context.getApplicationContext();//新建LocalBluetoothManagersInstance = new LocalBluetoothManager(adapter, appContext);}return sInstance;}private LocalBluetoothManager(LocalBluetoothAdapter adapter, Context context) {mContext = context;mLocalAdapter = adapter;//新建CachedBluetoothDeviceManager,用来管理远端设备的,就是对端mCachedDeviceManager = new CachedBluetoothDeviceManager(context);// BluetoothEventManager用来管理从bluetooth API那边传过来的broadcast和callback,并把他们分配到对应的class中去,详见1.1.2mEventManager = new BluetoothEventManager(mLocalAdapter,mCachedDeviceManager, context);//用来管理对bluetooth profile的访问的,详见1.1.3mProfileManager = new LocalBluetoothProfileManager(context,mLocalAdapter, mCachedDeviceManager, mEventManager);}

1.1.2BluetoothEventManager的分析

上文已经讲过了,bluetoothEventManager是用来管理api那边传过来的broadcastcallback,他会根据各个broadcast进行最终的分配,我们来了解一下它究竟关注了哪些broadcastcallback

 BluetoothEventManager(LocalBluetoothAdapter adapter,CachedBluetoothDeviceManager deviceManager, Context context) {mLocalAdapter = adapter;mDeviceManager = deviceManager;mAdapterIntentFilter = new IntentFilter();mProfileIntentFilter = new IntentFilter();mHandlerMap = new HashMap<String, Handler>();mContext = context;// Bluetooth on/off broadcasts// ACTION_STATE_CHANGED,在蓝牙的on和off的时候会发出addHandler(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedHandler());//这两个是扫描的broadcast,分别表示开始扫描和停止扫描// Discovery broadcastsaddHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true));addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false));//这是扫描到设备和设备消失的broadcastaddHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());addHandler(BluetoothDevice.ACTION_DISAPPEARED, new DeviceDisappearedHandler());//这个是设备名字改变的actionaddHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler());// Pairing broadcasts//这个是设备配对状态改变的action,比如正在配对,已经配对之类的addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, new BondStateChangedHandler());//取消配对的handleraddHandler(BluetoothDevice.ACTION_PAIRING_CANCEL, new PairingCancelHandler());// Fine-grained state broadcasts//CLASS和UUID改变的actionaddHandler(BluetoothDevice.ACTION_CLASS_CHANGED, new ClassChangedHandler());addHandler(BluetoothDevice.ACTION_UUID, new UuidChangedHandler());// Dock event broadcasts//dock的eventaddHandler(Intent.ACTION_DOCK_EVENT, new DockEventHandler());//注册对这些action处理的receivermContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter);}

1.1.3 LocalBluetoothProfileManager的分析

         LocalBluetoothProfileManager是用来访问支持的bluetoothprofileLocalBluetoothProfile的。具体的代码如下:

 LocalBluetoothProfileManager(Context context,LocalBluetoothAdapter adapter,CachedBluetoothDeviceManager deviceManager,BluetoothEventManager eventManager) {mContext = context;mLocalAdapter = adapter;mDeviceManager = deviceManager;mEventManager = eventManager;// pass this reference to adapter and event manager (circular dependency)//和localadapter以及eventmanager关联mLocalAdapter.setProfileManager(this);mEventManager.setProfileManager(this);ParcelUuid[] uuids = adapter.getUuids();// uuids may be null if Bluetooth is turned offif (uuids != null) {
//根据uuid刷新我们支持的profile,在蓝牙off的状态下(从没有打开过的情况下),他应该是null,这里我就暂时不详细介绍了,会在后面的文章中再详细介绍updateLocalProfiles(uuids);}// Always add HID and PAN profiles//HID和PAN总是会加入的,具体的后面的文章用到再详细介绍mHidProfile = new HidProfile(context, mLocalAdapter);addProfile(mHidProfile, HidProfile.NAME,BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);mPanProfile = new PanProfile(context);addPanProfile(mPanProfile, PanProfile.NAME,BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);Log.d(TAG, "LocalBluetoothProfileManager construction complete");
}

这里,我们总结一下,BluetoothEnabler构造所涉及的各类和他们的主要作用:

1BluetoothEnabler—用于管理蓝牙的on/off开关操作。

2LocalBluetoothManager—frameworkbluetooth api之上进行了重新封装,向该应用本身提供了一些简单的接口。

3CachedBluetoothDeviceManager—用于管理远端设备的类,比如耳机,鼠标等

4BluetoothEventManager—用于管理从frameworkbluetooth api那边上来的broadcastcallback,并把这些反馈到对应的class中去。

5LocalBluetoothProfileManager—管理对各个bluetoothprofile的访问和操作

1.2真正的开关实现

基本到bluetooth中兜了一圈,我们还是没有发现任何和那个开关相关的内容。没有关系,我们继续来分析Settings中的内容,我们突然发现它重写了getView,哈哈,大家都知道PreferenceActivity中每个list都是通过getView来得到对应要显示的内容的,所以我们有必要来看看这个内容。

   @Overridepublic View getView(int position, View convertView, ViewGroup parent) {HeaderViewHolder holder;//根据postition得到对应itemHeader header = getItem(position);//得到type,wifi和蓝牙是有swtich的,这个见1.2.1,很简单的//就是下面switch来判断用的,蓝牙是HEADER_TYPE_SWITCH,就是有个开关啦int headerType = getHeaderType(header);View view = null;if (convertView == null) {holder = new HeaderViewHolder();switch (headerType) {case HEADER_TYPE_CATEGORY:
……
//bluetooth是witch的type哦case HEADER_TYPE_SWITCH://找到preference_header_switch_item这个layoutview = mInflater.inflate(R.layout.preference_header_switch_item, parent,false);
//细心的你一定发现这里的icon和title神马的好像和我们真正要显示的不太一样啊?别急,继续看下面你就明白了holder.icon = (ImageView) view.findViewById(R.id.icon);holder.title = (TextView)view.findViewById(com.android.internal.R.id.title);holder.summary = (TextView)view.findViewById(com.android.internal.R.id.summary);
//这里就是开关了holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);break;case HEADER_TYPE_NORMAL:
……break;}//这里把这个holder加入到view,需要注意的这个holder还是会变的哦view.setTag(holder);} else {view = convertView;holder = (HeaderViewHolder) view.getTag();}// All view fields must be updated every time, because the view may be recycledswitch (headerType) {case HEADER_TYPE_CATEGORY:holder.title.setText(header.getTitle(getContext().getResources()));break;case HEADER_TYPE_SWITCH:// Would need a different treatment if the main menu had more switchesif (header.id == R.id.wifi_settings) {mWifiEnabler.setSwitch(holder.switch_);} else {//这里会把这个开关和bluetoothEnabler中的开关相关联,具体见1.2.2,这样对这个开关的操作才能真正有所反应,所以这个很关键哦mBluetoothEnabler.setSwitch(holder.switch_);}// No break, fall through on purpose to update common fields//同样注意的是这里没有break//$FALL-THROUGH$case HEADER_TYPE_NORMAL://这里就是把我们每个header对应的icon,title重新设置一下哦。//这样每个header都可以使用自己独有的资源了,了解了吧,呵呵holder.icon.setImageResource(header.iconRes);holder.title.setText(header.getTitle(getContext().getResources()));CharSequence summary = header.getSummary(getContext().getResources());if (!TextUtils.isEmpty(summary)) {holder.summary.setVisibility(View.VISIBLE);holder.summary.setText(summary);} else {holder.summary.setVisibility(View.GONE);}break;}//把这个view返回就可以显示了return view;}

1.2.1 getHeaderType

这个函数用于得到不同header的类型,我们关注的蓝牙是有一个开关的。这个其实从上面图1也是可以看出来的,只有wifi和蓝牙后面有一个开关的按钮,我们来看具体的代码:

static int getHeaderType(Header header) {if (header.fragment == null && header.intent == null) {return HEADER_TYPE_CATEGORY;} else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings) {//wifi和蓝牙就是switch的类型return HEADER_TYPE_SWITCH;} else {return HEADER_TYPE_NORMAL;}}

1.2.2 bluetoothEnablersetSwitch分析

         这个函数的大概作用就是为了把我们ui上的switchbluetoothEnabler相关联,这样我们在ui上点击这个开关的时候才能真正地去打开/关闭蓝牙。具体代码如下:

public void setSwitch(Switch switch_) {
//已经关联过了,就不需要再次关联了if (mSwitch == switch_) return;//把原来开关的监听先清除掉mSwitch.setOnCheckedChangeListener(null);mSwitch = switch_;//这里把开关的操作和自身关联起来,这样你的点击才会真正地起作用mSwitch.setOnCheckedChangeListener(this);//得到当前蓝牙的状态//整个这个地方的state是在开机后所做的操作来实现的,我们在之前的文章中有详细介绍过int bluetoothState = BluetoothAdapter.STATE_OFF;if (mLocalAdapter != null) bluetoothState = mLocalAdapter.getBluetoothState();boolean isOn = bluetoothState == BluetoothAdapter.STATE_ON;boolean isOff = bluetoothState == BluetoothAdapter.STATE_OFF;
//若是当前蓝牙是打开的,这里就会把开关移到打开的那个位置了,所以,我们可以看到,若是蓝牙默认是打开的,ui上开关就是打开的,它的实现就是在这里喽mSwitch.setChecked(isOn);if (WirelessSettings.isRadioAllowed(mContext, Settings.System.RADIO_BLUETOOTH)) {
//允许蓝牙,开关肯定是可见的mSwitch.setEnabled(isOn || isOff);} else {
//若是不运行蓝牙,这个开关就不可见了mSwitch.setEnabled(false);}if (mSupportBtWifiCoexist == false && isWifiAndWifiApStateDisabled() == false) {
//wifi打开了,这里就不能用蓝牙了,当然这个是在wifi和蓝牙不能共存的设置中。。悲催mSwitch.setChecked(false);mSwitch.setEnabled(false);}
}

至此,在打开Settings的时候,我们看到的ui上蓝牙相关的内容已经全部讲解完毕了。回顾一下,总得来说,就是首先有一个header的列表,然后在onBuildHeaders中会把这个列表加载进来,然后根据每个header不同的类型决定是否加入一些别的元素,比如按钮之类的。然后具体关联到bluetooth中去,根据bluetooth当时处于的状态显示对应的按钮状况,如实是否处于打开之类的。大概的流程就是这样了。


若您觉得该文章对您有帮助,请在下面用鼠标轻轻按一下“顶”,哈哈~~·

这篇关于眼花缭乱的UI,蓝牙位于何方的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1079331

相关文章

element-ui下拉输入框+resetFields无法回显的问题解决

《element-ui下拉输入框+resetFields无法回显的问题解决》本文主要介绍了在使用ElementUI的下拉输入框时,点击重置按钮后输入框无法回显数据的问题,具有一定的参考价值,感兴趣的... 目录描述原因问题重现解决方案方法一方法二总结描述第一次进入页面,不做任何操作,点击重置按钮,再进行下

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

开放式耳机好用?平价开放式耳机推荐?四款开放式的蓝牙耳机推荐

开放式耳机好用吗?有平价些的开放式耳机推荐吗?那这两个问题的回答当然是肯定的。 首先开放式耳机好不好用取决于对耳机的需求,因为开放式耳机其实是比较适用于需要注意周围环境、需要‌长时间佩戴舒适以及需要频繁与人交流的场景中,在这些场景下使用开放式耳机的话就会比较有优势。就例如跑步骑行健身等运动的时候,能够兼得佩戴舒适度的同时,增加一定的安全性;还有在办公学习的时候,会很适合长时间佩戴,能够方便和

Golang GUI入门——andlabs ui

官方不提供gui标准库,只好寻求第三方库。 https://github.com/google/gxui 这个gui库是谷歌内部人员提供的,并不是谷歌官方出品,现在停止维护,只好作罢。 第三方gui库 找了好多,也比较了好多,最终决定使用的是还是 https://github.com/andlabs/ui 相信golang gui还会发展的更好,期待更优秀的gui库 由于andlabs

Flutter 中的低功耗蓝牙概述

随着智能设备数量的增加,控制这些设备的需求也在增加。对于多种使用情况,期望设备在需要进行控制的同时连接到互联网会受到很大限制,因此是不可行的。在这些情况下,使用低功耗蓝牙(也称为 Bluetooth LE 或 BLE)似乎是最佳选择,因为它功耗低,在我们的手机中无处不在,而且无需连接到更广泛的网络。因此,蓝牙应用程序的需求也在不断增长。 通过阅读本文,您将了解如何开始在 Flutter 中开

移动UI:分类列表页、筛选页的设计揭秘。

移动UI的列表页设计需要考虑用户体验和界面美观性,以下是一些建议的设计要点: 1. 列表项的展示: 列表页应该清晰地展示各个列表项,包括标题、副标题、缩略图等内容,以便用户快速浏览和识别。可以使用卡片式布局或者简洁的列表布局。 2. 搜索和筛选: 如果列表项较多,应该提供搜索和筛选功能,方便用户查找感兴趣的内容。搜索框和筛选条件可以放置在页面顶部或者底部,以便用户方便操作。

UI自动化测试常见面试题

1、什么是UI自动化测试? UI自动化测试是一种通过模拟用户交互并自动执行UI操作的软件测试方法。它用于验证用户界面的功能和稳定性,以确保在不同的操作系统、浏览器和设备上的一致性。 2、UI自动化测试的优势和劣势是什么? 优势: 可以节省时间和成本,提高测试效率。 可以自动执行大量的重复测试任务,减少人为错误。 可以实现广泛的测试覆盖,包括不同的操作系统、浏览器和设备。 可以提供稳定

开放式蓝牙耳机哪个品牌好用?盘点五款超优秀的开放式耳机!

开放式蓝牙耳机现在挺受欢迎的,它们最大的好处就是不塞耳朵,戴着舒服,特别适合长时间佩戴。而且,这种耳机能让你在听音乐的同时,还能听到周围的环境声,这样在外面运动或者骑车的时候就更安全。音质方面,现在的开放式耳机也做得越来越好,有些高端款式还有特别的技术来减少漏音,保护你的隐私。但是现在市场上的开放式耳机品牌太多了,很多人不知道怎么选?为了帮助您在众多选项中做出选择,我根据个人经验挑选了一些表现良好

2024 年,数据中台引领企业走向何方?

2024 年,数据中台引领企业走向何方? 前言数据中台引领企业走向何方 前言 在当今数字化时代,数据已成为企业发展的核心资产。随着企业业务的不断扩展和数据量的急剧增长,如何有效地管理和利用数据,成为企业面临的重要挑战。数据中台作为一种新兴的技术解决方案,应运而生,为企业提供了数据整合、管理和分析的一体化平台,帮助企业实现数据驱动的决策和业务创新。 深入探讨了数据中台的概念、功能

Anroid BLE蓝牙(手机分别作为中心设备和外围设备)

蓝牙是一种短距的无线通讯技术,可实现固定设备、移动设备之间的数据交换。一般将蓝牙3.0之前的BR/EDR蓝牙称为传统蓝牙,而将蓝牙4.0规范下的LE蓝牙称为低功耗蓝牙。  BLE蓝牙模块主要应用领域     1、移动扩展设备     2、汽车电子设备     3、健康医疗用品:心跳带、血压计等     4、定位应用:室内定位、井下定位等     5、近距离数据采集:无线