Android findViewById returns null(层次结构查看器显示没有与视图关联的 id)

Android findViewById returns null (hierarchy viewer show's no id associated with view)

我试图在 google 地图上叠加比例尺,但 findViewById() 返回 null 并导致程序失败。我添加了两个 textView 以确定我的布局中的所有视图是否已损坏,但它们的 findViewById ()returns 有效视图以及 google 地图片段的有效视图。我在 Android Device Monitor 中使用了层次结构查看器,并确定没有 id 与 ScaleBar 视图关联。

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_maps);

    mTv1 = (TextView) findViewById(R.id.tv1);
    mTv2 = (TextView) findViewById(R.id.tv2);

    mScaleBar = (ScaleBar) findViewById(R.id.scale);

    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
}

我的布局文件'activity_maps.xml':

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

<fragment
    android:id="@+id/map"
    class="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Text1"
    android:id="@+id/tv1"
    android:layout_alignParentTop="true"
    android:layout_alignParentStart="true" />

<com.dbf.dirteditor.ScaleBar
    android:id="@+id/scale"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Text2"
    android:id="@+id/tv2"
    android:layout_alignParentBottom="true"
    android:layout_alignParentEnd="true" />
</RelativeLayout>

ScaleBar.java

public class ScaleBar extends ImageView {
    float mXOffset = 10;
    float mYOffset = 10;
    float mLineWidth = 3;
    int mTextSize = 25;

    boolean mIsImperial = false;
    boolean mIsNautical = false;

    boolean mIsLatitudeBar = true;
    boolean mIsLongitudeBar = true;

    private GoogleMap mMap = null;

    float mXdpi;
    float mYdpi;

    public ScaleBar(Context context) {
        super(context);
        init_ScaleBar(context);
    }

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

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

    private void init_ScaleBar(Context context) {
    }

    public void setGoogleMap(Context context, GoogleMap map) {
        mMap = map;

        mXdpi = context.getResources().getDisplayMetrics().xdpi;
        mYdpi = context.getResources().getDisplayMetrics().ydpi;
    }

    @Override
    public void onDraw(Canvas canvas) {
        if (mMap != null) {
            canvas.save();
            drawScaleBarPicture(canvas);
            canvas.restore();
        }
    }

    private void drawScaleBarPicture(Canvas canvas) {
        // We want the scale bar to be as long as the closest round-number miles/kilometers
        // to 1-inch at the latitude at the current center of the screen.

        Projection projection = mMap.getProjection();

        if (projection == null) {
            return;
        }

        final Paint barPaint = new Paint();
        barPaint.setColor(Color.BLACK);
        barPaint.setAntiAlias(true);
        barPaint.setStrokeWidth(mLineWidth);

        final Paint textPaint = new Paint();
        textPaint.setColor(Color.BLACK);
        textPaint.setAntiAlias(true);
        textPaint.setTextSize(mTextSize);

        drawXMetric(canvas, textPaint, barPaint);

        drawYMetric(canvas, textPaint, barPaint);
    }

    private void drawXMetric(Canvas canvas, Paint textPaint, Paint barPaint) {
        Projection projection = mMap.getProjection();

        if (projection != null) {
            LatLng p1 = projection.fromScreenLocation(new Point((int) ((getWidth() / 2) - (mXdpi / 2)), getHeight() / 2));
            LatLng p2 = projection.fromScreenLocation(new Point((int) ((getWidth() / 2) + (mXdpi / 2)), getHeight() / 2));

            Location locationP1 = new Location("ScaleBar location p1");
            Location locationP2 = new Location("ScaleBar location p2");

            locationP1.setLatitude(p1.latitude);
            locationP2.setLatitude(p2.latitude);
            locationP1.setLongitude(p1.longitude);
            locationP2.setLongitude(p2.longitude);

            float xMetersPerInch = locationP1.distanceTo(locationP2);

            if (mIsLatitudeBar) {
                String xMsg = scaleBarLengthText(xMetersPerInch);
                Rect xTextRect = new Rect();
                textPaint.getTextBounds(xMsg, 0, xMsg.length(), xTextRect);

                int textSpacing = (int) (xTextRect.height() / 5.0);

                canvas.drawRect(mXOffset, mYOffset, mXOffset + mXdpi, mYOffset + mLineWidth, barPaint);
                canvas.drawRect(mXOffset + mXdpi, mYOffset, mXOffset + mXdpi + mLineWidth, mYOffset +
                        xTextRect.height() + mLineWidth + textSpacing, barPaint);

                if (!mIsLongitudeBar) {
                    canvas.drawRect(mXOffset, mYOffset, mXOffset + mLineWidth, mYOffset +
                            xTextRect.height() + mLineWidth + textSpacing, barPaint);
                }
                canvas.drawText(xMsg, (mXOffset + mXdpi / 2 - xTextRect.width() / 2),
                        (mYOffset + xTextRect.height() + mLineWidth + textSpacing), textPaint);
            }
        }
    }

    private void drawYMetric(Canvas canvas, Paint textPaint, Paint barPaint) {
        Projection projection = mMap.getProjection();

        if (projection != null) {
            Location locationP1 = new Location("ScaleBar location p1");
            Location locationP2 = new Location("ScaleBar location p2");

            LatLng p1 = projection.fromScreenLocation(new Point(getWidth() / 2,
                    (int) ((getHeight() / 2) - (mYdpi / 2))));
            LatLng p2 = projection.fromScreenLocation(new Point(getWidth() / 2,
                    (int) ((getHeight() / 2) + (mYdpi / 2))));

            locationP1.setLatitude(p1.latitude);
            locationP2.setLatitude(p2.latitude);
            locationP1.setLongitude(p1.longitude);
            locationP2.setLongitude(p2.longitude);

            float yMetersPerInch = locationP1.distanceTo(locationP2);

            if (mIsLongitudeBar) {
                String yMsg = scaleBarLengthText(yMetersPerInch);
                Rect yTextRect = new Rect();
                textPaint.getTextBounds(yMsg, 0, yMsg.length(), yTextRect);

                int textSpacing = (int) (yTextRect.height() / 5.0);

                canvas.drawRect(mXOffset, mYOffset, mXOffset + mLineWidth, mYOffset + mYdpi, barPaint);
                canvas.drawRect(mXOffset, mYOffset + mYdpi, mXOffset + yTextRect.height() +
                        mLineWidth + textSpacing, mYOffset + mYdpi + mLineWidth, barPaint);

                if (!mIsLatitudeBar) {
                    canvas.drawRect(mXOffset, mYOffset, mXOffset + yTextRect.height() +
                            mLineWidth + textSpacing, mYOffset + mLineWidth, barPaint);
                }

                float x = mXOffset + yTextRect.height() + mLineWidth + textSpacing;
                float y = mYOffset + mYdpi / 2 + yTextRect.width() / 2;

                canvas.rotate(-90, x, y);
                canvas.drawText(yMsg, x, y + textSpacing, textPaint);
            }
        }
    }

    private String scaleBarLengthText(float meters) {
        if (this.mIsImperial) {
            if (meters >= 1609.344) {
                return (meters / 1609.344) + "mi";
            } else if (meters >= 1609.344/10) {
                return ((meters / 160.9344) / 10.0) + "mi";
            } else {
                return (meters * 3.2808399) + "ft";
            }
        } else if (this.mIsNautical) {
            if (meters >= 1852) {
                return ((meters / 1852)) + "nm";
            } else if (meters >= 1852/10) {
                return (((meters / 185.2)) / 10.0) + "nm";
            } else {
                return ((meters * 3.2808399)) + "ft";
            }
        } else {
            if (meters >= 1000) {
                return ((meters / 1000)) + "km";
            } else if (meters > 100) {
                return ((meters / 100.0) / 10.0) + "km";
            } else {
                return meters + "m";
            }
        }
    }
}

我看了这个太久了...我错过了什么愚蠢的东西?求助!

您只调用了 1 个参数的构造函数(忽略了 xml 属性)。 因此,以这种方式更改您的代码:

public ScaleBar(Context context) {
    this(context,null);
}

public ScaleBar(Context context, AttributeSet attrs) {
    this(context,attrs,0);
}

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