1

我有一个自定义文件格式(类似于 zip 文件),它将小文件(小图像、mp3 文件)打包成 1 个物理文件。我的 android 应用程序下载此文件,并从中显示一张图像。用户可以触摸图像,它将开始播放压缩文件中的一个小 mp3“文件”。他还可以向左或向右滑动,应用程序显示上一张或下一张图像。

为了使事情更顺利,我在内存中保存了 3 张“卡片”:当前显示的一张,前一张和下一张。这样,当它被刷卡时,我可以立即显示下一张图片。为此,我将图像和 mp3 预加载到 MediaPlayer 中。问题在于它是多线程的,因为预加载是在后台完成的。我有一个错误:当我开始播放 mp3 时,在播放过程中我滑动,我预加载的图像在中间被剪切。经过大量调试,我找到了原因:当我加载图像时,MediaPlayer 正在移动文件描述符中的文件指针,这导致下一次读取从 mp3 中间读取而不是图像。

这是代码:

InputStream imageStream = myPackedFile.getBaseStream("cat.jpg"); // this returns an InputStream representing "cat.jpg" from my packed file (which is based on a RandomAccessFile)
Drawable image = Drawable.createFromStream(imageStream, imagePath);

FileDescriptor fd = myPackedFile.getFD();
long pos = myPackedFile.getPos("cat.mp3");
long len = myPackedFile.getLength("cat.mp3");
player.setDataSource(fd, pos, len);
player.prepare();
4

2 回答 2

1

这对我有用:我没有创建一个 RandomAccessFile 并持有它,而是创建一个文件,每次我需要将它作为 RandomAccessFile 访问时,我都会创建一个新文件:

public class PackagedFile {
    private File file;
    PackagedFile(String filename) {
        file = new File(filename);
    }
    public RandomAccessFile getRandomAccessFile() {
        RandomAccessFile raf = null;
        try {
            raf = new RandomAccessFile(file, "r");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return raf;
    }
}

上面的代码变成了:

InputStream imageStream = myPackedFile.getBaseStream("cat.jpg"); // this returns an InputStream representing "cat.jpg" from my packed file (which is based on a RandomAccessFile)
Drawable image = Drawable.createFromStream(imageStream, imagePath);

FileDescriptor fd = myPackedFile.getRandomAccessFile().getFD();
long pos = myPackedFile.getPos("cat.mp3");
long len = myPackedFile.getLength("cat.mp3");
player.setDataSource(fd, pos, len);
player.prepare();
于 2013-03-23T19:31:53.600 回答
1

对于 API 级别 13 及以上,可以考虑ParcelFileDescriptor.dup复制文件描述符。更多信息请参考此链接: http ://androidxref.com/4.2.2_r1/xref/frameworks/base/core/java/android/app/ActivityThread.java#864

于 2013-03-24T00:21:25.197 回答