Android Studio中蓝牙发送.txt文件无法弹出设备选择窗口报错求解
问题原因
你遇到的两个报错和蓝牙窗口不弹出的问题核心来自三个错误:
Fail to get file list com.example.apptest:蓝牙OPP传输进程没有权限读取你的APP私有目录下的文件,你未给目标应用授予FileProvider的临时访问权限,同时可能存在FileProvider路径配置错误。getFolderSize() : Exception_1 = java.lang.NullPointerException: Attempt to get length of null array:蓝牙进程读取文件内容失败,获取文件大小的时候拿到空数组触发空指针,通常是文件未写入完成、或无权限读取文件导致。- 硬编码蓝牙组件类名:不同厂商的系统蓝牙应用包名、类名可能存在定制修改,硬编码
com.android.bluetooth.opp.BluetoothOppLauncherActivity会导致大量机型无法匹配到对应的页面,自然弹不出选择窗口。
修复步骤
1. 配置正确的FileProvider路径
检查你res/xml目录下的FileProvider配置文件(默认命名为file_paths.xml),添加你存储文件的私有目录映射:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 对应getDir("DirFile", MODE_PRIVATE)生成的app_DirFile目录 --> <files-path name="shared_dir" path="../app_DirFile/" /> </paths>
同时确认AndroidManifest.xml中已经正确注册FileProvider:
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
2. 给Intent添加临时读取权限
传输文件时需要给接收Intent的应用授予Uri的临时读取权限,否则蓝牙进程无法访问你提供的文件路径。
3. 写入文件后主动flush缓冲区
数据写入FileOutputStream后会先存在内存缓冲区,需要主动flush才能确保数据落地到磁盘,避免读取到空文件。
4. 移除硬编码的蓝牙组件名,使用系统通用选择器
不要写死蓝牙的类名,使用Intent.createChooser让系统自动匹配支持分享的应用,兼容性更好。
修复后的完整代码
public void sendData(){ String sensorName = tvSensorName.getText().toString(); String s1 = tvS1.getText().toString(); String s2 = tvS2.getText().toString(); String s3 = tvS3.getText().toString(); String s4 = tvS4.getText().toString(); String allData = sensorName + ";" + s1 + ";" + s2 + ";" + s3 + ";" + s4 + ";"; File ficheiro_dir = getApplicationContext().getDir("DirFile", MODE_PRIVATE); File ficheiro = new File(ficheiro_dir, FILE_NAME); FileOutputStream fos = null; try { fos = new FileOutputStream(ficheiro,true); fos.write(allData.getBytes(StandardCharsets.UTF_8)); // 新增:主动flush缓冲区,确保数据写入磁盘 fos.flush(); Toast.makeText(this, "Saved to " + ficheiro.getPath(), Toast.LENGTH_LONG).show(); if(ficheiro.exists()) Toast.makeText(this, "EXIST", Toast.LENGTH_LONG).show(); else Toast.makeText(this, "NOT EXIST", Toast.LENGTH_LONG).show(); Uri uri = FileProvider.getUriForFile( SensorSelectedActivity.this, BuildConfig.APPLICATION_ID + ".provider", ficheiro); String type = "text/plain"; Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND); sharingIntent.setType(type); // 新增:授予临时读取权限 sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // 移除硬编码的蓝牙类名,使用系统选择器 sharingIntent.putExtra(Intent.EXTRA_STREAM, uri); // 弹出分享选择器 startActivity(Intent.createChooser(sharingIntent, "发送文件到")); } catch (Exception e) { e.printStackTrace(); } finally { if (fos != null) { try { fos.close(); } catch (Exception e) { e.printStackTrace(); } } } }
内容的提问来源于stack exchange,提问作者Diogo Simao
相关产品推荐
相关产品推荐

