Android

分类下相关文章

Android API 无法获取蓝牙 BLE Attribute Handle 值

最近写了一个 Android APP 用于快速配置蓝牙网关(已上架 Google Play),但是基本功能完成后, 发现无法获取指定特性 (characteristic) / 描述符 (descriptor) 的 handle 值。 handle 存在的意义 Handle 的全称是 Attribute Handle。 在用 Android API 实现这个 BLE 扫描 APP 的过程中,我发现无论是服务,还是特性、描述符其 UUID 都是可能重复的。 举个例子,如果一个蓝牙设备包含两个电池模块,则存在两个相同服务的 UUID 是合理的。 那么用 UUID 来标识一个服务/特性/描述符就不合理 ...

阅读全文...

BLE Scan: Privacy policy

Welcome to the BLE Scan app for Android! This is an Android app developed by Zhongwei Sun. The app is available on Google Play. As an avid Android user myself, I take privacy very seriously. I know how irritating it is when apps collect your data without your knowledge. I hereby state, to the best o ...

阅读全文...

Material dialogs MaterialAlertDialogBuilder 中添加文本编辑框

setView 官方 Material Design 3 的文档中并没有详细的 MaterialAlertDialogBuilder 使用说明。 https://github.com/material-components/material-components-android/blob/master/docs/components/Dialog.md 找不到如何在里面添加文本编辑框。 但是在接口文档中可以看到有一个 setView 的方法 https://developer.android.com/reference/com/google/android/material/dialog/Ma ...

阅读全文...

Android 哪些操作应该放到 ViewModel 中

权限申请是否应该放到 ViewModel 中 有此疑问的原因是,我看到权限相关的操作,需要传入 Context 参数。 private fun isLocationPermissionGranted(): Boolean { return ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED } 而 Context 只能在 Activity / Fragment / View 中得到。 ...

阅读全文...

Android RecyclerView Adapter ViewHolder 中获取 Activity

之前记录过如何在 Fragment 中获取父级 Activity,这次发现需要在 RecyclerView Adapter ViewHolder 中获取 Activity。 简单来说,就是: get Context from the view 例如,ViewHolder 中包含一个 text view 用来显示姓名,可以借此获取 context,从而得到 Activity. (binding.name.context as ItemDetailHostActivity).stopSomething() 实际应用场景 例如,在各种嵌套的 RecyclerView Adapter 中想访 ...

阅读全文...

Android 使用 LiveData 显示实时状态变化

例如加载数据时, 显示转圈提示。或者显示 connecting / finding data ... 也可以加上动态图标: https://github.com/material-components/material-components-android/blob/master/docs/components/ProgressIndicator.md 用最下面的转圈图标非常直观。 注意还有失败的情况,比如列表中蓝牙设备消失或关闭。 状态放在哪里 还是存储在 ViewModel 中最合适。 同时在 activity / fragment 中对状态 LiveData 进行监听。 LiveData ...

阅读全文...

Android RecyclerView 嵌套显示 BLE 蓝牙 Service 的 Characteristic 子项

例如,外层 RecyclerView 显示的是一个 BLE 蓝牙设备的 Service 列表; 内存嵌套的 RecyclerView 显示的各个 Service 所包含的 Characteristic 特性列表。 点击展开 Service,显示其所包含的特性。 RecyclerView 嵌套 首先在父级 RecyclerView 的 Item Layout 中定义一个子 RecyclerView 控件 嵌套的 RecyclerViewAdapter 绑定逻辑,在父级 RecyclerViewAdapter 的 onBindViewHolder 中实现 item:BluetoothGattC ...

阅读全文...

Android Kotlin 中获取 context 的几种方法

Fragment 中获取 context 调用 getActivity 获取父级 activity 的 context, Kotlin 中简化为 fragment.activity: 例如: Toast.makeText( activity, "Start Scanning", Toast.LENGTH_SHORT ).show() RecyclerViewAdapter 中获取 context 使用 layout 中 view (每个小控件就是一个 view) 的 getContext 方法, Kotlin 中即简化为 view.context: 例如: recyc ...

阅读全文...

Android Primary/Detail Flow 模板的 fragment 点击跳转逻辑

TODO 看懂原有 primary/detail 模板的跳转逻辑 新建 snippet list fragment override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val itemDetailFragmentContainer: View? = view.findViewById(R.id.item_detail_nav_container) setupRecyclerView(recyclerView, itemDetailFragmentContainer) } private ...

阅读全文...

Android 复制文本到系统剪切板

需求 我正在开发的一个 Android App,其主要功能就是将扫描出来的蓝牙设备信息,自动复制到手机剪切板。 然后复制到其他需要配置的地方。 例如,点击蓝牙设备的 Mac 地址,自动写入剪切板。 复杂的实现 看了官方文档,发现要实现这么个简单的功能,远比想象中复杂。 https://developer.android.com/develop/ui/views/touch-and-input/copy-paste 操作反馈。Android 13 之后,在写入剪切板之后,会有自动的提示。而低版本就需要自己去实现提示,Toasts 或者 Snackbars。 fragment 与 activit ...

阅读全文...

android fragment 中调用父级 activity 中定义的方法

需求场景 一个 list / detail 的小 android app,分为两个 fragment 置于一个 activity 中。 list fragment 底部一个按钮,点击需要调用 activity 中的一个方法。 解决方法 (activity as YourActivityClassName).methodName() 实际上这个问题可以简化为,如何在 fragment 中获取其父级 activity。 由于 fragment 必然寄生于一个宿主 activity,所以可以直接通过 getActivity() 方法来得到宿主 activity,而 Kotlin 中则可以简写为 a ...

阅读全文...

registerForActivityResult 解决 startActivityForResult(Intent!, Int): Unit is deprecated. Deprecated in Java

举两个例子 例子一:开启蓝牙 废弃的 startActivityForResult 写法: const val ENABLE_BLUETOOTH_REQUEST_CODE = 1 val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) startActivityForResult(enableBtIntent, ENABLE_BLUETOOTH_REQUEST_CODE) 新的 registerForActivityResult 写法: val enableBtIntent = Intent(Bluetooth ...

阅读全文...

设置 Android Studio 在保存时自动对代码进行格式化

写 Android 还是用 Android Studio 能快一点,毕竟我这种入门级开发者,东拼西凑的代码,很容易出现各种警告、错误,用 Android Studio 的自动修复非常节省时间。这一点甚至比 Visual Studio 都强大许多。 但是,唯一不爽的是,AS 没有默认开启代码的自动格式化。 这个对我来说太重要了,习惯了 VIM 里对 golang,js 等代码的自动格式化,很难回头。 开启保存时自动格式化 Android Studio 版本:Dolphin 2021.3.1 build on September 1, 2022 File - Settings - Tools - ...

阅读全文...

Android LiveData

可以包含任何类型的数据,通过监听 LiveData,在数据发生变化时,可以立即得到通知。 LiveData 与 ViewModel 通常 LiveData 定义在 ViewModel 中,然后在 Activity / Fragment 中监听 LiveData 的变化。 不在 Activity 中定义 LiveData,原因有两点: 防止 Activity / Fragment 过于臃肿。要分工明确:Activity / Fragment 只负责显示数据;ViewModel 负责存储数据及状态。 防止 Activity 因屏幕旋转被销毁,状态数据消失。而存在 ViewModel 中就能很好的 ...

阅读全文...

'constructor Handler()' is deprecated. Deprecated in Java

使用 Android 官方文档的示例代码,10 秒后停止扫描附近的蓝牙设备,报错: 有问题的代码 import android.os.Handler private val handler = Handler() handler.postDelayed({ scanning = false bluetoothLeScanner.stopScan(leScanCallback) }, SCAN_PERIOD) 警告提示: 'constructor Handler()' is deprecated. Deprecated in Java 解决方法 import android.os. ...

阅读全文...