BitmapFactory.Options.inBitmap导致开关经常ImageView的位图时,撕裂位图、Options、BitmapFactory、ImageView

2023-09-04 12:45:48 作者:初二三班

我遇到一个情况下,我必须在一个幻灯片切换图像非常快的显示图像。图像的数量之多,让我想要存储的JPEG数据在内存中,德$ C C $他们时,我想显示它们。为了缓解垃圾收集器,我使用的BitmapFactory.Options.inBitmap重用位图。

I've encountered a situation where I have to display images in a slideshow that switches image very fast. The sheer number of images makes me want to store the JPEG data in memory and decode them when I want to display them. To ease on the Garbage Collector, I'm using BitmapFactory.Options.inBitmap to reuse bitmaps.

不幸的是,这会导致相当严峻的流泪,我已经尝试了不同的解决方案,如同步,信号量,交替2-3之间的位图,但是,似乎没有解决这个问题。

Unfortunately, this causes rather severe tearing, I've tried different solutions such as synchronization, semaphores, alternating between 2-3 bitmaps, however, none seem to fix the problem.

我已经成立了一个例子项目,通过在GitHub上演示了这个问题; https://github.com/Berglund/android-tearing-example

I've set up an example project which demonstrates this issue over at GitHub; https://github.com/Berglund/android-tearing-example

我有一个线程,去codeS位图,并将其设置在UI线程上,和休眠5毫秒:

I've got a thread which decodes the bitmap, sets it on the UI thread, and sleeps for 5 ms:

Runnable runnable = new Runnable() {
@Override
public void run() {
        while(true) {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inSampleSize = 1;

            if(bitmap != null) {
                options.inBitmap = bitmap;
            }

            bitmap = BitmapFactory.decodeResource(getResources(), images.get(position), options);

            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    imageView.setImageBitmap(bitmap);
                }
            });

            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {}

            position++;
            if(position >= images.size())
                position = 0;
        }
    }
};
Thread t = new Thread(runnable);
t.start();

我的想法是,ImageView.setImageBitmap(位图)绘制的下一个垂直同步的位图,但是,我们很可能已经解码的下一个位图时出现这种情况,正因为如此,我们已经开始修改位图的像素。我在想,在正确的方向?

My idea is that ImageView.setImageBitmap(Bitmap) draws the bitmap on the next vsync, however, we're probably already decoding the next bitmap when this happens, and as such, we've started modifying the bitmap pixels. Am I thinking in the right direction?

有没有人有在哪里从这里?

Has anyone got any tips on where to go from here?

推荐答案

作为替代你目前的做法,可以考虑保持JPEG数据,你在做什么,而且还创造了每一个图像的一个单独的位图,以及使用 inPurgeable inInputShareable 标志。这些标志分配后盾内存的位图上的一个单独的堆不直接由Java垃圾收集管理,并允许Android的自身丢弃位图数据时,它没有空间,并重新去code的JPEG文件点播时必需的。 Android有这一切的专用code管理位图数据,那么为什么不使用它呢?

As an alternative to your current approach, you might consider keeping the JPEG data as you are doing, but also creating a separate Bitmap for each of your images, and using the inPurgeable and inInputShareable flags. These flags allocate the backing memory for your bitmaps on a separate heap that is not directly managed by the Java garbage collector, and allow Android itself to discard the bitmap data when it has no room for it and re-decode your JPEGs on demand when required. Android has all this special-purpose code to manage bitmap data, so why not use it?