3

私のアプリでは、ユーザーは getExternalStorage() パス以外の外部 SD カードにファイルを保存できます。Android には外部 SD カードなどの概念がないことは理解していますが、多くのデバイス メーカーがタブレット/電話用に追加の SD カード スロットを提供していることを知っています。また、この特定の SD カードへのパスは、ベンダーに依存する可能性があります。

私のアプリは、getExternalStorage() によって返されるパスとは異なる SD カードへのベンダー パスをユーザーが提供できる設定をユーザーに提供します。

以前は、次のコードを使用してメディア スキャナーを呼び出していましたが、

  sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"
  + Environment.getExternalStorageDirectory())));

しかし、次のコードが機能するかどうか疑問に思っています。

  sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"
  + "/someotherpath/blah/");

それはうまくいくでしょうか?私はそれをテストするための追加のSDカードスロットを備えたそのようなデバイスを持っていません, あなたの意見は私にとって役に立ちます.

4

2 に答える 2

1

Android オープン ソース コード (Android 4.1) を調べました

/packages/providers/MediaProvider/src/com/android/providers/media/MediaScannerReceiver.java というファイルがあります

次のコードがあります。

 @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Uri uri = intent.getData();
        if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
            // scan internal storage
            scan(context, MediaProvider.INTERNAL_VOLUME);
        } else {
            if (uri.getScheme().equals("file")) {
                // handle intents related to external storage
                String path = uri.getPath();
                String externalStoragePath = Environment.getExternalStorageDirectory().getPath();

                Log.d(TAG, "action: " + action + " path: " + path);
                if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
                    // scan whenever any volume is mounted
                    scan(context, MediaProvider.EXTERNAL_VOLUME);
                } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE) &&
                        path != null && path.startsWith(externalStoragePath + "/")) {
                    scanFile(context, path);
                }
            }
        }
    }

ご覧のとおり、ACTION_MEDIA_MOUNT (使用するもの) をチェックし、scan() を呼び出します。ただし、ハードコードされた MediaProvier.EXTERNAL_VOLUME を使用します (渡されたファイル URI の代わりに)。

あなたの質問に答えると、コードを変更しても意味がありません。ファイル スキーマを持つ URI はすべて同じように機能します。

ただし、ベンダーがこのコードを変更する可能性があります。

後もう一つ。Android 4.2 ではマルチユーザーの概念が導入され、各ユーザーは独自の外部ストレージを持っています。これに基づいて、示されているコードが変更されている可能性があります。

更新 1

それは面白い。最初、私は MediaScannerReceiver の一部を調べただけで、1 つの外部ボリュームしかスキャンしないという印象を受けました。ただし、コードを調べて、それが機能するかどうかを尋ねたとあなたが私に言った後。もう少し調査したところ、マウント可能なすべてのボリュームを検索することがわかりました(あなたが言ったように)。

私が理解しているように、次の実行パスを通過します(すべてのインスタンス化などを無視する疑似Javaコードのようなものです)

  • MediaScannerReceiver.onReceive 呼び出し scan(context, MediaProvider.EXTERNAL_VOLUME);
  • MediaScannerReceiver.scan 呼び出し context.startService( new Intent(context, MediaScannerService.class).putExtras(args)); ここで、引数にはキーと値のペアが含まれます "volume"=MediaProvider.EXTERNAL_VOLUME)
  • MediaScannerService.onStartCommand が mServicehandler.sendMessage を呼び出す
  • MediaScannerService.ServiceHandler.handleMessage はメッセージを受信し、scan(StorageManager.getVolumePaths(),MediaProvider.EXTERNAL_VOLUME) と同等の呼び出しを行います。
  • MediaScannerService.scan は MediaScanner.scanDirectories を呼び出します
  • MediaScanner は各ディレクトリを 1 つずつ調べます

「StorageManager.getVolumePaths()」がすべてのマウント可能なボリュームを返す必要があることを考慮すると、現在のコードで問題ないと思います (すべてのボリュームをスキャンします)。

于 2013-01-31T02:56:17.987 に答える
0

Api 8以降では、これを使用できます

 MediaScannerConnection.scanFile(this,
      new String[] { file.toString() }, null,
      new MediaScannerConnection.OnScanCompletedListener() {
  public void onScanCompleted(String path, Uri uri) {
      Log.i("ExternalStorage", "Scanned " + path + ":");
      Log.i("ExternalStorage", "-> uri=" + uri);
  }
 });

これは個々のファイルのみをスキャンし、代替の外部ストレージを含め、ここで任意のパスを指定できます。

于 2013-01-31T17:04:03.353 に答える