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.
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.
I've set up an example project which demonstrates this issue over at GitHub; https://github.com/Berglund/android-tearing-example
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();
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?
ImageView
a necessary requirement ? I'd suggestSurfaceView
orTextureView
for high draw rates. – Enface