ビューがそのコンテンツを画面に描画する必要があるときにそのメソッドが呼び出されるため、ImageView の onDraw() メソッドを使用する必要があります。
ImageView を拡張する MyImageView という名前の新しいクラスを作成し、このビューが描画を終了したことをリスナーに知らせるコールバックをトリガーする onDraw() メソッドをオーバーライドします。
public class MyImageView extends ImageView {
private OnDrawFinishedListener mDrawFinishedListener;
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mDrawFinishedListener != null) {
mDrawFinishedListener.onOnDrawFinish();
}
}
public void setOnDrawFinishedListener(OnDrawFinishedListener listener) {
mDrawFinishedListener = listener;
}
public interface OnDrawFinishedListener {
public void onOnDrawFinish();
}
}
MainActivity で、3 つのビットマップを定義します。1 つは ImageView が描画に使用するビットマップへの参照、もう 1 つはデコード用、もう 1 つは次のデコードのために再利用されるビットマップへの参照です。vminorovの回答から同期ブロックを再利用しますが、コードコメントに説明を付けて別の場所に配置します
public class MainActivity extends Activity {
private Bitmap mDecodingBitmap;
private Bitmap mShowingBitmap;
private Bitmap mRecycledBitmap;
private final Object lock = new Object();
private volatile boolean ready = true;
ArrayList<Integer> images = new ArrayList<Integer>();
int position = 0;
@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 MyImageView imageView = (MyImageView) findViewById(R.id.image);
imageView.setOnDrawFinishedListener(new OnDrawFinishedListener() {
@Override
public void onOnDrawFinish() {
/*
* The ImageView has finished its drawing, now we can recycle
* the bitmap and use the new one for the next drawing
*/
mRecycledBitmap = mShowingBitmap;
mShowingBitmap = null;
synchronized (lock) {
ready = true;
lock.notifyAll();
}
}
});
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() {
while (true) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
if (mDecodingBitmap != null) {
options.inBitmap = mDecodingBitmap;
}
mDecodingBitmap = BitmapFactory.decodeResource(
getResources(), images.get(position),
options);
/*
* If you want the images display in order and none
* of them is bypassed then you should stay here and
* wait until the ImageView finishes displaying the
* last bitmap, if not, remove synchronized block.
*
* It's better if we put the lock here (after the
* decoding is done) so that the image is ready to
* pass to the ImageView when this thread resume.
*/
synchronized (lock) {
while (!ready) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
ready = false;
}
if (mShowingBitmap == null) {
mShowingBitmap = mDecodingBitmap;
mDecodingBitmap = mRecycledBitmap;
}
runOnUiThread(new Runnable() {
@Override
public void run() {
if (mShowingBitmap != null) {
imageView
.setImageBitmap(mShowingBitmap);
/*
* At this point, nothing has been drawn
* yet, only passing the data to the
* ImageView and trigger the view to
* invalidate
*/
}
}
});
try {
Thread.sleep(5);
} catch (InterruptedException e) {
}
position++;
if (position >= images.size())
position = 0;
}
}
};
Thread t = new Thread(runnable);
t.start();
}
});
}
}