我正在图像视图上绘制可调整大小的矩形。
用于绘制自定义可缩放矩形视图的View类:
public class DrawPolygonCanvas extends View implements OnTouchListener {
private final String TAG = "DrawLineCanvas";
private final String defaultROI = "Roi1:0.2,0.2|0.8,0.2|0.8,0.8|0.2,0.8";
private Context context;
private CanvasTouchManager canvasTouchManager = new CanvasTouchManager();
private boolean isInitialized = false;
private Paint circlePaint, linePaint;
private String cameraROI = "";
// Debug helpers to draw lines between the two touch points
private HashMap<String, List<Vector2D>> polygons = new HashMap();
public DrawPolygonCanvas(Context context) {
super(context);
init(context);
}
public DrawPolygonCanvas(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public DrawPolygonCanvas(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
public DrawPolygonCanvas(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
private void init(Context context) {
Log.e(TAG, "called init");
this.context = context;
Log.e(TAG, "calling setOnTouchListener");
setOnTouchListener(this);
}
public void clearROI() {
Log.e(TAG, "called clearROI");
// Get ROI from the shared preferences.
SharedPreferences prefs = UserSharedPref.initializeSharedPreferencesForCameraROI(context);
cameraROI = prefs.getString(UserSharedPref.cameraROI, cameraROI);
Log.e(TAG, "Reloaded ROI = " + cameraROI);
convertString2Polygons();
}
@Override
protected void onDraw(Canvas canvas) {
Log.e(TAG, "called onDraw");
super.onDraw(canvas);
if (!isInitialized) {
// Get ROI from the shared preferences.
SharedPreferences prefs = UserSharedPref.initializeSharedPreferencesForCameraROI(context);
cameraROI = prefs.getString(UserSharedPref.cameraROI, cameraROI);
if (cameraROI.isEmpty()) {
cameraROI = defaultROI;
}
convertString2Polygons();
circlePaint = new Paint();
circlePaint.setColor(0xFFFF0000);
linePaint = new Paint();
linePaint.setColor(0xFF00FF00);
linePaint.setStyle(Paint.Style.STROKE);
linePaint.setStrokeWidth(10);
isInitialized = true;
}
Rect dest = new Rect(0, 0, getWidth(), getHeight());
Paint paint = new Paint();
paint.setFilterBitmap(true);
exampleActivity ex = new exampleActivity();
Bitmap bm = ex.getBitmap();
canvas.drawBitmap(bm, null, dest, paint);
try {
for (Map.Entry<String, List<Vector2D>> entry : polygons.entrySet()) {
List<Vector2D> polygon = entry.getValue();
for (int i = 0; i < polygon.size() - 1; i++) {
canvas.drawLine(polygon.get(i).getX(), polygon.get(i).getY(), polygon.get(i + 1).getX(), polygon.get(i + 1).getY(), linePaint);
}
canvas.drawLine(polygon.get(polygon.size() - 1).getX(), polygon.get(polygon.size() - 1).getY(), polygon.get(0).getX(), polygon.get(0).getY(), linePaint);
for (int i = 0; i < polygon.size(); i++) {
canvas.drawCircle(polygon.get(i).getX(), polygon.get(i).getY(), 40, circlePaint);
}
}
} catch (NullPointerException e) {
e.printStackTrace();
}
}
@Override
public void onDetachedFromWindow() {
Log.e(TAG, "called onDetachedFromWindow");
super.onDetachedFromWindow();
// Convert polygon back to string.
convertPolygons2String();
SharedPreferences.Editor editor = UserSharedPref.initializeSharedPreferencesForCameraROI(context).edit();
editor.putString(UserSharedPref.cameraROI, cameraROI);
editor.apply();
}
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.e(TAG, "called onTouch");
canvasTouchManager.update(event);
Vector2D vct = canvasTouchManager.getPoint();
float minDist = 200000.0f;
float radius = 200;
int minIndex = -1;
String key = "";
for (Map.Entry<String, List<Vector2D>> entry : polygons.entrySet()) {
List<Vector2D> points = entry.getValue();
for (int i = 0; i < points.size(); i++) {
float dist = points.get(i) == null ? 0 : Vector2D.subtract(vct, points.get(i)).getLength();
if (dist >= radius) {
continue;
}
if (dist < minDist) {
minDist = dist;
minIndex = i;
Log.e(TAG, "Matching x = " + points.get(i).getX() + ", y = " + points.get(i).getY());
key = entry.getKey();
}
}
}
if (minIndex != -1 && !key.isEmpty()) {
polygons.get(key).set(minIndex, vct);
} else {
Log.e("OK2", "Touch point is too far, dist = " + minDist);
}
invalidate();
return true;
}
private void convertPolygons2String() {
cameraROI = "";
for (Map.Entry<String, List<Vector2D>> entry : polygons.entrySet()) {
cameraROI += cameraROI.isEmpty() ? entry.getKey() + ":" : ";" + entry.getKey() + ":";
List<Vector2D> points = entry.getValue();
for (int i = 0; i < points.size(); i++) {
float x = points.get(i).getX() / (float) getWidth();
float y = points.get(i).getY() / (float) getHeight();
cameraROI += String.format("%.2f", x);
cameraROI += ",";
cameraROI += String.format("%.2f", y);
if (i < points.size() - 1) {
cameraROI += "|";
}
}
}
Log.e(TAG, "Converted string = " + cameraROI);
}
private void convertString2Polygons() {
Log.e(TAG, "called convertString2Polygons");
String[] ROIs = cameraROI.split(";");
if (cameraROI.isEmpty() || ROIs.length == 0) {
Log.e(TAG, "No polygon is configured.");
polygons.clear();
return;
}
// Parse and add each polygon
for (String roi : ROIs) {
String[] polygonString = roi.split(":");
if (polygonString.length != 2) {
continue;
}
String[] vertices = polygonString[1].split("\\|");
if (vertices.length < 3) {
Log.d(TAG, polygonString[1] + " is not a valid polygon setting, which needs at least 3 vertices, e.g '0,5,0.1|0.3,0.4|0.5,0.6|0.7,0.8'.");
return;
}
List<Vector2D> points = new ArrayList<>();
for (String vertex : vertices) {
Log.d(TAG, "Vertex = " + vertex);
String[] vertexString = vertex.split(",");
if (vertexString.length != 2) {
Log.d(TAG, vertex + " is not a valid vertex setting. An example should look like '0.5,0.5'.");
return;
}
try {
float x = Float.parseFloat(vertexString[0]);
float y = Float.parseFloat(vertexString[1]);
points.add(new Vector2D(x * getWidth(), y * getHeight()));
Log.d(TAG, "Adding [" + x + ", " + y + "]");
} catch (NumberFormatException e) {
e.printStackTrace();
Log.d(TAG, vertex + " is invalid. Vertex's X and Y coordinates should be float numbers.");
return;
}
}
polygons.put(polygonString[0], points);
Log.d(TAG, "Add configured polygon: " + polygonString[0] + " - " + polygonString[1]);
}
}
}
这是我的XML文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".exampleActivity">
<ImageView
android:id="@+id/office"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/office"
android:src="@raw/office" />
<com.lambdahash.sonic.example.draw.senapr.DrawPolygonCanvas
android:id="@+id/DrawPolygonCanvas"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
最后,这就是我将视图附加到xml文件(活动)的方式:
public class exampleActivity extends Activity {
private ImageView img;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_example);
DrawPolygonCanvas canvas = (DrawPolygonCanvas) findViewById(R.id.DrawPolygonCanvas);
img = (ImageView) findViewById(R.id.office);
}
public Bitmap getBitmap(){
Bitmap bm = ((BitmapDrawable) img.getDrawable()).getBitmap();
return bm;
}
public void onReset(View v) {
DrawPolygonCanvas canvas = (DrawPolygonCanvas) findViewById(R.id.DrawPolygonCanvas);
SharedPreferences.Editor editor = UserSharedPref.initializeSharedPreferencesForCameraROI(canvas.getContext()).edit();
editor.putString(UserSharedPref.cameraROI, "");
editor.apply();
canvas.clearROI();
}
}
基本上,这段代码中最重要的部分是 DrawPolygonCanvas 中的 onDraw()出现问题时,这些行,
exampleActivity ex = new exampleActivity();
和Bitmap bm = ex.getBitmap();
所产生的错误是:
java.lang.NullPointerException: Attempt to invoke virtual method 'android.graphics.drawable.Drawable android.widget.ImageView.getDrawable()' on a null object reference
。
由于某种原因,XML文件中的imageView尚未初始化。 我该如何解决这个问题?
答案 0 :(得分:0)
exampleActivity ex = new exampleActivity();
Bitmap bm = ex.getBitmap();
根本原因:由于您正在创建ExampleActivity
的新实例,因此所有活动回调方法,例如onCreate
,onStart
,{{1} }等不会被调用。对于您而言,因为onResume
从未打电话给您,为什么您的onCreate
总是img
。结果,当您在其上调用null
方法时,Android将抛出NullPointerException
。
getDrawable
提示:永远不要在Android中创建Activity的实例,您要做的就是在AndroidManifest.xml文件中注册该活动,然后在Activity回调方法中编写您的代码。
解决方案:返回您的案例,要从Activity中获取位图,您可以实现一个侦听器接口,以将位图从java.lang.NullPointerException: Attempt to invoke virtual method 'android.graphics.drawable.Drawable android.widget.ImageView.getDrawable()' on a null object reference.
传递到exampleActivity
。
DrawPolygonCanvas
DrawPolygonCanvas
exampleActivity
public class DrawPolygonCanvas extends View implements OnTouchListener{
public interface OnGetBitmapListener {
Bitmap onGetBitmap();
}
private OnGetBitmapListener mOnGetBitmapListener;
public void setOnGetBitmapListener(OnGetBitmapListener listener) {
mOnGetBitmapListener = listener;
}
@Override
protected void onDraw(Canvas canvas) {
Log.e(TAG, "called onDraw");
super.onDraw(canvas);
paint.setFilterBitmap(true);
// Add these lines
Bitmap bm = null;
if (mOnGetBitmapListener != null) {
bm = mOnGetBitmapListener.onGetBitmap();
}
canvas.drawBitmap(bm, null, dest, paint);
}
}