3

オーディオ ファイルのタグの読み取りと書き込みに JAudioTagger ライブラリを使用しています。タグを読み取ることはできますが、書き込むことはできません。

次のようにオーディオファイルパスを取得しています:

 private String getSongPath(long songId) {
        String path = null;
        ContentResolver contentResolver = getContentResolver();
        Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
        String[] projection = {MediaStore.Audio.Media.DATA};
        String selection = MediaStore.Audio.Media._ID + " == ?";
        String[] selectionArgs = {String.valueOf(songId)};

        Cursor cursor = contentResolver.query(uri, projection, selection, selectionArgs, null);

        if (cursor != null) {
            int pathCol = cursor.getColumnIndexOrThrow(projection[0]);
            cursor.moveToFirst();
            path = cursor.getString(pathCol);
            cursor.close();
        }

        return path;
    }

次に、 JAudioTagger を使用してタグを記述します。

File songFile = new File(path); // path looks like /storage/3932-3434/Music/xyz.mp3
AudioFile audiofile = = AudioFileIO.read(songFile);
Tag tag = = audiofile.getTag();
tag.setField(FieldKey.TITLE, title);
// some more setField calls for different feilds
audiofile.commit();

commit() メソッドは次の Exception を与えています:

org.jaudiotagger.audio.exceptions.CannotWriteException: java.io.IOException: com.techapps.musicplayerplus の org.jaudiotagger.audio.mp3.MP3File.commit(MP3File.java:799) でファイル xyz.mp3 を変更できません。 MainActivity$17.onClick(MainActivity.java:2125) で android.support.v7.app.AlertController$ButtonHandler.handleMessage(AlertController.java:157) で android.os.Handler.dispatchMessage(Handler.java:102) で android. os.Looper.loop(Looper.java:148) android.app.ActivityThread.main(ActivityThread.java:5417) 06-18 10:59:48.134 8802-8802/com.techapps.musicplayerplus W/System.err:
java.lang.reflect.Method.invoke(Native Method) で com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) で com.android.internal.os.ZygoteInit.main(ZygoteInit. java:616) 原因: java.io.IOException: Cannot make changes to file Saibo.mp3 at org.jaudiotagger.audio.mp3.MP3File.precheck(MP3File.java:824) at org.jaudiotagger.audio.mp3.MP3File .save(MP3File.java:850) at org.jaudiotagger.audio.mp3.MP3File.save(MP3File.java:783) at org.jaudiotagger.audio.mp3.MP3File.commit(MP3File.java:795)

アプリがSDK 22をターゲットにしている間に、このコードをAndroid 6で実行しています。マニフェストで次の許可についても言及しました。

android.permission.WRITE_EXTERNAL_STORAGE

それでもSDカードに書き込めません。私を助けてください。前もって感謝します。

4

5 に答える 5

1

API 19 (Kitkat) 以降の SD カードにアクセスするには、Storage Access Framework (SAF) を使用する必要があります。

  1. まず、アクセスしたいフォルダの URI を提供するようにユーザーに依頼する必要があります。SD カード全体にアクセスする場合、ユーザーは SD カードのルート フォルダーの URI を提供する必要があります。たとえば、ユーザーが [編集] ボタンを押すと、最初にヒント ダイアログ ボックスを表示し、アクセスしたい SD カード内の必要なディレクトリを選択するようユーザーに求めます。ヒント ダイアログ ボックスに次の画像を表示して、ユーザーに SD カードのルート ディレクトリを選択するように求めることができます。ヒント ダイアログ ボックスでこの画像を使用して、ユーザーに SD カードのルート ディレクトリを選択するように求めることができます。

  2. ユーザーがヒント ダイアログ ボックスを閉じたら、 Storage Access Framework をトリガーする必要があります。

    private void triggerStorageAccessFramework() {
     Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
     startActivityForResult(intent, REQUEST_CODE_STORAGE_ACCESS);
     }
    
    public final void onActivityResult(final int requestCode, final int resultCode, final Intent resultData) {
     if (resultCode == Activity.RESULT_OK) {
            if (requestCode == REQUEST_CODE_STORAGE_ACCESS) {
                    Uri treeUri = null;
                    // Get Uri from Storage Access Framework.
                    treeUri = resultData.getData();
                    pickedDir= DocumentFile.fromTreeUri(this, treeUri);
    
                    if (!isSDCardRootDirectoryUri(treeUri)) {
                        Toast.makeText(this, "Wrong directory selected. Please select SD Card root directory.", Toast.LENGTH_LONG).show();
                        createSDCardHintDialog().show();
                        return;
                    }        
    
                    // Persist URI in shared preference so that you can use it later.                   
                    SharedPreferences sharedPreferences = getSharedPreferences(App.PREFERENCE_FILENAME, Context.MODE_PRIVATE);
                    SharedPreferences.Editor editor = sharedPreferences.edit();
                    editor.putString(App.SDCARD_URI_KEY, treeUri.toString());
                    editor.apply();  
    
                    // Persist access permissions, so you dont have to ask again
                    final int takeFlags = resultData.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                    getContentResolver().takePersistableUriPermission(treeUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    
                }
       } 
    
    private boolean isSDCardRootDirectoryUri(Uri treeUri) {
        String uriString = treeUri.toString();
        return uriString.endsWith("%3A");
    }
    

ユーザーが選択したディレクトリの Uri を取得したら、SAF を使用して書き込み操作を実行できます: (creadit: this answer )

public void writeFile(DocumentFile pickedDir) {
    try {
        DocumentFile file = pickedDir.createFile("image/jpeg", "try2.jpg");
        OutputStream out = getContentResolver().openOutputStream(file.getUri());
        try {

            // write the image content

        } finally {
            out.close();
        }

    } catch (IOException e) {
        throw new RuntimeException("Something went wrong : " + e.getMessage(), e);
    }
}
于 2017-01-04T10:04:09.847 に答える
0

Android-M または API 23 では、Android デバイスのセキュリティ上の欠陥を減らすためにランタイム アクセス許可が導入されました。

Android 6.0 のアクセス許可を処理するために Google Play サービスを使用してアプリを更新するには、ランタイムが必要とする可能性のあるアクセス許可を設定する際のユーザーの期待を管理することをお勧めします。次のリンクは、潜在的な問題を回避するのに役立ちます。

https://developer.android.com/training/permissions/requesting.html

于 2016-06-18T06:44:08.657 に答える
0

存在しないファイルを指している可能性があります。

ログを使用してパス ファイルを確認します。

Log.d("Activity", "path = " + path);
于 2016-06-18T06:07:00.273 に答える