Reputation: 41
I am trying to create a drawing activity with a custom view but the app crashes when I try to launch the activity. It does not crash when I remove myDrawView from the layout file. My guess would be that the layout file somehow fails to connect with the custom draw view I've created.
Here is the activity:
public class PaintActivity extends AppCompatActivity {
MyDrawView myDrawView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_paint);
RelativeLayout parent = (RelativeLayout) findViewById(R.id.drawing);
myDrawView = new MyDrawView(this);
parent.addView(myDrawView);
}
public void back(View view){
super.onBackPressed();
}
}
The layout file:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.PaintActivity">
<ImageButton
android:id="@+id/back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="44dp"
android:onClick="back"
app:layout_constraintBottom_toTopOf="@+id/drawing"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/back" />
<info.jonas.notes.view.MyDrawView
android:id="@+id/drawing"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="63dp"
android:layout_marginEnd="61dp"
android:layout_marginLeft="61dp"
android:layout_marginRight="61dp"
android:layout_marginStart="61dp"
android:layout_weight="1"
android:background="#FFFFFFFF"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/back" />
</android.support.constraint.ConstraintLayout>
The MyDrawView.java class:
public class MyDrawView extends View {
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
private Paint mPaint;
public MyDrawView(Context c) {
super(c);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFF000000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(3);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
public void clear(){
mBitmap.eraseColor(Color.TRANSPARENT);
invalidate();
System.gc();
}}
Here is the stack trace:
10-07 15:12:26.797 20682-20682/info.androidhive.sqlite E/AndroidRuntime: FATAL EXCEPTION: main
Process: info.androidhive.sqlite, PID: 20682
java.lang.RuntimeException: Unable to start activity ComponentInfo{info.androidhive.sqlite/info.jonas.notes.view.PaintActivity}: android.view.InflateException: Binary XML file line #20: Binary XML file line #20: Error inflating class info.jonas.notes.view.MyDrawView
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: android.view.InflateException: Binary XML file line #20: Binary XML file line #20: Error inflating class info.jonas.notes.view.MyDrawView
Caused by: android.view.InflateException: Binary XML file line #20: Error inflating class info.jonas.notes.view.MyDrawView
Caused by: java.lang.NoSuchMethodException: <init> [class android.content.Context, interface android.util.AttributeSet]
at java.lang.Class.getConstructor0(Class.java:2327)
at java.lang.Class.getConstructor(Class.java:1725)
at android.view.LayoutInflater.createView(LayoutInflater.java:615)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:790)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
at android.view.LayoutInflater.inflate(LayoutInflater.java:374)
at android.support.v7.app.AppCompatDelegateImplV9.setContentView(AppCompatDelegateImplV9.java:287)
at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:139)
at info.jonas.notes.view.PaintActivity.onCreate(PaintActivity.java:18)
at android.app.Activity.performCreate(Activity.java:7136)
at android.app.Activity.performCreate(Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Please help me find the problem.
Upvotes: 0
Views: 1275
Reputation: 1418
there are 2 issues in this piece of code:
1st: you need to add missing constructors
public MyDrawView(Context context) {
this(context, null);
}
public MyDrawView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MyDrawView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
2nd: wrong casting
findViewById(R.id.drawing);
is not a RelativeLayout, it is your custom view which is MyDrawView
Upvotes: 0
Reputation: 447
As per the stacktrace your MyDrawView needs to override one more constructor.
public class MyDrawView extends View {
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
private Paint mPaint;
public MyDrawView(Context c) {
super(c);
init();
}
public MyDrawView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public void init() {
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFF000000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(3);
}
.........
.........
//Rest of the code
Upvotes: 0
Reputation: 17834
You have two problems I see. The first is in your stacktrace, and the second you'd have run into after fixing the first.
First, you need to add another constructor to your custom View. Otherwise, there's no way for Android to apply any attributes from XML. That's where the crash is happening. Change your current constructor to:
public MyDrawView(Context c, AttributeSet attrs) {
super(c, attrs);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFF000000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(3);
}
And add another constructor:
public MyDrawView(Context c) {
this(c, null);
}
The second issue is, well, your entire onCreate()
method:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_paint);
RelativeLayout parent = (RelativeLayout) findViewById(R.id.drawing);
myDrawView = new MyDrawView(this);
parent.addView(myDrawView);
}
R.id.drawing
is your custom View, which doesn't extend RelativeLayout. In fact, you don't even have a RelativeLayout in your XML. Then you're creating a new instance of your View and attempting to add it to this non-existent RelativeLayout? None of that code is needed if you already have your custom View in XML. Remove it all.
If you need a reference to your View:
myDrawView = findViewById(R.id.drawing);
Upvotes: 3
Reputation: 2045
You need to override other constructor used when the XML is inflated:
public MyDrawView(Context context, AttributeSet attrs) {....
The attrs
contains the view attributes and if you want you can create your own attributes too.
Upvotes: 0