Bitmap的null对象引用,它是对象的最终属性

时间:2016-03-23 22:52:08

标签: java android bitmap

我正在"尝试调用虚拟方法' int android.graphics.Bitmap.getWidth()'在空对象引用" (下面的完整堆栈跟踪)。我觉得令人困惑的是,引用的行是类的 final 属性 - 当类的实例存在引用它时,它应该已经定义:

摘录

public class WindView extends View {
...
    private final Bitmap pDirectionArrow = BitmapFactory.decodeResource(getResources(), R.drawable.wind_arrow);
...
    public void setWindOriginDegrees(float mWindOriginDegrees) {
        this.mWindOriginDegrees = mWindOriginDegrees;
        _rotateArrow();
        invalidate();
    }
...
    private Matrix _rotateArrow() {
        pMatrix.setRotate((180+mWindOriginDegrees)%360, pDirectionArrow.getWidth() / 2, pDirectionArrow.getHeight() / 2);
        return pMatrix;
    }

呼叫

public class DetailFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
...
    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
...
            WindView windGraphic = new WindView(getActivity());
            windGraphic.setWindSpeed((int) windSpeedStr);
            windGraphic.setWindOriginDegrees(windDirStr);
            windGraphic.setForegroundColor(getResources().getColor(R.color.sunshine_light_blue));
            windGraphic.setBackgroundColor(getResources().getColor(R.color.sunshine_dark_blue));
            parent.addView(windGraphic, parent.indexOfChild(mWindView) + 1);

全班

package com.example.android.sunshine.app;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.View;

/**
 * Created by RobertoTomás on 0023, 23/3/2016.
 */
public class WindView extends View {
    private static final float GESTURE_THRESHOLD_DIP = 16.0f;

    private final Bitmap pDirectionArrow = BitmapFactory.decodeResource(getResources(), R.drawable.wind_arrow);
    private final Bitmap pCompassRing = BitmapFactory.decodeResource(getResources(), R.drawable.wind_compass_ring);
    private final Paint pSpeedText = new Paint(Paint.ANTI_ALIAS_FLAG);

    private final Matrix pMatrix = new Matrix();

    private Float pDensity;
    private Rect pSpeedTextBoundingRectangle;

    private int mForegroundColor;

    private int mBackgroundColor;
    private int mWindSpeed;
    private float mWindOriginDegrees;

    public float getWindOriginDegrees() {
        return mWindOriginDegrees;
    }

    public void setWindOriginDegrees(float mWindOriginDegrees) {
        this.mWindOriginDegrees = mWindOriginDegrees;
        _rotateArrow();
        invalidate();
    }

    public int getForegroundColor() {
        return mForegroundColor;
    }

    public void setForegroundColor(int foregroundColor) {
        this.mForegroundColor = foregroundColor;
        _changeForegroundColor();
        invalidate();
    }

    private void _changeForegroundColor(){
        int [] allpixels = new int [pDirectionArrow.getHeight()* pDirectionArrow.getWidth()];

        pDirectionArrow.getPixels(allpixels, 0, pDirectionArrow.getWidth(), 0, 0, pDirectionArrow.getWidth(), pDirectionArrow.getHeight());

        for(int i = 0; i < allpixels.length; i++)
        {
            if(allpixels[i] == Color.BLACK)
            {
                allpixels[i] = mForegroundColor;
            }
        }

        pDirectionArrow.setPixels(allpixels, 0, pDirectionArrow.getWidth(), 0, 0, pDirectionArrow.getWidth(), pDirectionArrow.getHeight());
    }

    public int getBackgroundColor() {
        return mBackgroundColor;
    }

    public void setBackgroundColor(int backgroundColor) {
        this.mBackgroundColor = backgroundColor;
        _changeBackgroundColor();
        invalidate();
    }

    private void _changeBackgroundColor(){
        int [] allpixels = new int [pCompassRing.getHeight()* pCompassRing.getWidth()];

        pCompassRing.getPixels(allpixels, 0, pCompassRing.getWidth(), 0, 0, pCompassRing.getWidth(), pCompassRing.getHeight());

        for(int i = 0; i < allpixels.length; i++)
        {
            if(allpixels[i] == Color.BLACK)
            {
                allpixels[i] = mBackgroundColor;
            }
        }

        pCompassRing.setPixels(allpixels, 0, pCompassRing.getWidth(), 0, 0, pCompassRing.getWidth(), pCompassRing.getHeight());
    }

    public int getWindSpeed() {
        return mWindSpeed;
    }

    public void setWindSpeed(int wind_speed) {
        this.mWindSpeed = wind_speed;
        invalidate();
    }

    public String getWindSpeedText (){
        return Integer.toString(mWindSpeed);
    }

    /** Constructors **/
    public WindView(Context c){
        super(c);
        objectHandler();
    }
    public WindView(Context c, AttributeSet attrs) {
        super(c, attrs);
        objectHandler();
    }
    public WindView(Context c, AttributeSet attrs, int DefaultStyle) {
        super(c, attrs, DefaultStyle);
        objectHandler();
    }

    public void objectHandler(){
        this.mForegroundColor = getResources().getColor(R.color.primary_dark_material_light);
        this.mBackgroundColor = getResources().getColor(R.color.primary_material_dark);
        this.mWindSpeed = 0;
        this.mWindOriginDegrees = 0;

        this.pDensity = getContext().getResources().getDisplayMetrics().density;

        this.pSpeedText.setStyle(Paint.Style.FILL);
        this.pSpeedText.setColor(mForegroundColor);
        this.pSpeedText.setAntiAlias(true);
        int textSize = (int) (GESTURE_THRESHOLD_DIP * pDensity + 0.5f);
        textSize *= pDensity;
        this.pSpeedText.setTextSize(textSize);
        this.pSpeedText.setTextAlign(Paint.Align.LEFT);

        Typeface typeface = Typeface.create(Typeface.SANS_SERIF,Typeface.BOLD_ITALIC);
        this.pSpeedText.setTypeface(typeface);
        this.pSpeedTextBoundingRectangle = new Rect();
    }

    private Matrix _rotateArrow() {
        pMatrix.setRotate((180+mWindOriginDegrees)%360, pDirectionArrow.getWidth() / 2, pDirectionArrow.getHeight() / 2);
        return pMatrix;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.translate(18 * pDensity, 18 * pDensity);

        canvas.drawBitmap(pCompassRing, 0, 0, null);

        String txt = pSpeedText + " km/h";
        pSpeedText.getTextBounds(
                txt, // text
                0, // start
                txt.length(), // end
                pSpeedTextBoundingRectangle // bounds
        );
        canvas.drawText(
                txt, // Text to draw
                canvas.getWidth() / 2, // x
                canvas.getHeight() / 2 + Math.abs(pSpeedTextBoundingRectangle.height()) / 2, // y
                pSpeedText // Paint
        );

        canvas.drawBitmap(pDirectionArrow, _rotateArrow(), null);

    }
}

堆栈跟踪

03-23 18:37:47.870 4152-4152/com.example.android.sunshine.app E/AndroidRuntime: FATAL EXCEPTION: main
                                                                                Process: com.example.android.sunshine.app, PID: 4152
                                                                                java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
                                                                                    at com.example.android.sunshine.app.WindView._rotateArrow(WindView.java:147)
                                                                                    at com.example.android.sunshine.app.WindView.setWindOriginDegrees(WindView.java:42)
                                                                                    at com.example.android.sunshine.app.DetailFragment.onLoadFinished(DetailFragment.java:227)
                                                                                    at com.example.android.sunshine.app.DetailFragment.onLoadFinished(DetailFragment.java:44)
                                                                                    at android.support.v4.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:427)
                                                                                    at android.support.v4.app.LoaderManagerImpl$LoaderInfo.onLoadComplete(LoaderManager.java:395)
                                                                                    at android.support.v4.content.Loader.deliverResult(Loader.java:104)
                                                                                    at android.support.v4.content.CursorLoader.deliverResult(CursorLoader.java:73)
                                                                                    at android.support.v4.content.CursorLoader.deliverResult(CursorLoader.java:35)
                                                                                    at android.support.v4.content.AsyncTaskLoader.dispatchOnLoadComplete(AsyncTaskLoader.java:223)
                                                                                    at android.support.v4.content.AsyncTaskLoader$LoadTask.onPostExecute(AsyncTaskLoader.java:61)
                                                                                    at android.support.v4.content.ModernAsyncTask.finish(ModernAsyncTask.java:461)
                                                                                    at android.support.v4.content.ModernAsyncTask.access$500(ModernAsyncTask.java:47)
                                                                                    at android.support.v4.content.ModernAsyncTask$InternalHandler.handleMessage(ModernAsyncTask.java:474)
                                                                                    at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                                    at android.os.Looper.loop(Looper.java:148)
                                                                                    at android.app.ActivityThread.main(ActivityThread.java:5417)
                                                                                    at java.lang.reflect.Method.invoke(Native Method)
                                                                                    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                                                                                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

2 个答案:

答案 0 :(得分:0)

将您的位图声明更改为:

private Bitmap pDirectionArrow;

然后在视图的构造函数中调用位图上的get资源,如下所示:

pDirectionArrow = BitmapFactory.decodeResource(c.getResources(), R.drawable.wind_arrow);

getResources需要应用程序的上下文。

答案 1 :(得分:0)

所以事实证明问题在于BitmapFactory.decodeResource(getResources(), R.drawable.wind_arrow);假定资源将变为BitmapDrawable而不是VectorDrawable。在我看来,这很容易成为android中的一个bug。 我要报告。symfony documentation

解决方案是在构造函数中分配它,如:

private Bitmap _getBitmap(int drawableId, int color) {
    Drawable vectorDrawable;
    if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.LOLLIPOP){
        vectorDrawable = getResources().getDrawable(drawableId,null);
    }else {
        vectorDrawable = getResources().getDrawable(drawableId);
    }

    // Wrap the drawable so that future tinting calls work
    // on pre-v21 devices. Always use the returned drawable.
    Drawable wrapDrawable = DrawableCompat.wrap(vectorDrawable);
    DrawableCompat.setTint(wrapDrawable.mutute(), getResources().getColor(color));

    int h = vectorDrawable.getIntrinsicHeight();
    int w = vectorDrawable.getIntrinsicWidth();
    //Setting a pixel default if intrinsic height or width is not found , eg a shape drawable
    h=h>0?h:96;
    w=w>0?w:96;

    wrapDrawable.setBounds(0, 0, w, h);
    Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bm);
    wrapDrawable.draw(canvas);
    return bm;
}

现在我实际上仍然遇到颜色问题(mutatewrap都突出显示为红色并且没有使用Alt +输入提供分辨率),但这只是在我检查后用螺栓固定基本解决方案有效。