BitmapFactory.Options.inBitmap causes tearing when switching ImageView bitmap often

后端 未结 5 942
野的像风
野的像风 2021-02-05 16:31

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 mem

5条回答
  •  南旧
    南旧 (楼主)
    2021-02-05 17:23

    You need to do the following things in order to get rid of this problem.

    1. Add an extra bitmap to prevent situations when ui thread draws a bitmap while another thread is modifying it.
    2. Implement threads synchronization to prevent situations when background thread tries to decode a new bitmap, but the previous one wasn't shown by the ui thread.

    I've modified your code a bit and now it works fine for me.

    package com.example.TearingExample;
    
    import android.app.Activity;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.ImageView;
    
    import java.util.ArrayList;
    
    public class MainActivity extends Activity {
        ArrayList images = new ArrayList();
    
        private Bitmap[] buffers = new Bitmap[2];
        private volatile Bitmap current;
    
        private final Object lock = new Object();
        private volatile boolean ready = true;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            images.add(R.drawable.black);
            images.add(R.drawable.blue);
            images.add(R.drawable.green);
            images.add(R.drawable.grey);
            images.add(R.drawable.orange);
            images.add(R.drawable.pink);
            images.add(R.drawable.red);
            images.add(R.drawable.white);
            images.add(R.drawable.yellow);
    
            final ImageView imageView = (ImageView) findViewById(R.id.image);
            final Button goButton = (Button) findViewById(R.id.button);
    
            goButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Runnable runnable = new Runnable() {
                        @Override
                        public void run() {
                            int position = 0;
                            int index = 0;
    
                            while (true) {
                                try {
                                    synchronized (lock) {
                                        while (!ready) {
                                            lock.wait();
                                        }
                                        ready = false;
                                    }
    
                                    BitmapFactory.Options options = new BitmapFactory.Options();
    
                                    options.inSampleSize = 1;
                                    options.inBitmap = buffers[index];
    
                                    buffers[index] = BitmapFactory.decodeResource(getResources(), images.get(position), options);
                                    current = buffers[index];
    
                                    runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            imageView.setImageBitmap(current);
                                            synchronized (lock) {
                                                ready = true;
                                                lock.notifyAll();
                                            }
                                        }
                                    });
    
                                    position = (position + 1) % images.size();
                                    index = (index + 1) % buffers.length;
    
                                    Thread.sleep(5);
                                } catch (InterruptedException ignore) {
                                }
                            }
                        }
                    };
                    Thread t = new Thread(runnable);
                    t.start();
                }
            });
        }
    }
    

提交回复
热议问题