如何将Android Wearable设备中的数据以文本文件形式后台传输至配对手机?
解答:WearOS 数据文件静默传输到配对手机的实现方案
首先明确回答你的第一个疑问:WearOS 完全支持与配对手机进行这类数据传输,Google 提供的 Data Layer API 就是专门用于跨穿戴设备和手机同步数据(包括文件类数据)的核心方案,完全能满足你的需求。下面结合你的现有代码,一步步实现完整流程:
一、核心思路梳理
- 整合所有需要传输的日志数据(日期时间、UUID、地理位置、所选参数)为结构化内容(文本或 JSON)
- 使用 Data Layer API 的
Asset类封装文件数据(适合传输二进制/文本文件) - 通过
DataClient从穿戴设备后台发送数据 - 在配对手机端监听 Data Layer 数据变化,接收并保存文件
- 用
WorkManager确保传输任务在后台静默执行(即使穿戴设备的 Activity 被销毁)
二、穿戴设备端代码改造
1. 整合日志数据为统一内容
先新增一个方法,把你现有 getDateTime()、getUUID()、getSelections()、getLocation() 获取的数据整合为可保存的文本内容:
private String generateReportContent() { // 1. 日期时间 SimpleDateFormat sdf_date = new SimpleDateFormat("dd/MM/yyyy"); SimpleDateFormat sdf_time = new SimpleDateFormat("HH:mm:ss z"); String currentDate = sdf_date.format(new Date()); String currentTime = sdf_time.format(new Date()); String dateTimeStr = "Date: " + currentDate + "\nTime: " + currentTime + "\n"; // 2. UUID SharedPreferences sh = getSharedPreferences("UUID_File", MODE_APPEND); String theUUID = sh.getString(PREF_UNIQUE_ID, uniqueID); String uuidStr = "UUID: " + theUUID + "\n"; // 3. 所选参数 String selectionsStr = "Tool No.: " + c.getToolNo() + "\nTool Size: " + c.getToolSizeStr() + "\nFrom Mode: " + c.getCurrentModeStr() + "\nGoto Mode: " + c.getModeStr() + "\nMethod: " + c.getMethodStr() + "\nBit Duration: " + c.getBitDuration() + "\nUpper bound: " + c.getUpStageValue() + "\nLower bound: " + c.getDownStageValue() + "\n"; // 4. 地理位置(假设你已经在 getLocation() 中保存了 location 对象) String locationStr = ""; if (location != null) { locationStr = "Latitude: " + location.getLatitude() + "\nLongitude: " + location.getLongitude() + "\n"; } // 整合所有内容 return dateTimeStr + uuidStr + selectionsStr + locationStr; }
2. 用 Data Layer API 发送文件数据
首先在 MainActivity 中初始化 DataClient:
private DataClient dataClient; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化 DataClient dataClient = Wearable.getDataClient(this); // 其他初始化代码... }
然后新增传输文件的方法,将整合后的内容封装为 Asset 发送:
private void sendReportToPhone() { String reportContent = generateReportContent(); try { // 将文本转成字节数组,创建 Asset(适合传输文件类数据) byte[] reportBytes = reportContent.getBytes(StandardCharsets.UTF_8); Asset reportAsset = Asset.createFromBytes(reportBytes); // 创建数据请求,添加时间戳确保 Data Layer 识别数据变化 PutDataMapRequest putDataMapReq = PutDataMapRequest.create("/wear_report"); putDataMapReq.getDataMap().putAsset("report_asset", reportAsset); putDataMapReq.getDataMap().putLong("timestamp", System.currentTimeMillis()); PutDataRequest putDataReq = putDataMapReq.asPutDataRequest(); // 发送数据 dataClient.putDataItem(putDataReq) .addOnSuccessListener(dataItem -> Log.d("WearData", "日志报告已成功发送")) .addOnFailureListener(e -> Log.e("WearData", "发送失败: ", e)); } catch (Exception e) { Log.e("WearData", "生成报告出错: ", e); } }
3. 修改按钮点击事件,触发传输
在你的按钮点击逻辑中,获取完所有数据后调用传输方法:
gps_btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (Build.VERSION.SDK_INT >= 26) { getLocation(); getDateTime(); getUUID(); getSelections(); // 调用传输方法 sendReportToPhone(); } else { Toast.makeText(get_location.this,"Build SDK 版本过低",Toast.LENGTH_SHORT).show(); } } });
4. 后台静默传输优化(可选)
如果需要在穿戴设备 Activity 销毁后仍能完成传输,建议用 WorkManager 调度任务:
- 先创建一个 Worker 类:
public class ReportSendWorker extends Worker { private DataClient dataClient; public ReportSendWorker(@NonNull Context context, @NonNull WorkerParameters params) { super(context, params); dataClient = Wearable.getDataClient(context); } @NonNull @Override public Result doWork() { // 从 SharedPreferences 读取预存的报告内容 SharedPreferences sh = getApplicationContext().getSharedPreferences("ReportData", MODE_PRIVATE); String reportContent = sh.getString("report_content", ""); try { byte[] reportBytes = reportContent.getBytes(StandardCharsets.UTF_8); Asset reportAsset = Asset.createFromBytes(reportBytes); PutDataMapRequest putDataMapReq = PutDataMapRequest.create("/wear_report"); putDataMapReq.getDataMap().putAsset("report_asset", reportAsset); putDataMapReq.getDataMap().putLong("timestamp", System.currentTimeMillis()); PutDataRequest putDataReq = putDataMapReq.asPutDataRequest(); Tasks.await(dataClient.putDataItem(putDataReq)); return Result.success(); } catch (ExecutionException | InterruptedException e) { Log.e("ReportWorker", "发送失败,将重试", e); return Result.retry(); } catch (Exception e) { Log.e("ReportWorker", "出错", e); return Result.failure(); } } }
- 修改按钮点击事件,先保存数据再调度 Worker:
// 在按钮点击事件中,获取完数据后: String reportContent = generateReportContent(); // 保存到 SharedPreferences SharedPreferences.Editor editor = getSharedPreferences("ReportData", MODE_PRIVATE).edit(); editor.putString("report_content", reportContent); editor.apply(); // 调度后台任务 OneTimeWorkRequest sendRequest = new OneTimeWorkRequest.Builder(ReportSendWorker.class).build(); WorkManager.getInstance(this).enqueue(sendRequest);
三、配对手机端接收并保存文件
1. 创建数据监听 Service
手机端需要监听 Data Layer 的数据变化,创建一个 WearableListenerService:
public class WearDataListenerService extends WearableListenerService { private static final String TAG = "WearDataListener"; @Override public void onDataChanged(DataEventBuffer dataEvents) { super.onDataChanged(dataEvents); for (DataEvent event : dataEvents) { if (event.getType() == DataEvent.TYPE_CHANGED) { DataItem item = event.getDataItem(); // 匹配穿戴设备发送的路径 if (item.getUri().getPath().equals("/wear_report")) { DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap(); Asset reportAsset = dataMap.getAsset("report_asset"); if (reportAsset != null) { // 读取 Asset 内容 Task<InputStream> inputStreamTask = Wearable.getDataClient(this).getFdForAsset(reportAsset); inputStreamTask.addOnSuccessListener(inputStream -> { try { String reportContent = new String(IOUtils.toByteArray(inputStream), StandardCharsets.UTF_8); // 保存到手机文件系统 saveReportToFile(reportContent); Log.d(TAG, "报告已接收并保存"); } catch (IOException e) { Log.e(TAG, "读取 Asset 出错", e); } finally { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } }).addOnFailureListener(e -> Log.e(TAG, "获取 Asset 输入流失败", e)); } } } } } // 保存报告到手机下载目录 private void saveReportToFile(String content) { File downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); File reportFile = new File(downloadsDir, "wear_report_" + System.currentTimeMillis() + ".txt"); try (FileWriter writer = new FileWriter(reportFile)) { writer.write(content); Toast.makeText(this, "报告已保存到: " + reportFile.getAbsolutePath(), Toast.LENGTH_LONG).show(); } catch (IOException e) { Log.e(TAG, "保存文件出错", e); Toast.makeText(this, "保存报告失败", Toast.LENGTH_SHORT).show(); } } }
2. 在 AndroidManifest 中注册 Service
<service android:name=".WearDataListenerService" android:exported="true"> <intent-filter> <action android:name="com.google.android.gms.wearable.DATA_CHANGED" /> <data android:scheme="wear" android:host="*" android:pathPrefix="/wear_report" /> </intent-filter> </service>
四、关键注意事项
- 确保穿戴设备和手机已配对且处于连接状态,Data Layer 会自动处理离线同步(离线时数据会暂存,联网后自动发送)
- 手机端需要申请
WRITE_EXTERNAL_STORAGE权限(Android 10+ 可使用 scoped storage) - Data Layer 只会同步数据变化,所以每次发送时添加时间戳是必要的,确保数据能被识别为新内容
内容的提问来源于stack exchange,提问作者Mohamed El Kayal
相关产品推荐
相关产品推荐

