《Training:Requesting a Shared File》

本文档详细介绍了在安卓应用中实现跨应用文件共享的方法。客户端应用通过发送带有特定动作和MIME类型的Intent请求文件,服务器应用响应并提供文件的内容URI。客户端应用随后可以使用此URI访问文件。

注:本人非专业翻译人员,编写此博客只是为了自学使用,如有疑问,请参考官方博客。



当应用程式想要存取其他应用程式共用的文件时,请求app(客户端)通常会向共享文件(服务器)的app发送一个要求。 在大多数情况下,此请求在服务器应用程序中启动一个活动,显示可以共享的文件。 用户选择一个文件,之后服务器应用程序将文件的内容URI返回给客户端应用程序。


本课程向您展示客户端应用程序如何从服务器应用程序请求文件,从服务器应用程序接收文件的内容URI,并使用内容URI打开文件。



一、发送文件请求

要从服务器应用程序请求文件,客户端应用程序会调用包含服务器app能处理的例如 ACTION_PICK的动作以及一个MIME类型的intent的startActivityForResult 方法。


例如,以下代码段演示了如何将Intent发送到服务器应用程序,以便启动共享文件中描述的活动:

public class MainActivity extends Activity {
    private Intent mRequestFileIntent;
    private ParcelFileDescriptor mInputPFD;
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRequestFileIntent = new Intent(Intent.ACTION_PICK);
        mRequestFileIntent.setType("image/jpg");
        ...
    }
    ...
    protected void requestFile() {
        /**
         * When the user requests a file, send an Intent to the
         * server app.
         * files.
         */
            startActivityForResult(mRequestFileIntent, 0);
        ...
    }
    ...
}


二、访问请求的文件

服务器应用程序将文件的内容URI发送到Intent中的客户端应用程序。 该意图在其overActivityResult()的重写方法中传递给客户端应用程序。 一旦客户端应用程序拥有该文件的内容URI,它可以通过获取其FileDescriptor来访问该文件。


文件安全性保留在此过程中,因为内容URI是客户端应用程序接收的唯一数据。 由于此URI不包含目录路径,客户端应用程序无法在服务器应用程序中发现和打开任何其他文件。 只有客户端应用程序可以访问该文件,并且只能由服务器应用程序授予的权限。 权限是临时的,所以一旦客户端应用程序的任务堆栈完成,文件就不能在服务器应用程序之外访问。


下一个代码段演示了客户端应用程序如何处理从服务器应用程序发送的Intent,以及客户端应用程序如何使用内容URI获取FileDescriptor:

/*
     * When the Activity of the app that hosts files sets a result and calls
     * finish(), this method is invoked. The returned Intent contains the
     * content URI of a selected file. The result code indicates if the
     * selection worked or not.
     */
    @Override
    public void onActivityResult(int requestCode, int resultCode,
            Intent returnIntent) {
        // If the selection didn't work
        if (resultCode != RESULT_OK) {
            // Exit without doing anything else
            return;
        } else {
            // Get the file's content URI from the incoming Intent
            Uri returnUri = returnIntent.getData();
            /*
             * Try to open the file for "read" access using the
             * returned URI. If the file isn't found, write to the
             * error log and return.
             */
            try {
                /*
                 * Get the content resolver instance for this context, and use it
                 * to get a ParcelFileDescriptor for the file.
                 */
                mInputPFD = getContentResolver().openFileDescriptor(returnUri, "r");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                Log.e("MainActivity", "File not found.");
                return;
            }
            // Get a regular file descriptor for the file
            FileDescriptor fd = mInputPFD.getFileDescriptor();
            ...
        }
    }

方法openFileDescriptor()返回该文件的ParcelFileDescriptor。 使用该对象,客户端应用程序获取一个FileDescriptor对象,然后可以使用它来读取该文件。
<think>嗯,用户这次的问题是关于日志中特定信息的解读和错误修复,看起来是个嵌入式开发或无人机相关的技术问题。用户提到了三个关键点:任务接收信息、请求返航位置信息,以及最重要的libusb控制传输报错。这个错误码11(资源暂时不可用)在Linux系统中对应EAGAIN,属于典型的非阻塞I/O操作冲突。 从用户能精确给出源码文件名和行号(messenger-libusb.cpp:42)来看,ta应该是个开发者,可能正在调试无人机或机器人设备的通信模块。用户没有提供更多环境细节,但libusb-win32的引用提示可能是Windows环境,而错误号却是Linux风格的——这种矛盾需要特别注意,可能是跨平台开发时的兼容性问题。 上次对话历史里用户询问过快速排序,和当前问题完全无关,可以忽略。重点在于分析这个USB通信错误的成因。控制传输报错通常有四大诱因:设备未响应(超时)、资源竞争(多线程同时访问)、权限不足(Linux下的udev规则问题)、或者固件端未正确处理请求。错误号11明确指向资源竞争,但需要排除其他可能性。 用户提到的'mission received'和'requesting home position'信息是正常业务流程,反而佐证了业务逻辑在运行。关键矛盾点在于:当业务逻辑尝试通过USB与设备通信时,底层驱动返回了资源被占用的错误。这里有两个排查方向:一是检查是否有其他进程占用了USB设备(比如调试工具未关闭),二是检查代码中是否在未完成前次操作时就发起了新请求。 解决方案需要分层处理:先验证设备连接状态(lsusb命令),再检查进程占用(lsof命令),最后审查代码中的异步调用逻辑。特别要注意libusb-win32的异步API使用规范——它的回调机制要求开发者严格管理请求生命周期,常见的错误就是未等待前次传输完成就发起新请求。 用户可能还需要知道如何验证具体堵塞点。建议在代码里添加传输时间戳日志,同时用usbmon工具抓包分析。如果用户环境是Windows,可以用Wireshark的USBPcap插件替代。不过这些高级诊断步骤暂时不必主动提供,等用户反馈基础方案效果后再决定是否深入。 </think>根据日志中的信息,以下是问题分析和解决方案: ### 错误原因分析 1. **`mission received` & `requesting home position` 信息** 这是正常业务日志,表示设备已接收任务指令并向飞控/导航系统请求返航位置,通常无需处理[^1]。 2. **`control_transfer returned error 11` 核心问题** ```log messenger-libusb.cpp:42 control_transfer returned error, error: Resource temporarily unavailable, number: 11 ``` - **错误本质**:`EAGAIN`(POSIX错误码11),表示资源暂时不可用 - **直接原因**: - USB设备未及时响应传输请求(超时) - 资源竞争(多线程同时访问USB设备) - 设备繁忙未释放USB接口 - **底层关联**:基于引用[1],`libusb-win32`的异步API在进行控制传输(Control Transfer)时触发了操作系统级资源阻塞[^1]。 --- ### 解决方案 #### 第一步:基础排查 1. **检查物理连接** - 重新插拔USB设备 - 更换USB端口/数据线(排除接口老化问题) - 使用`lsusb`(Linux)或设备管理器(Windows)确认设备识别状态 2. **验证设备状态** ```bash # Linux下查看USB设备错误计数 dmesg | grep usb ``` ```powershell # Windows下检查设备状态 Get-PnpDevice -Class USB | Where Status -eq "Error" ``` #### 第二步:软件层修复 1. **增加重试机制**(修改`messenger-libusb.cpp`代码) ```cpp // 在控制传输调用处加入重试逻辑 int retries = 3; while (retries--) { int ret = libusb_control_transfer(dev_handle, ...); if (ret >= 0) break; // 成功则退出 usleep(10000); // 等待10ms重试 } if (ret < 0) { // 记录最终错误 log_error("Control transfer failed after retries"); } ``` 2. **同步访问控制** ```cpp // 添加互斥锁保护USB访问 std::mutex usb_mutex; void send_control_message() { std::lock_guard<std::mutex> lock(usb_mutex); libusb_control_transfer(...); } ``` 3. **调整传输参数** ```cpp // 增加传输超时时间(单位ms) libusb_control_transfer(dev_handle, bmRequestType, bRequest, wValue, wIndex, data, wLength, 5000); // 将超时从默认值改为5000ms ``` #### 第三步:驱动与系统优化 1. **更新libusb库** ```bash # 升级到支持异步IO优化的版本 git clone https://github.com/libusb/libusb cd libusb && ./autogen.sh && make && sudo make install ``` 2. **调整内核参数**(Linux) ```bash # 增加USB控制器中断阈值 echo 1000 | sudo tee /sys/module/usbcore/parameters/usbfs_memory_mb ``` --- ### 典型应用场景关联 当设备处于**高频率控制指令交互**状态时易触发此错误,例如: - 无人机任务执行中实时位置回传 - 工业设备连续发送控制信号 - 医疗设备持续传输监测数据 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值