3

I was testing my app on different APIs and it seems to work on API 17 till 23 but I found in API 16, I cannot load my customview. I just want to display a photo in a circle and I have obtained the code for the customview from this thread: How to create a circular ImageView in Android?

My code is pasted here:

public class CircularImageView extends ImageView {

    public CircularImageView(Context context) {
        super(context);
    }

    public CircularImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CircularImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onDraw(Canvas canvas) {

        Drawable drawable = getDrawable();

        int w = getWidth();

        if (drawable == null) {
            return;
        }

        if (getWidth() == 0 || getHeight() == 0) {
            return;
        }
        Bitmap b = ((BitmapDrawable) drawable).getBitmap();

        Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);

        Bitmap roundBitmap = getCroppedBitmap(bitmap, w);
        canvas.drawBitmap(roundBitmap, 0, 0, null);

    }

    public static Bitmap getCroppedBitmap(Bitmap bmp, int radius) {
        Bitmap sbmp;

        if (bmp.getWidth() != radius || bmp.getHeight() != radius) {
            float smallest = Math.min(bmp.getWidth(), bmp.getHeight());
            float factor = smallest / radius;
            sbmp = Bitmap.createScaledBitmap(bmp, (int) (bmp.getWidth() / factor), (int) (bmp.getHeight() / factor), false);
        } else {
            sbmp = bmp;
        }

        Bitmap output = Bitmap.createBitmap(radius, radius,
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(output);

        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, radius, radius);

        paint.setAntiAlias(true);
        paint.setFilterBitmap(true);
        paint.setDither(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(Color.parseColor("#BAB399"));
        canvas.drawCircle(radius / 2 + 0.7f,
                radius / 2 + 0.7f, radius / 2 + 0.1f, paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(sbmp, rect, rect, paint);

        return output;
    }
}

The error occurs in this line:

    if (bmp.getWidth() != radius || bmp.getHeight() != radius) 

This is the logcat:

01-09 15:09:51.185 2119-2119/? E/AndroidRuntime: FATAL EXCEPTION: main java.lang.NullPointerException at com.example.simon.customshapes.CircularImageView.getCroppedBitmap(CircularImageView.java:59) at com.example.simon.customshapes.CircularImageView.onDraw(CircularImageView.java:51) at android.view.View.draw(View.java:13458) at android.view.View.getDisplayList(View.java:12409) at android.view.View.getDisplayList(View.java:12453) at android.view.View.draw(View.java:13182) at android.view.ViewGroup.drawChild(ViewGroup.java:2929) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2799) at android.view.View.draw(View.java:13461) at android.view.View.getDisplayList(View.java:12409) at android.view.View.getDisplayList(View.java:12453) at android.view.View.draw(View.java:13182) at android.view.ViewGroup.drawChild(ViewGroup.java:2929) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2799) at android.view.View.getDisplayList(View.java:12407) at android.view.View.getDisplayList(View.java:12453) at android.view.View.draw(View.java:13182) at android.view.ViewGroup.drawChild(ViewGroup.java:2929) at android.support.v7.widget.RecyclerView.drawChild(RecyclerView.java:3588) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2799) at android.view.View.draw(View.java:13461) at android.support.v7.widget.RecyclerView.draw(RecyclerView.java:3097) at android.view.View.getDisplayList(View.java:12409) at android.view.View.getDisplayList(View.java:12453) at android.view.View.draw(View.java:13182) at android.view.ViewGroup.drawChild(ViewGroup.java:2929) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2806) at android.view.View.draw(View.java:13461) at android.view.View.getDisplayList(View.java:12409) at android.view.View.getDisplayList(View.java:12453) at android.view.View.draw(View.java:13182) at android.view.ViewGroup.drawChild(ViewGroup.java:2929) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2799) at android.view.View.getDisplayList(View.java:12407) at android.view.View.getDisplayList(View.java:12453) at android.view.View.draw(View.java:13182) at android.view.ViewGroup.drawChild(ViewGroup.java:2929) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2799) at android.view.View.draw(View.java:13461) at android.support.v4.view.ViewPager.draw(ViewPager.java:2262) at android.view.View.getDisplayList(View.java:12409) at android.view.View.getDisplayList(View.java:12453) at android.view.View.draw(View.java:13182) at android.view.ViewGroup.drawChild(ViewGroup.java:2929) at android.support.design.widget.CoordinatorLayout.drawChild(CoordinatorLayout.java:1077) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2799) at android.view.View.getDisplayList(View.java:12407) at android.view.View.getDisplayList(View.java:12453) at android.view.View.draw(View.java:13182) at android.view.ViewGroup.drawChild(ViewGroup.java:2929) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2799) at android.view.View.getDisplayList(View.java:12407) at android.view.View.getDisplayList(View.java:12453) at android.view.View.draw(View.java:13182) at android.view.ViewGroup.drawChild(ViewGroup.java:2929) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2799) at android.view.View.getDisplayList(View.java:12407) at android.view.View.getDisplayList(View.java:12453) at android.view.View.draw(View.java:13182) at android.view.ViewGroup.drawChild(ViewGroup.java:2929) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2799) at android.view.View.draw(View.java:13461) at android.widget.FrameLayout.draw(FrameLayout.java:467) at android.view.View.getDisplayList(View.java:12409) at android.view.View.getDisplayList(View.java:12453) at android.view.View.draw(View.java:13182) at android.view.ViewGroup.drawChild(ViewGroup.java:2929) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2799) at android.view.View.getDisplayList(View.java:12407) at android.view.View.getDisplayList(View.java:12453) at android.view.View.draw(View.java:13182) at android.view.ViewGroup.drawChild(ViewGroup.java:2929) at a

Is there a reason why I cannot draw a circular imageview in Android API 16?

Community
  • 1
  • 1
Simon
  • 19,658
  • 27
  • 149
  • 217

3 Answers3

1

Well since your bitmap is null and the drawable isn't the only place the error can be at is within copy(Bitmap, boolean).

If you look at the documentation

If the conversion is not supported, or the allocator fails, then this returns NULL.

Try using a smaller image, since this can be a sign of Low Memory. You should also add some guard against the possible null value returned, e.g. just drawing the normal bitmap in that case.

David Medenjak
  • 33,993
  • 14
  • 106
  • 134
  • The bitmaps I'm loading are really small though. Nothing is greater than 100kb, most are under 50kb. – Simon Jan 09 '16 at 15:32
  • From what I see the error comes from that line. It could still be the bitmap transform being failing, but I would not know why :/ – David Medenjak Jan 09 '16 at 15:35
1

Use this method to convert your drawable to a bitmap:

public static Bitmap drawableToBitmap (Drawable drawable) {
    Bitmap bitmap = null;

    if (drawable instanceof BitmapDrawable) {
        BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
        if(bitmapDrawable.getBitmap() != null) {
            return bitmapDrawable.getBitmap();
        }
    }

    if(drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
        bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); // Single color bitmap will be created of 1x1 pixel
    } else {
        bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    }

    Canvas canvas = new Canvas(bitmap);
    drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    drawable.draw(canvas);
    return bitmap;
}

Then instead of using in the original code, the following line:

Bitmap b = ((BitmapDrawable) drawable).getBitmap();

Use this instead:

Bitmap b = drawableToBitmap(drawable);

Then it will run without error.

Simon
  • 19,658
  • 27
  • 149
  • 217
0

You can use MLRoundedImageView for circular imageview. MLRoundedImageView.java

public class MLRoundedImageView extends ImageView {

public MLRoundedImageView(Context context) {
    super(context);
}

public MLRoundedImageView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public MLRoundedImageView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

@Override
protected void onDraw(Canvas canvas) {

    Drawable drawable = getDrawable();

    if (drawable == null) {
        return;
    }

    if (getWidth() == 0 || getHeight() == 0) {
        return;
    }
    Bitmap b = ((BitmapDrawable) drawable).getBitmap();
    Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);

    int w = getWidth(), h = getHeight();

    Bitmap roundBitmap = getCroppedBitmap(bitmap, w);
    canvas.drawBitmap(roundBitmap, 0, 0, null);

}

public static Bitmap getCroppedBitmap(Bitmap bmp, int radius) {
    Bitmap sbmp;

    if (bmp.getWidth() != radius || bmp.getHeight() != radius) {
        float smallest = Math.min(bmp.getWidth(), bmp.getHeight());
        float factor = smallest / radius;
        sbmp = Bitmap.createScaledBitmap(bmp, (int)(bmp.getWidth() / factor), (int)(bmp.getHeight() / factor), false);
    } else {
        sbmp = bmp;
    }

    Bitmap output = Bitmap.createBitmap(radius, radius,
            Config.ARGB_8888);
    Canvas canvas = new Canvas(output);

    final int color = 0xffa19774;
    final Paint paint = new Paint();
    final Rect rect = new Rect(0, 0, radius, radius);

    paint.setAntiAlias(true);
    paint.setFilterBitmap(true);
    paint.setDither(true);
    canvas.drawARGB(0, 0, 0, 0);
    paint.setColor(Color.parseColor("#BAB399"));
    canvas.drawCircle(radius / 2 + 0.7f,
            radius / 2 + 0.7f, radius / 2 + 0.1f, paint);
    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
    canvas.drawBitmap(sbmp, rect, rect, paint);

    return output;
}
}

Then use like this in layout

   <com.yourproject.MLRoundedImagView
  Layout properties here />

Then in your activity

MLRoundedImagView imageview = (MLRoundedImagView) findViewbyId(R.id.imageview);
Asad Haider
  • 504
  • 1
  • 5
  • 17
  • Sorry - not sure how this answers my question as the code inside your class is the same as the code in my class. I can create the circle - i just cannot create the circle in API 16. – Simon Jan 09 '16 at 17:14