ImageView.setImageBitmap 在使用 Handler.postDelayed 方法调用时不会改变视图
ImageView.setImageBitmap doesn't change view when called using Handler.postDelayed method
我正在尝试制作简单的幻灯片,这是我正在使用的代码:
public class Pictures extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
private ImageView picture;
private Integer resourceImage;
private Handler handler = new Handler();
private Runnable runnable = new Runnable() {
public void run() {
showNewPicture(true);
handler.postDelayed(this, 1000);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
// initialization here
final Button slideshowStart = (Button) findViewById(R.id.slideshow_start);
// I'm starting slideshow using this:
slideshowStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handler.removeCallbacks(runnable);
handler.post(runnable);
}
});
final Button slideshowStop = (Button) findViewById(R.id.slideshow_stop);
// I'm stopping slideshow using this:
slideshowStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handler.removeCallbacks(runnable);
}
});
}
private void showNewPicture(Boolean next){
// defining resource ID for the new picture, i. e.:
resourceImage = R.drawable.some_picture;
setScaledImage(picture, resourceImage);
picture.setTag(newTag);
}
// all the code below is to scale images to the actual size of the view
private void setScaledImage(ImageView imageView, final int resId) {
final ImageView iv = imageView;
ViewTreeObserver viewTreeObserver = iv.getViewTreeObserver();
viewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
iv.getViewTreeObserver().removeOnPreDrawListener(this);
int imageViewHeight = iv.getMeasuredHeight();
int imageViewWidth = iv.getMeasuredWidth();
iv.setImageBitmap(
decodeSampledBitmapFromResource(getResources(),
resId, imageViewWidth, imageViewHeight));
return true;
}
});
}
private static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds = true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
private static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
if(height > width){
while ((halfHeight / inSampleSize) >= reqHeight) {
inSampleSize *= 2;
}
}else{
while ((halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
}
return inSampleSize;
}
}
当我通过单击某些按钮调用 showNewPicture(true) 时,它工作正常并更新了 ImageView 的源。但是当我使用提供的代码 运行 幻灯片时,它只会在我单击 "start" 和 "stop" 按钮时发生变化。 runnable 中的代码会执行,所以如果我有 10 张图片,开始幻灯片放映,等待大约 5 秒并单击 "stop",ImageView 将显示第 6 张图片。另外,如果我替换 runnable
中的行
handler.postDelayed(this, 1000);
和
handler.post(this);
它工作得很好,我的 ImageView 正在更新,但过程是恒定的,我想设置一些延迟,这就是我使用 "postDelayed" 的原因。
我也试过这样声明处理程序:
private Handler handler = new Handler(Looper.getMainLooper());
得到了同样的结果。
此外,当我将带有 Pictures.this 上下文的 Toast 添加到 runnable 时 - 它会出现,所以我也尝试像这样声明 Runnable:
private Runnable runnable = new Runnable() {
public void run() {
Pictures.this.showNewPicture(true);
Pictures.this.handler.postDelayed(this, 1000);
}
};
但它导致相同的结果。
我在这里错过了什么?
您正在删除 slideShowStart onClick
中的处理程序回调,
handler.removeCallbacks(runnable);
因此无法接收消息。删除该行,它应该可以工作。
仍然没有弄清楚是什么原因导致了问题,但找到了解决方法,我已经像这样更改了我的 Runnable
(添加了 picture.invalidate()
):
private Runnable runnable = new Runnable() {
public void run() {
showNewPicture(true);
picture.invalidate();
handler.postDelayed(this, 5000);
}
};
现在 ImageView
中的图像在每次 Runnable
执行时都会正确更新,即使我使用的是 postDelayed
.
我正在尝试制作简单的幻灯片,这是我正在使用的代码:
public class Pictures extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
private ImageView picture;
private Integer resourceImage;
private Handler handler = new Handler();
private Runnable runnable = new Runnable() {
public void run() {
showNewPicture(true);
handler.postDelayed(this, 1000);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
// initialization here
final Button slideshowStart = (Button) findViewById(R.id.slideshow_start);
// I'm starting slideshow using this:
slideshowStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handler.removeCallbacks(runnable);
handler.post(runnable);
}
});
final Button slideshowStop = (Button) findViewById(R.id.slideshow_stop);
// I'm stopping slideshow using this:
slideshowStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handler.removeCallbacks(runnable);
}
});
}
private void showNewPicture(Boolean next){
// defining resource ID for the new picture, i. e.:
resourceImage = R.drawable.some_picture;
setScaledImage(picture, resourceImage);
picture.setTag(newTag);
}
// all the code below is to scale images to the actual size of the view
private void setScaledImage(ImageView imageView, final int resId) {
final ImageView iv = imageView;
ViewTreeObserver viewTreeObserver = iv.getViewTreeObserver();
viewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
iv.getViewTreeObserver().removeOnPreDrawListener(this);
int imageViewHeight = iv.getMeasuredHeight();
int imageViewWidth = iv.getMeasuredWidth();
iv.setImageBitmap(
decodeSampledBitmapFromResource(getResources(),
resId, imageViewWidth, imageViewHeight));
return true;
}
});
}
private static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds = true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
private static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
if(height > width){
while ((halfHeight / inSampleSize) >= reqHeight) {
inSampleSize *= 2;
}
}else{
while ((halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
}
return inSampleSize;
}
}
当我通过单击某些按钮调用 showNewPicture(true) 时,它工作正常并更新了 ImageView 的源。但是当我使用提供的代码 运行 幻灯片时,它只会在我单击 "start" 和 "stop" 按钮时发生变化。 runnable 中的代码会执行,所以如果我有 10 张图片,开始幻灯片放映,等待大约 5 秒并单击 "stop",ImageView 将显示第 6 张图片。另外,如果我替换 runnable
中的行handler.postDelayed(this, 1000);
和
handler.post(this);
它工作得很好,我的 ImageView 正在更新,但过程是恒定的,我想设置一些延迟,这就是我使用 "postDelayed" 的原因。 我也试过这样声明处理程序:
private Handler handler = new Handler(Looper.getMainLooper());
得到了同样的结果。 此外,当我将带有 Pictures.this 上下文的 Toast 添加到 runnable 时 - 它会出现,所以我也尝试像这样声明 Runnable:
private Runnable runnable = new Runnable() {
public void run() {
Pictures.this.showNewPicture(true);
Pictures.this.handler.postDelayed(this, 1000);
}
};
但它导致相同的结果。 我在这里错过了什么?
您正在删除 slideShowStart onClick
中的处理程序回调,
handler.removeCallbacks(runnable);
因此无法接收消息。删除该行,它应该可以工作。
仍然没有弄清楚是什么原因导致了问题,但找到了解决方法,我已经像这样更改了我的 Runnable
(添加了 picture.invalidate()
):
private Runnable runnable = new Runnable() {
public void run() {
showNewPicture(true);
picture.invalidate();
handler.postDelayed(this, 5000);
}
};
现在 ImageView
中的图像在每次 Runnable
执行时都会正确更新,即使我使用的是 postDelayed
.