Как воспроизвести аудио из массива mp3 [Android] - PullRequest
2 голосов
/ 06 апреля 2019

Работая над тестовым проектом, моя текущая цель - использовать int, чтобы указать, какой файл mp3 будет воспроизводиться при инициализации приложения, не зная заранее названия звуковых дорожек (проблема масштабируемости, поскольку я хочу иметь возможность добавлять новые mp3 файлы в пул рандомизации, не касаясь кода в будущем). Однако при запуске следующего кода произошла ошибка со следующим описанием:

ошибка: не найден подходящий метод для метода create (MainActivity, String) MediaPlayer.create (Context, Uri) не применяется (несоответствие аргумента; строка не может быть преобразована в Uri) метод MediaPlayer.create (Context, int) не является применимо (несоответствие аргумента; строка не может быть преобразована в int)

import android.content.res.AssetManager;
import android.content.res.Resources;
import android.media.MediaPlayer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.RecyclerView;
import android.widget.ArrayAdapter;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    RecyclerView bensonRecycler;
    ArrayList<String> arrayList;

    ArrayAdapter bensonAdapter;
    MediaPlayer bensonPlayer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        AssetManager assetManager = getAssets();
        String[] audios = assetManager.list("sound");

        int i = 1;

        final MediaPlayer mp = MediaPlayer.create(this, audios[i]);
        mp.start();

    }
}

Мои активы mp3-файлов имеют следующую структуру:

enter image description here

Итак, мой вопрос: что мне делать, чтобы использовал int i, чтобы указать, какую звуковую дорожку mp3 воспроизводить (не зная заранее названия звуковой дорожки mp3) среди массива mp3-ресурсов? (Я должен использовать переменную, чтобы указать саундтрек для воспроизведения в этом проекте тестирования)

1 Ответ

2 голосов
/ 10 апреля 2019

Папка «assets» - это вообще не папка, а пакетный поток байтов. Вот почему существует AssetManager .

AssetManager

Предоставляет доступ к файлам исходного кода приложения; см. Ресурсы, чтобы узнать, как большинство приложений захотят получить данные о своих ресурсах. Этот класс представляет API-интерфейс более низкого уровня, который позволяет открывать и читать необработанные файлы, связанные с приложением, в виде простого потока байтов.

AssetManager позволяет достаточно легко создать массив строк из файлов, и мы можем рассматривать эти файлы как принадлежащие к небольшой файловой системе. Хитрость заключается в том, как представить эти файлы (на самом деле поток байтов) в MediaPlayer, чтобы звук мог воспроизводиться на основе индекса в активах звука.

Следующий код воспроизводит проиндексированный звук. Комментарии в коде объясняют, как это работает. Для тестирования я только что построил простую раскладку с тремя кнопками, которые воспроизводят звук с индексами 0, 1 и 2.

MainActivity

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    private void playSoundFromAssets(int index) {
        try {
            AssetManager assetManager = getAssets();
            String[] audios = assetManager.list(SOUNDFILE_PATH);
            if (audios == null || index >= audios.length) {
                return;
            }
            String soundFilePath = new File(SOUNDFILE_PATH, audios[index]).getPath();
            AssetFileDescriptor afd = getAssets().openFd(soundFilePath);
            final MediaPlayer mp = new MediaPlayer();

            /*  For API 24+, we can just use the AssetFileDescriptor to play the sound. However,
                for API 23-, we can't use the AssetFileDescriptor directly but can retrieve a
                FileDescriptor from it that points to the beginning of our assets. The offset
                and length from the AssetFileDescriptor serve for the FileDescriptor as well.
             */

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                mp.setDataSource(afd);
            } else {
                FileDescriptor fd = afd.getFileDescriptor();
                Log.d("MainActivity", String.format("<<<< %s %d %d", soundFilePath, afd.getStartOffset(), afd.getLength()));
                mp.setDataSource(fd, afd.getStartOffset(), afd.getLength());

                // One might think that mp.setDataSource(fd) would play the sound file we want, but
                // it actually plays all sound files one after another. It seems that fd is a
                // FileDescriptor that points to the beginning of the assets.
            }
            afd.close();
            mp.prepare();
            mp.start();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public void playSound(View view) {

        switch (view.getId()) {
            case R.id.play0:
                playSoundFromAssets(0);
                break;

            case R.id.play1:
                playSoundFromAssets(1);
                break;

            case R.id.play2:
                playSoundFromAssets(2);
                break;
        }
    }

    private static final String SOUNDFILE_PATH = "sound";
}
...