Android: Установка фона изображения для отображения в виде клипа приводит к ошибке с нулевым объектом?

#java #android

Вопрос:

Я создаю приложение, в котором пользователь нажимает на a Button , чтобы ввести выбранное изображение в an ImageView . Изначально изображение правильно обрезано на 50% справа, как показано ниже:

введите описание изображения здесь

Затем пользователь может перетащить ползунок влево, чтобы показать меньше изображения, или вправо, чтобы показать больше изображения. Однако, когда пользователь перемещает ползунок, приложение аварийно завершает работу, возвращая следующую ошибку нулевого объекта в строке кода, в которой я установил ImageView фон для недавно обрезанного изображения на основе хода выполнения ползунка ( singlePreviewBox.setBackground(mClipDrawable); ).

java.lang.Исключение NullPointerException: Попытка вызвать виртуальный метод в android.graphics.drawable.Drawable.getOpacity()’ по нулевой ссылке на объект в android.graphics.drawable.ClipDrawable.getOpacity(ClipDrawable.java:159) в android.view.View.computeOpaqueFlags(View.java:15698) в android.view.View.setBackgroundDrawable(View.java:20502) в android.view.View.setBackground(View.java:20395) в com.пример.изменение ширины изображения.Основная активность$1.onProgressChanged(основная активность.java:49)

Это кажется странным, учитывая, что код, выполняющий начальную обрезку 50% справа, работает, и я использовал тот же код в своем прослушивателе слайдера.

Ниже приведен мой код:

activity_main.xml:

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@ id/transition_root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center_horizontal">
    <Button
        android:id="@ id/photo_input_1"
        android:onClick="chooseFile"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:fontFamily="sans-serif"
        android:text="No Photo"
        android:textAllCaps="false"
        android:textSize="16sp"
        android:background="#f3f3f3"
        android:elevation="4dp"
        android:layout_margin="4dp"
        android:minHeight="40dp"/>

    <SeekBar
        android:id="@ id/image_reveal_slider"
        style="@style/Widget.AppCompat.SeekBar.Discrete"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="10"
        android:progress="5" />

    <ImageView
            android:id="@ id/image_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:maxHeight="370dp"
            android:adjustViewBounds="true"/>
</LinearLayout>
 

MainActivity.java:

 package com.example.changingimageviewwidth;

import androidx.appcompat.app.AppCompatActivity;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ClipDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.Toast;

import java.io.InputStream;

public class MainActivity extends Activity
{
    // Request code used when reading in a file
    private Integer READ_IN_FILE = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        SeekBar imageRevealSlider = (SeekBar) findViewById(R.id.image_reveal_slider);
        // perform seek bar change listener event used for getting the progress value
        imageRevealSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            int progressChangedValue = 0;

            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                progressChangedValue = progress;

                ImageView singlePreviewBox = findViewById(R.id.image_container);
                singlePreviewBox.invalidate();

                ClipDrawable mClipDrawable = new ClipDrawable(singlePreviewBox.getDrawable(), 11,
                        ClipDrawable.HORIZONTAL);
                mClipDrawable.setLevel((progress / 10) * 10000);
                singlePreviewBox.setImageResource(0);
                singlePreviewBox.setBackground(mClipDrawable);
            }

            public void onStartTrackingTouch(SeekBar seekBar) {
                // TODO Auto-generated method stub
            }

            public void onStopTrackingTouch(SeekBar seekBar) {
                Toast.makeText(MainActivity.this, "Seek bar progress is :"   progressChangedValue,
                        Toast.LENGTH_SHORT).show();
            }
        });
    }

    public void chooseFile(View v) {
        // Specify that only photos are allowed as inputs (.jpg, .png).
        Intent photoInputSpecs = new Intent(Intent.ACTION_GET_CONTENT);
        photoInputSpecs.setType("image/*");

        Intent photoInputHandler = Intent.createChooser(photoInputSpecs, "Choose a file");
        startActivityForResult(photoInputHandler, READ_IN_FILE);
    }

    // Processes the results of Activities.
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        try {
            // Processes the photos that the user selected
            if (requestCode == READ_IN_FILE) {
                // Retrieve the photo's location
                Uri photoUri = data.getData();

                InputStream photoInputStream = getContentResolver().openInputStream(photoUri);
                System.out.println("[photoInputStream.available()] = "   photoInputStream.available());
                Bitmap photoBitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(),
                        photoUri);
                // Display the selected image in the preview box
                displayPhoto(photoUri);
            }
        }
        catch (Exception ex) {
            System.out.println("onActivityResult error: "   ex.toString());
        }
    }

    // Displays a specified photo in the split and single screen preview boxes.
    private void displayPhoto(Uri photoUri) {
        ImageView singlePreviewBox = findViewById(R.id.image_container);
        singlePreviewBox.invalidate();
        singlePreviewBox.setImageURI(photoUri);

        ClipDrawable mClipDrawable = new ClipDrawable(singlePreviewBox.getDrawable(), 11,
                                                      ClipDrawable.HORIZONTAL);
        mClipDrawable.setLevel(5000);
        singlePreviewBox.setImageResource(0);
        singlePreviewBox.setBackground(mClipDrawable);
    }
}
 

Ответ №1:

Я заметил несколько проблем с вашим кодом.

Исключение Нулевого Указателя

  • Если ImageView у вас нет изображения, ваше приложение выйдет из строя. Это то, что вам нужно проверить заранее.

Математика

  • mClipDrawable.setLevel((progress / 10) * 10000); Разделение между целыми числами может привести к потере фракции. Так что вам придется либо бросить одного из них, либо обоих; как этот.
 mClipDrawable.setLevel((int)((progress / 10F) * 10000F));
 

Использование методов

  • singlePreviewBox.setImageResource(0); Вы устанавливаете изображение на свой ImageView , вскоре после того, как вы устанавливаете его другим методом. Кстати, вам даже не нужен этот метод. Даже использование этого метода неверно. Это должно было выглядеть так:
 singlePreviewBox.setImageResource(R.drawable.myImage);
 

Комментарии:

1. В строке кода «singlePreviewBox.setImageResource(R. drawable. myImage);», я не могу жестко закодировать значение для рисования (R. drawable. myImage), так как рисоваемым может быть любое изображение, выбранное пользователем. Кроме того, когда я пытаюсь определить, есть ли в ImageView изображение с помощью «singlePreviewBox.getDrawable() != null», оно всегда возвращает значение null.

2. 1) Как я уже сказал, вам не нужна эта строка. 2) Просто используйте логическую переменную. Вставьте один displayPhoto() , проверьте эту переменную onProgressChanged() и не забудьте установить/сбросить ее в false первую очередь, вероятно, в onActivityResult() или onCreate() .