Androidベストプラクティスの共有ファイル

9409 ワード

原文リンク:Sharing a File
このコースでは、
  • ファイル要求
  • を受信する.
  • 選択ファイルを作成するActivity
  • 応答ファイル選択
  • 選択したファイルに対する許可
  • アプリケーションにこのファイルの共有を要求する
  • アプリケーションがcontent URIsを使用してファイルを共有するように設定すると、他のアプリケーションのこれらのファイルに対する要求に応答することができます.これらの要求に応答する1つの方法は、サービス側アプリケーションから他のアプリケーションに呼び出すためのファイル選択インタフェースを提供することである.これにより、クライアントアプリケーションユーザは、サービス側アプリケーションから選択ファイルを適用し、選択ファイルのcontent URIを受信することができる.
    このコースでは、アプリケーションで要求されたファイルに基づいてファイル選択のActivityを作成する方法を説明します.
    ファイルリクエストの受信
    クライアントアプリケーションからのリクエストを受信し、content URIを返すには、アプリケーションがActivityを選択するファイルを提供する必要があります.クライアントアプリケーション使用含むACTION_PICK動作のIntentコール[startActivity ForResult()](https://developer.android.com/reference/android/app/Activity.html#startActivityForResult(android.content.Intent,int))このActivityを起動すると、ユーザーが選択したファイルに基づいて対応するcontent URIがクライアントアプリケーションに返されます.
    クライアントアプリケーションを使用して要求を開始する方法の詳細については、Requesting a Shared File(中国語リンク:要求ファイル共有)を参照してください.
    ファイル選択Activityの作成
    選択ファイルのActivityを設定するには、manifestファイルにこのActivity名を指定し、intent filterにACTION_を追加します.PICK動作、CATEGORY_DEFAULTポリシーおよびCATEGORY_OPENABLEポリシーは、指定した選択イベントに一致します.同様に、MIMEタイプのフィルタを追加して、他のアプリケーションに提供できるファイルタイプを指定します.次のコードは、新しいActivityとintent filterを指定する方法を示しています.
    
    ...
        
        ...
            
                
                    
                    
                    
                    
                    
                
            
    

    コードで選択ファイルのActivityを定義する
    次に、アプリケーション内部メモリfiles/images/ディレクトリの下で使用可能なファイルを表示するActivityのサブクラスを定義します.このディレクトリの下で、ユーザーは希望するファイルを選択できます.次のコードは、このActivityを定義する方法と、ユーザーの選択に応じて応答する方法を示しています.
    public class MainActivity extends Activity {
        // The path to the root of this app's internal storage
        private File mPrivateRootDir;
        // The path to the "images" subdirectory
        private File mImagesDir;
        // Array of files in the images subdirectory
        File[] mImageFiles;
        // Array of filenames corresponding to mImageFiles
        String[] mImageFilenames;
        // Initialize the Activity
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            ...
           // Set up an Intent to send back to apps that request a file
           mResultIntent =
                new Intent("com.example.myapp.ACTION_RETURN_FILE");
          // Get the files/ subdirectory of internal storage
          mPrivateRootDir = getFilesDir();
          // Get the files/images subdirectory;
           mImagesDir = new File(mPrivateRootDir, "images");
          // Get the files in the images subdirectory
          mImageFiles = mImagesDir.listFiles();
          // Set the Activity's result to null to begin with
          setResult(Activity.RESULT_CANCELED, null);
          /*
           * Display the file names in the ListView mFileListView.
           * Back the ListView with the array mImageFilenames, which
           * you can create by iterating through mImageFiles and
           * calling File.getAbsolutePath() for each File
           */
           ...
        }
        ...
    }
    

    レスポンスファイルの選択
    ユーザーが共有するファイルを選択すると、アプリケーションはどのファイルが選択されたのかを決定し、このファイルにcontent URIを生成する必要があります.ActivityはListViewコントロールに可能なすべてのファイルを表示するため、ユーザーがファイルを選択すると[onItemClick()]が呼び出されます(https://developer.android.com/reference/android/widget/AdapterView.OnItemClickListener.html#onItemClick(android.widget.AdapterView>,android.view.View,int,long))メソッドを使用すると、ユーザーが選択したファイルを得ることができます.
    [onItemClick()](https://developer.android.com/reference/android/widget/AdapterView.OnItemClickListener.html#onItemClick(android.widget.AdapterView>,android.view.View,int,long))では、現在選択されているファイルのFileオブジェクトを取得し、FileProviderで指定した権限とともに[getUriForFile()](https://developer.android.com/reference/android/support/v4/content/FileProvider.html#getUriForFile(android.content.Context, java.lang.String, java.io.File)).最終的に生成されるcontent URIには、この権限、ファイルディレクトリに基づいて生成されるパスセグメント、およびファイルの名前と拡張子が含まれます.FileProviderがパスセグメントに基づいて対応するファイルディレクトリにどのようにマッピングするかは、XML meta-dataの説明に依存します.詳細はSpecify Sharable Directories(中国語リンク:Androidベストプラクティスの設定ファイル共有--共有可能なディレクトリを指定)を参照してください.
    次のコード・セグメントでは、選択したファイルのモニタリング方法とcontent URIの取得方法を示します.
     protected void onCreate(Bundle savedInstanceState) {
        ...
        // Define a listener that responds to clicks on a file in the ListView
        mFileListView.setOnItemClickListener(
                new AdapterView.OnItemClickListener() {
            @Override
            /*
             * When a filename in the ListView is clicked, get its
             * content URI and send it to the requesting app
             */
            public void onItemClick(AdapterView> adapterView,
                    View view,
                    int position,
                    long rowId) {
                /*
                 * Get a File for the selected file name.
                 * Assume that the file names are in the
                 * mImageFilename array.
                 */
                File requestFile = new File(mImageFilename[position]);
                /*
                 * Most file-related method calls need to be in
                 * try-catch blocks.
                 */
                // Use the FileProvider to get a content URI
                try {
                    fileUri = FileProvider.getUriForFile(
                            MainActivity.this,
                            "com.example.myapp.fileprovider",
                            requestFile);
                } catch (IllegalArgumentException e) {
                    Log.e("File Selector",
                          "The selected file can't be shared: " +
                          clickedFilename);
                }
                ...
            }
        });
        ...
    }
    
    provider meta-dataファイルの下の要素に含まれるファイルパスに対応するcontent URIsを生成するしかないことに注意してください.Specify Sharable Directories(中国語リンク:Androidベストプラクティスの設定ファイル共有--共有可能なディレクトリを指定する)の章で述べたように.[getUriForFile()]を呼び出すと(https://developer.android.com/reference/android/support/v4/content/FileProvider.html#getUriForFile(android.content.context,java.lang.String,java.io.File))未定義のファイルパスを入力すると、IllegalArgumentException例外が受信されます.
    ファイルの承認
    他のアプリケーションに共有したいcontent URIがあります.クライアントアプリケーションがこのファイルにアクセスできるようにする必要があります.このファイルへのアクセスを許可するために、Intentファイルにこのファイルのcontent URIを追加し、アクセス権フラグを設定します.許可された権限は一時的で、受信者のアプリケーションタスクスタックが終了すると、この権限は自動的に期限切れになります.
    次のコードでは、このファイルに対する読み取り権限の設定方法を示します.
    protected void onCreate(Bundle savedInstanceState) {
        ...
        // Define a listener that responds to clicks in the ListView
        mFileListView.setOnItemClickListener(
                new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView> adapterView,
                    View view,
                    int position,
                    long rowId) {
                ...
                if (fileUri != null) {
                    // Grant temporary read permission to the content URI
                    mResultIntent.addFlags(
                        Intent.FLAG_GRANT_READ_URI_PERMISSION);
                }
                ...
             }
             ...
        });
    ...
    }
    

    注意:一時的なアクセス権を使用する場合、setFlags()を呼び出すことは、ファイルに安全にアクセスする唯一の方法です.[Context.grantUriPermission()](https://developer.android.com/reference/android/content/Context.html#grantUriPermission(java.lang.String,android.net.Uri,int))メソッドは、[Context.revokeUriPermission()を呼び出すまでアクセスを許可するため、ファイルのcontent URIを取得します(https://developer.android.com/reference/android/content/Context.html#revokeUriPermission(android.net.Uri,int))メソッドがこの権限を削除するまで.
    リクエストアプリケーションを使用してこのファイルを共有
    このファイルを要求されたアプリケーションに共有するために、setResult()にcontent URIと権限を含むIntentを転送します.このActivityを定義して終了すると、content URIを含むIntentがクライアントアプリケーションに送信されます.次のコードでは、これらの操作を完了する方法を示します.
    protected void onCreate(Bundle savedInstanceState) {
        ...
        // Define a listener that responds to clicks on a file in the ListView
        mFileListView.setOnItemClickListener(
                new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView> adapterView,
                    View view,
                    int position,
                    long rowId) {
                ...
                if (fileUri != null) {
                    ...
                    // Put the Uri and MIME type in the result Intent
                    mResultIntent.setDataAndType(
                            fileUri,
                            getContentResolver().getType(fileUri));
                    // Set the result
                    MainActivity.this.setResult(Activity.RESULT_OK,
                            mResultIntent);
                    } else {
                        mResultIntent.setDataAndType(null, "");
                        MainActivity.this.setResult(RESULT_CANCELED,
                                mResultIntent);
                    }
                }
        });
    

    ユーザがファイルを選択すると、ユーザに直ちにクライアントアプリケーションに戻る方法が提供される.1つの方法は、チェックマークまたは完了ボタンを提供することです.ボタンにandroid:onClickプロパティを使用してメソッドをバインドし、このメソッドでfinish()を呼び出します.例:
    public void onDoneClick(View v) {
        // Associate a method with the Done button
        finish();
    }