我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android BlueToothBLE入门(二)——设备的连接和通讯(附Demo源码地址)

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android BlueToothBLE入门(二)——设备的连接和通讯(附Demo源码地址)

学更好的别人,

做更好的自己。

——《微卡智享》

f98a7c1995354157b92adeec3f3f0d95.jpeg

本文长度为7870,预计阅读12分钟

前言

接《Android BlueToothBLE入门(一)——低功耗蓝牙介绍》上篇,这篇文章主要就是来做Demo实现Android两台设备的数据通讯。

265be150c55a258e1f6706ac4b187866.png

实现效果

a9419e281e36da4547eac0c7a83bfeab.jpeg

Android BLE Demo简介

256e157d1778e648caefe10bac58b2a3.png

微卡智享

01

目录及使用的组件

5b702abca0dd6934c392134519936e8c.png

整个Demo的目录上图中已经做了说明,其中最核心的是BlueToothBLEUtil类,这是把这个Demo中用到的BLE蓝牙方法都放到这里了,因为中心设备(Client)和外围设备(Server)统一用的这个程序,所以这个类里面中心设备和外围设备用到的都做了一个封装,当时还有不少要加的,后面会再补充。

Demo使用的MVI架构(Jeppack Compose还不会,所以用的viewBinding),像RecyclerView的适配器这块还是使用的BaseQuickAdapter,现在4.0在测试过程中了,所以我直接用的4.0beta版,蓝牙权限的申请采用了easypermissions,确实比自己写方便了许多。

build.gradle相关依赖项

09dcaad06b31cb7f24cc55c73f24c631.png

dependencies {    'androidx.lifecycle:lifecycle-livedata-ktx:2.4.1'    'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1'    'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1'    //使用协程    "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4"    "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"    "io.github.cymchad:BaseRecyclerViewAdapterHelper:4.0.0-beta04"    // 使用 Android X 的应用添加该依赖    'pub.devrel:easypermissions:3.0.0'}

02

蓝牙核心类BlueToothBLEUtil

外围设备和中心设备通讯,我们就用自己定义的服务即可,所以类中我们已经定义好常量来实现。

上一篇介绍过蓝牙技术联盟SIG定义UUID共用了一个基本的UUID:0x0000xxxx-0000-1000-8000-00805F9B34FB。总共128位,为了进一步简化基本UUID,每一个蓝牙技术联盟定义的属性有一个唯一的16位UUID,以代替上面的基本UUID的‘x’部分。使用16位的UUID便于记忆和操作。

所以类中我们定义的服务UUID只是中间xxxx四位即可,写了一个函数来直接生成对应的UUID

5bbfc6913293fc3e1a4747e010ab39b5.png

1489f97e1ade6e92d179a7221d9734e5.png

代码中使用BLE蓝牙相关Api时,Android Studio会经常提示要先判断是否有蓝牙权限,所以这里也是把蓝牙是否做过初始化,和判断是否有相关的蓝牙权限写了一个函数调用

1d1ee7d358d67e675fcc1edbe7d1e755.png

蓝牙权限

9befaca7fc6d9872dbdac39d75a078d2.png

检测是否有相关权限

231d91049d1188143156cd4a89b930cc.png

调用蓝牙API时先检测是否有对应的权限

像扫描设备,连接设备时需要知道返回的结果,用到了回调,那类中直接就是传入相磁的CallBack回调函数,在UI界面写回调函数即可。如下面这个扫描蓝牙设备函数

f61a3c4d0586d22469834111bb540efb.png

参数为ScanCallback

3c54c36d841f4df2168248b6466b4924.png

ScanFragment中定义ScanCallback,实现onScanResult中发送意图

5c532a8aa4f6ef4c26470a42a0757f13.png

点击扫描设备直接调用类中函数并传入回调函数

BlueToothBLEUtil源码

package vac.test.bluetoothbledemo.repositoryimport android.Manifestimport android.app.Applicationimport android.bluetooth.BluetoothAdapterimport android.bluetooth.BluetoothDeviceimport android.bluetooth.BluetoothGattimport android.bluetooth.BluetoothGattCallbackimport android.bluetooth.BluetoothGattCharacteristicimport android.bluetooth.BluetoothGattDescriptorimport android.bluetooth.BluetoothGattServerimport android.bluetooth.BluetoothGattServerCallbackimport android.bluetooth.BluetoothGattServiceimport android.bluetooth.BluetoothManagerimport android.bluetooth.le.AdvertiseCallbackimport android.bluetooth.le.AdvertiseDataimport android.bluetooth.le.AdvertiseSettingsimport android.bluetooth.le.BluetoothLeAdvertiserimport android.bluetooth.le.ScanCallbackimport android.bluetooth.le.ScanFilterimport android.bluetooth.le.ScanSettingsimport android.content.Contextimport android.content.pm.PackageManagerimport android.os.Buildimport android.os.ParcelUuidimport android.util.Logimport android.widget.Toastimport androidx.core.app.ActivityCompatimport kotlinx.coroutines.CoroutineScopeimport kotlinx.coroutines.Dispatchersimport kotlinx.coroutines.delayimport kotlinx.coroutines.launchimport pub.devrel.easypermissions.AfterPermissionGrantedimport pub.devrel.easypermissions.EasyPermissionsimport vac.test.bluetoothbledemo.BaseAppimport vac.test.bluetoothbledemo.EncodeUtilimport vac.test.bluetoothbledemo.bytesToHexStringimport vac.test.bluetoothbledemo.ui.MainActivityimport java.io.IOExceptionimport java.util.UUIDobject BlueToothBLEUtil {    //服务 UUID    const val BLESERVER = "2603"    //特征 UUID    const val BLECHARACTERISTIC = "ca01"    //描述 UUID    const val BLEDESCRIPTOR = "da01"    //蓝牙相关权限    const val REQUEST_CODE_PERMISSIONS = 10    val REQUIRED_BLEPERMISSIONS = arrayOf(        Manifest.permission.BLUETOOTH, Manifest.permission.BLUETOOTH_ADMIN,        Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN,        Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.BLUETOOTH_ADVERTISE    )    private var mBluetoothManager: BluetoothManager? = null    private var mBluetoothAdapter: BluetoothAdapter? = null    private var mBluetoothGattService: BluetoothGattService? = null    private var mBluetoothGattServer: BluetoothGattServer? = null    private var mBluetoothDevice: BluetoothDevice? = null    private var mBluetoothGatt: BluetoothGatt? = null    //BLE广播操作类    private var mBluetoothLeAdvertiser: BluetoothLeAdvertiser? = null    //是否初始化    var hasInit = false    lateinit var mApplication: Application    //检测蓝牙权限    fun checkBlueToothPermission(permissions: String = ""): Boolean {        if (!hasInit) throw IOException("未初始化蓝牙BlueTooth!")        if (permissions == "") return true        return ActivityCompat.checkSelfPermission(            mApplication.applicationContext,            permissions        ) == PackageManager.PERMISSION_GRANTED    }    fun init(application: Application): Boolean {        if (hasInit) return true        mApplication = application        //初始化ble设配器        mBluetoothManager =            mApplication.applicationContext.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager        //初始化适配器        mBluetoothAdapter = mBluetoothManager!!.adapter        hasInit = true        return hasInit    }    fun destory() {        mBluetoothGatt = null        mBluetoothDevice = null        mBluetoothGattService = null        mBluetoothAdapter = null        hasInit = false    }    //获取UUID        fun getUUID(baseuuid: String): UUID {        return UUID.fromString("0000${baseuuid}-0000-1000-8000-00805f9b34fb")    }    //广播时间(设置为0则持续广播)    val Time = 0    //是否在扫描中    private var mScanning: Boolean = false    //获取BluetoothManager    fun getBluetoothManager(): BluetoothManager? {        return if (checkBlueToothPermission()) {            mBluetoothManager        } else {            null        }    }    //获取BluetoothAdapter    fun getBluetoothAdapter(): BluetoothAdapter? {        return if (checkBlueToothPermission()) {            mBluetoothAdapter        } else {            null        }    }    //region 服务端外围设备相关函数        //获取Gatt服务    fun getGattService(): BluetoothGattService {        //初始化Service        //创建服务,并初始化服务的UUID和服务类型。        //BluetoothGattService.SERVICE_TYPE_PRIMARY 为主要服务类型        val mGattService = BluetoothGattService(            getUUID(BLESERVER),            BluetoothGattService.SERVICE_TYPE_PRIMARY        )        //初始化特征(添加读写权限)        //在服务端配置特征时,设置BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE,        //那么onCharacteristicWriteRequest()回调时,不需要GattServer进行response才能进行响应。        val mGattCharacteristic = BluetoothGattCharacteristic(            getUUID(BLECHARACTERISTIC),            BluetoothGattCharacteristic.PROPERTY_WRITE or                    BluetoothGattCharacteristic.PROPERTY_NOTIFY or                    BluetoothGattCharacteristic.PROPERTY_READ,            (BluetoothGattCharacteristic.PERMISSION_WRITE or BluetoothGattCharacteristic.PERMISSION_READ)        )        //初始化描述        val mGattDescriptor = BluetoothGattDescriptor(            getUUID(BLEDESCRIPTOR),            BluetoothGattDescriptor.PERMISSION_READ or BluetoothGattDescriptor.PERMISSION_WRITE        )        //Service添加特征值        mGattService.addCharacteristic(mGattCharacteristic)        //特征值添加描述        mGattCharacteristic.addDescriptor(mGattDescriptor)        return mGattService    }    //添加服务    fun addGattServer(mGattServerCallback: BluetoothGattServerCallback) {        if (checkBlueToothPermission(Manifest.permission.BLUETOOTH_CONNECT)) {            mBluetoothGattService = getGattService()            mBluetoothGattServer =                mBluetoothManager!!.openGattServer(                    mApplication.applicationContext, mGattServerCallback                )            mBluetoothGattServer!!.addService(mBluetoothGattService)        }    }    //开启广播    //官网建议获取mBluetoothLeAdvertiser时,先做mBluetoothAdapter.isMultipleAdvertisementSupported判断,    // 但部分华为手机支持Ble广播却还是返回false,所以最后以mBluetoothLeAdvertiser是否不为空且蓝牙打开为准    fun startAdvertising(phonename: String, mAdvertiseCallback: AdvertiseCallback): Boolean {        if (checkBlueToothPermission(Manifest.permission.BLUETOOTH_CONNECT)) {            mBluetoothAdapter!!.name = phonename            mBluetoothLeAdvertiser = mBluetoothAdapter!!.bluetoothLeAdvertiser            //蓝牙关闭或者不支持            return if (mBluetoothLeAdvertiser != null && mBluetoothAdapter!!.isEnabled) {                Log.d(                    "pkg", "mBluetoothLeAdvertiser != null = ${mBluetoothLeAdvertiser != null} " +"mBluetoothAdapter.isMultipleAdvertisementSupported = ${mBluetoothAdapter!!.isMultipleAdvertisementSupported}"                )                //开始广播(不附带扫描响应报文)                mBluetoothLeAdvertiser?.startAdvertising(                    getAdvertiseSettings(),                    getAdvertiseData(), mAdvertiseCallback                )                true            } else {                false            }        } else {            return false        }    }    //关闭蓝牙广播    fun stopAdvertising(mAdvertiseCallback: AdvertiseCallback): Boolean {        if (checkBlueToothPermission(Manifest.permission.BLUETOOTH_ADVERTISE)) {            mBluetoothLeAdvertiser?.let { advertiser ->                advertiser.stopAdvertising(mAdvertiseCallback)            }            return true        } else {            return false        }    }    //endregion    fun scanBlueToothDevice(scancallback: ScanCallback) {        if (mScanning) return        if (checkBlueToothPermission(Manifest.permission.BLUETOOTH_SCAN)) {            //扫描设置                        val builder = ScanSettings.Builder()                .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)                        builder.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)            //判断手机蓝牙芯片是否支持皮批处理扫描            if (mBluetoothAdapter!!.isOffloadedFilteringSupported) {                builder.setReportDelay(0L)            }            mScanning = true            //3秒后关闭            CoroutineScope(Dispatchers.IO).launch {                delay(6000)                stopScanBlueToothDevice(scancallback)                Log.i("bluetooth", "关闭扫描")            }            //过滤掉不是自己程序发送的广播            val filter = getScanFilter()            mBluetoothAdapter!!.bluetoothLeScanner?.startScan(filter, builder.build(), scancallback)            //过滤特定的 UUID 设备            //bluetoothAdapter?.bluetoothLeScanner?.startScan()        }    }    fun stopScanBlueToothDevice(scancallback: ScanCallback) {        //连接时要先关闭扫描        if (mScanning) {            if (checkBlueToothPermission(Manifest.permission.BLUETOOTH_SCAN)) {                mBluetoothAdapter!!.bluetoothLeScanner?.stopScan(scancallback)                mScanning = false            }        }    }    //初始化广播设置    fun getAdvertiseSettings(): AdvertiseSettings {        //初始化广播设置        return AdvertiseSettings.Builder()            //设置广播模式,以控制广播的功率和延迟。ADVERTISE_MODE_LOW_LATENCY为高功率,低延迟            .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER)            //设置蓝牙广播发射功率级别            .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_LOW)            //广播时限。最多180000毫秒。值为0将禁用时间限制。(不设置则为无限广播时长)            .setTimeout(Time)            //设置广告类型是可连接还是不可连接。            .setConnectable(true)            .build()    }    //设置广播报文    fun getAdvertiseData(): AdvertiseData {        return AdvertiseData.Builder()            //设置广播包中是否包含设备名称。            .setIncludeDeviceName(true)            //设置广播包中是否包含发射功率            .setIncludeTxPowerLevel(true)            //设置UUID            .addServiceUuid(ParcelUuid(getUUID(BLESERVER)))            .build()    }    //设置扫描过滤    fun getScanFilter(): ArrayList {        val scanFilterList = ArrayList()        val builder = ScanFilter.Builder()        builder.setServiceUuid(ParcelUuid(getUUID(BLESERVER)))        scanFilterList.add(builder.build())        return scanFilterList    }    //获取原生蓝牙对象    fun getBlueToothDevice(macAddress: String): BluetoothDevice? {        return if (checkBlueToothPermission()) {            mBluetoothDevice = mBluetoothAdapter!!.getRemoteDevice(macAddress)            if (mBluetoothDevice == null) throw IOException("获取不到BluetoothDevice")            mBluetoothDevice!!        } else {            null        }    }    //申请通讯字节长度    fun requestMTP(size: Int = 512): Boolean {        return if (checkBlueToothPermission()) {            mBluetoothGatt?.let {                it.requestMtu(size)            } ?: false        } else {            false        }    }    //连接蓝牙Gatt    fun connect(macAddress: String, callback: BluetoothGattCallback): BluetoothGatt? {        return if (checkBlueToothPermission(Manifest.permission.BLUETOOTH_CONNECT)) {            if (mBluetoothDevice == null)                getBlueToothDevice(macAddress)            mBluetoothGatt =                mBluetoothDevice!!.connectGatt(mApplication.applicationContext, false, callback)            mBluetoothGatt        } else {            null        }    }    //断开蓝牙Gatt    fun disConnect() {        if (checkBlueToothPermission(Manifest.permission.BLUETOOTH_CONNECT)) {            mBluetoothGatt?.let {                it.disconnect()                //调用close()后,连接时传入callback会被置空,无法得到断开连接时onConnectionStateChange()回调                it.close()            }        }    }    //获取蓝牙GattService    fun getBlueToothGattService(gatt: BluetoothGatt): List {        return gatt.services    }    //发送Characteristic    fun writeCharacteristic(        srvuuid: String,        charuuid: String,        byteArray: ByteArray    ) {        if (checkBlueToothPermission(Manifest.permission.BLUETOOTH_CONNECT)) {            mBluetoothGatt?.let {                val characteristic =                    it.getService(getUUID(srvuuid)).getCharacteristic(getUUID(charuuid))                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {                    it.writeCharacteristic(                        characteristic,                        byteArray,                        BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE                    )                } else {                    characteristic.setValue(byteArray)                    it.writeCharacteristic(characteristic)                }            } ?: {                throw IOException("mBluetoothGatt为空")            }        }    }    //发送Characteristic    fun writeCharacteristic(        characteristic: BluetoothGattCharacteristic,        byteArray: ByteArray    ) {        if (checkBlueToothPermission(Manifest.permission.BLUETOOTH_CONNECT)) {//        var hexstr = byteArrsyToHexString(byteArray)//        var transbytes = hexstr!!.toByteArray()            mBluetoothGatt?.let {                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {                    it.writeCharacteristic(                        characteristic,                        byteArray,                        BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE                    )                } else {                    characteristic.setValue(byteArray)                    it.writeCharacteristic(characteristic)                }            } ?: {                throw IOException("mBluetoothGatt为空")            }        }    }    fun readCharacteristic(characteristic: BluetoothGattCharacteristic): ByteArray? {        return if (checkBlueToothPermission(Manifest.permission.BLUETOOTH_CONNECT)) {            var byteArray: ByteArray? = null            mBluetoothGatt?.let {                it.readCharacteristic(characteristic)                byteArray = characteristic.value            }            byteArray        } else {            null        }    }    //发送返回值sendResponse    fun sendResponse(        device: BluetoothDevice, requestId: Int, offset: Int, value: ByteArray    ) {        if (checkBlueToothPermission(Manifest.permission.BLUETOOTH_CONNECT)) {            mBluetoothGattServer!!.sendResponse(                device, requestId, BluetoothGatt.GATT_SUCCESS,                offset, value            )        }    }    fun setCharacteristicNotify(characteristic: BluetoothGattCharacteristic, bool: Boolean) {        if (checkBlueToothPermission(Manifest.permission.BLUETOOTH_CONNECT)) {            mBluetoothGatt?.let {                it.setCharacteristicNotification(characteristic, bool)            }        }    }    fun notifyCharacteristicChanged(        device: BluetoothDevice,        characteristic: BluetoothGattCharacteristic,        byteArray: ByteArray    ) {        if (checkBlueToothPermission(Manifest.permission.BLUETOOTH_CONNECT)) {            //回复客户端,让客户端读取该特征新赋予的值,获取由服务端发送的数据            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {                mBluetoothGattServer!!.notifyCharacteristicChanged(                    device,                    characteristic,                    false,                    byteArray                )            } else {                characteristic.value = byteArray                mBluetoothGattServer!!.notifyCharacteristicChanged(device, characteristic, false)            }        }    }}

03

适配器BaseQuickAdapter

0版本的BaseQuickAdapter,里面的ViewHolder要自己定义,用法和原来有点不太一样

6ccfbcf7337f99f3db16804e18e242f6.png

41bc85769100e1b49234d69a87e2caa2.png

还有原来我用BaseQuickAdapter中直接用的二级列表,当时也是会有问题,具体问题可以看《Android BaseQuickAdapter3.0.4版本二级列表的使用及遇到的问题》,正好这次服务的列表刷新中又需要实现二级列表,现在我是改为自定义添加了,同样绑定了viewBinding。

40fdcf34d78bbe061f6cd00cb4f5b79e.png

68ca2469271136e75b01b846e913a722.png

04

Fragment中使用ViewBinding注意事项

在Fragment中使用viewBinding,为了防止内存泄漏,Google有标准的写法,不过每个Fragment都这样写比较麻烦,所以这里定义了一个BaseFragment,用于处理viewBinding内存泄露问题。

abstract class BaseFragment : Fragment() {    private var _binding: T? = null    protected val binding: T get() = _binding!!    abstract val bindingInflater: (LayoutInflater, ViewGroup?, Bundle?) -> T    override fun onCreateView(        inflater: LayoutInflater,        container: ViewGroup?,        savedInstanceState: Bundle?    ): View {        _binding = bindingInflater.invoke(inflater, container, savedInstanceState)        return binding.root    }    override fun onDestroyView() {        super.onDestroyView()        _binding = null    }}

aaff3b28a61a7b999318d1a01ec83946.png

这样一个基本的蓝牙Ble通讯就完成了。

后续问题

上面的视频中通讯传输是没问题,但是如果发送大点的数据,就不行了,蓝牙BLE发送数据默认单次最大传输20个byte,如果是一般的协议命令,如:开关灯、前进左右等等,是没有问题的,如果是需要发送如:图片、BIN文档、音乐等大数据量的文件,则需要做数据的处理。

基本说考虑到蓝牙发送大数据量时应该通过两个途径结合实现:

  1. 申请修改MTU值,MTU: 最大传输单元(MAXIMUM TRANSMISSION UNIT)

  2. 分包数据发送

简单的通讯Demo实现后,接下来就准备开始研究分包通讯的问题了。

源码地址

https://github.com/Vaccae/AndroidBLEDemo.git

点击原文链接可以看到“码云”的源码地址

b555b12c37de5bcf8a19d835eb445af1.png

f17be96a3f171ddee3a8d5048af22020.png

往期精彩回顾

 

51110eba9a28ec644b8f640c1c437822.jpeg

Android BlueToothBLE入门(一)——低功耗蓝牙介绍

 

 

9132f2df2517286d7a36a8a289f0a1c6.jpeg

Android监听消息(二)——电话及短信监听

 

 

557e546de405bbff90b2fe4225d807f9.jpeg

Android监听消息(一)——应用消息捕获

 

来源地址:https://blog.csdn.net/Vaccae/article/details/131179791

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android BlueToothBLE入门(二)——设备的连接和通讯(附Demo源码地址)

下载Word文档到电脑,方便收藏和打印~

下载Word文档

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录