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

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

发送文件请求

要从服务器应用程序请求文件,客户端应用程序使用包含操作(如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);
        ...
    }
    ...
}

访问请求的文件

服务器应用程序在Intent中将文件的内容URI发送回客户端应用程序。 这个Intent传递给客户端应用程序的覆盖onActivityResult()。 一旦客户端应用程序具有文件的内容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对象,然后可以使用它来读取文件。