想实现一个 Android APP 扫描附近 BLE 蓝牙设备,并显示其服务、特性 UUID,及对应 Handle,CCCD。 尽量能自动化,并加快目前一个项目中用到的蓝牙网关配对的过程。
界面展示类似于列表加详情页的形式,恰好 Android Studio 里内置了这种模板,即 Primary/Detail Flow。
里面的列表页与详情页是用两个独立的 Fragment 实现的。
入口在哪里
因为 Fragment 并不能单独使用,他需要嵌套在 Activity 中使用。
> tree app/src/main/java/com/sunzhongwei/ble/
app/src/main/java/com/sunzhongwei/ble/
├── ItemDetailFragment.kt // 详情页
├── ItemDetailHostActivity.kt // 主 Activity
├── ItemListFragment.kt // 列表页
└── placeholder
└── PlaceholderContent.kt // 填充用的测试数据
1 directory, 4 files
猜测是 ItemDetailHostActivity.kt,但是这个文件名有极大的歧义,所以我不是很确定。
实际上在 AndroidManifest.xml 中就能看到入口的 Activity。
<activity
android:name=".ItemDetailHostActivity"
android:exported="true"
android:label="@string/app_name"
android:resizeableActivity="true"
tools:targetApi="24">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
填充的测试数据在哪里
placeholder/PlaceholderContent.kt
object PlaceholderContent {
val ITEMS: MutableList<PlaceholderItem> = ArrayList()
val ITEM_MAP: MutableMap<String, PlaceholderItem> = HashMap()
private val COUNT = 25
init {
// Add some sample items.
for (i in 1..COUNT) {
addItem(createPlaceholderItem(i))
}
}
private fun addItem(item: PlaceholderItem) {
ITEMS.add(item)
ITEM_MAP.put(item.id, item)
}
private fun createPlaceholderItem(position: Int): PlaceholderItem {
return PlaceholderItem(position.toString(), "Item " + position, makeDetails(position))
}
private fun makeDetails(position: Int): String {
}
data class PlaceholderItem(val id: String, val content: String, val details: String) {
override fun toString(): String = content
}
}
tips:kotlin 中 object 与 class 的区别。
navigation router 在哪里
activity layout xml 中有个:
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment_item_detail"
android:name="androidx.navigation.fragment.NavHostFragment"
app:defaultNavHost="true"
app:navGraph="@navigation/primary_details_nav_graph"
tools:layout="@layout/fragment_item_detail" />
FragmentContainerView 用来切换 list 与 detail fragment。
- FragmentContainerView 使用 android:name 指定的名字创建一个 Fragment。
- app:navGraph 指向了 graph。这里面就是 router 逻辑。
而不需要切换的则如下面这种布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android">
<fragment android:name="com.example.news.ArticleListFragment"
android:id="@+id/list" />
<fragment android:name="com.example.news.ArticleReaderFragment"
android:id="@+id/viewer" />
</LinearLayout>
activity 中的逻辑:
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.nav_host_fragment_item_detail) as NavHostFragment
val navController = navHostFragment.navController
appBarConfiguration = AppBarConfiguration(navController.graph)
setupActionBarWithNavController(navController, appBarConfiguration)
tips: 其他内容可以参考之前整理的 Android Navigation 组件。
参考
- https://developer.android.com/reference/androidx/fragment/app/FragmentContainerView
微信关注我哦 👍
我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式