ImageView.setImageBitmap не меняет представление при вызове с использованием метода Handler.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. Но когда я запускаю слайд-шоу с предоставленным кодом, оно меняется только тогда, когда я нажимаю кнопку «Пуск» и «Стоп». Код внутри runnable выполняется, поэтому, если у меня будет 10 изображений, запустите слайд-шоу, подождите около 5 секунд и нажмите «стоп», ImageView отобразит 6-е изображение. Также, если я заменю строку на рабочем месте

handler.postDelayed(this, 1000);

с

handler.post(this);

он работает просто отлично, мой ImageView обновляется, но процесс постоянный, и я хочу установить некоторую задержку, поэтому я использую «postDelayed». Я также пытался объявить Handler следующим образом:

private Handler handler = new Handler(Looper.getMainLooper());

и получил тот же результат. Кроме того, когда я добавляю контекст Toast with Pictures.this в runnable, он появляется, поэтому я также пробовал объявить Runnable следующим образом:

private Runnable runnable = new Runnable() {
    public void run() {
        Pictures.this.showNewPicture(true);
        Pictures.this.handler.postDelayed(this, 1000);
    }
};

но это приводит к тому же результату. Что мне здесь не хватает?


person oort    schedule 09.03.2016    source источник
comment
Нет, все работает нормально, лог не показывает ошибок, просто ImageView не обновляется, когда я использую postDelayed.   -  person oort    schedule 09.03.2016


Ответы (2)


Вы удаляете обратные вызовы обработчика в onClick слайд-шоустарта,

handler.removeCallbacks(runnable);

поэтому сообщение не будет получено. Удалите эту строку, и она должна работать.

person barq    schedule 09.03.2016
comment
Пробовал, изображение не обновляется. Кроме того, линии, которую вы упоминаете, сначала не было, наткнулся на такую ​​​​конструкцию, когда искал лекарство... - person oort; 09.03.2016

До сих пор не понял, в чем причина проблемы, но нашел обходной путь, я изменил свой Runnable следующим образом (добавлено picture.invalidate()):

private Runnable runnable = new Runnable() {
    public void run() {
        showNewPicture(true);
        picture.invalidate();
        handler.postDelayed(this, 5000);
    }
};

Теперь изображение в ImageView корректно обновляется при каждом выполнении Runnable, даже если я использую postDelayed.

person oort    schedule 09.03.2016