Question

This question seems to have been asked a lot, but I couldn't find an answer. I welcome any links to a duplicate that solves my problem.

I have two views, one custom and one defined in xml as

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:id="@+id/button_bar_id" >

    <Button
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content"
        android:id="@+id/button_undo"></Button>
</LinearLayout>

In my main activity, I get a reference to the two views, and create a FrameLayout to put them in:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    canvasView = new CustomCanvasView(this);

    buttonBar = (LinearLayout) findViewById(R.id.button_bar_id);
    frameLayout = new FrameLayout(this);
    frameLayout.addView(canvasView);
    frameLayout.addView(buttonBar);
    setContentView(frameLayout);
}

and that's it! Everything works if I'm just using the FrameLayout and my custom view, but if I try to add the predefined view buttonBar then I get a nullPointerException from the line where I initialize it.

I looked at this question where the solution seemed to be to call setContentView(frameLayout) first, but that doesn't work for me, and in fact makes the working case (where I don't add buttonBar) crash paradoxically.

Any notion as to what is going on here?

Thanks!

UPDATE

So, as some have suggested I tried modifying my xml file so that it includes a reference to my custom view:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:id="@+id/button_bar_id" >

<com.collin.customcanvasengine.CustomCanvasView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/customCanvasView">
</com.collin.customcanvasengine.CustomCanvasView>
<Button
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content"
    android:id="@+id/button_undo"></Button>

</LinearLayout>

as well as modifying my main activity so that it uses this xml file as its content view:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.button_bar);

    canvasView = (CustomCanvasView) findViewById(R.id.customCanvasView);
    canvasView.setDimensions(10,10);
    canvasView.requestFocus();
}

Now the error I am getting is that my custom view cannot be inflated:

android.view.InflateException: Binary XML file line #8: Error inflating class com.collin.customcanvasengine.CustomCanvasView

Any ideas? Thanks.

UPDATE

Here is the logcat output:

06-06 01:55:30.010: E/Trace(19901): error opening trace file: Permission denied (13)
06-06 01:55:30.010: D/ActivityThread(19901): setTargetHeapUtilization:0.25
06-06 01:55:30.010: D/ActivityThread(19901): setTargetHeapIdealFree:8388608
06-06 01:55:30.010: D/ActivityThread(19901): setTargetHeapConcurrentStart:2097152
06-06 01:55:30.050: D/AndroidRuntime(19901): Shutting down VM
06-06 01:55:30.050: W/dalvikvm(19901): threadid=1: thread exiting with uncaught exception     (group=0x410b5438)
06-06 01:55:30.060: I/Process(19901): Sending signal. PID: 19901 SIG: 9
06-06 01:55:30.060: E/AndroidRuntime(19901): FATAL EXCEPTION: main
06-06 01:55:30.060: E/AndroidRuntime(19901): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.collin.customcanvasengine/com.collin.customcanvasengine.MainActivity}: android.view.InflateException: Binary XML file line #8: Error inflating class com.collin.customcanvasengine.CustomCanvasView
06-06 01:55:30.060: E/AndroidRuntime(19901):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2117)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2155)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at android.app.ActivityThread.access$700(ActivityThread.java:139)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1248)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at android.os.Handler.dispatchMessage(Handler.java:99)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at android.os.Looper.loop(Looper.java:137)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at android.app.ActivityThread.main(ActivityThread.java:5062)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at java.lang.reflect.Method.invokeNative(Native Method)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at java.lang.reflect.Method.invoke(Method.java:511)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:558)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at dalvik.system.NativeStart.main(Native Method)
06-06 01:55:30.060: E/AndroidRuntime(19901): Caused by: android.view.InflateException: Binary XML file line #8: Error inflating class com.collin.customcanvasengine.CustomCanvasView
06-06 01:55:30.060: E/AndroidRuntime(19901):    at android.view.LayoutInflater.createView(LayoutInflater.java:596)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:687)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:256)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at android.app.Activity.setContentView(Activity.java:1893)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at com.collin.customcanvasengine.MainActivity.onCreate(MainActivity.java:23)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at android.app.Activity.performCreate(Activity.java:5058)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2081)
06-06 01:55:30.060: E/AndroidRuntime(19901):    ... 11 more
06-06 01:55:30.060: E/AndroidRuntime(19901): Caused by: java.lang.NoSuchMethodException: <init> [class android.content.Context, interface android.util.AttributeSet]
06-06 01:55:30.060: E/AndroidRuntime(19901):    at java.lang.Class.getConstructorOrMethod(Class.java:460)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at java.lang.Class.getConstructor(Class.java:431)
06-06 01:55:30.060: E/AndroidRuntime(19901):    at android.view.LayoutInflater.createView(LayoutInflater.java:561)
06-06 01:55:30.060: E/AndroidRuntime(19901):    ... 22 more

Also, the constructor for CustomCanvasView is of the form

public CustomCanvasView(Context context)

FINAL UPDATE

So Christopher Perry's answer worked best for me. As suggested, it is necessary to have a constructor of the form public CustomCanvasView(Context context, AttributeSet attr) and, importantly, to pass the attribute set to the parent in the call to super within this constructor. At the moment I have not used the attribute set in the constructor but I may decide to implement custom attributes in the future. It will work either way.

Thanks again to everyone, and thanks Christopher Perry for being quite helpful.

Was it helpful?

Solution 2

You are asking the Activity to find your view before you even put it in the view hierarchy of the Activity. You need to call setContentView with your layout resource id before you can find views inside of the Activity.

What you should do is change your xml to something like this (i.e. your xml file is called some_layout.xml in this example, since I don't know your file name):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content"
        android:id="@+id/button_undo" />

    <com.mypackage.CustomCanvasView
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" />

</LinearLayout>

Then your onCreate is simply:

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.some_layout);
    }

Since you are putting a custom View in the Activity view hierarchy, just declare it in the layout xml file. There's no reason to clutter up your Activity code with things Android already does for you.

EDIT:

Make sure you define a constructor in your CustomCanvasView class that takes an AttributeSet or you'll get an InflateException. Like so:

public CustomCanvasView(Context context, AttributeSet attributes) {
  super(context, attributes);
  // code goes here
}

OTHER TIPS

try it as using LayoutInflater.inflate :

canvasView = new CustomCanvasView(this);
LayoutInflater inflater= (LayoutInflater)this.getSystemService(
                                               Context.LAYOUT_INFLATER_SERVICE);
View buttonBar=inflater.inflate(R.layout.your_layout_name,null);
frameLayout = new FrameLayout(this);
frameLayout.addView(canvasView);
frameLayout.addView(buttonBar);
setContentView(frameLayout);

You need to set the content of your layout to the activity first

  setContentView(R.layout.mylayout);

Then you can findviewbyid (initialize views);

   buttonBar = (LinearLayout) findViewById(R.id.button_bar_id); 

You can findViewById of the current view hierarchy set to the activity. If view is not initialized you get NullPointerException

Use buttonBar = (LinearLayout)canvasView. findViewById(R.id.button_bar_id);

You will have to inflate your layout first and then add it into your frameLayout

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top