Android:Crash: Binary XML file line : Error inflating class (using SurfaceView)

m4n07 picture m4n07 · Apr 29, 2011 · Viewed 33.3k times · Source

I'm having android surfaceView and in that I'm trying to add buttons to this. In the surfaceView canvas I draw something. And I have a thread class to keep drawing.

package com.androidsurfaceview;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class androidsurfaceview extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Button buttonShowHide = (Button)findViewById(R.id.showhide);
        final Button buttonDummy = (Button)findViewById(R.id.dummy);

        buttonShowHide.setOnClickListener(
                new Button.OnClickListener(){

                    @Override
                    public void onClick(View arg0) {
                        // TODO Auto-generated method stub
                        if(buttonDummy.getVisibility()==View.VISIBLE){
                            buttonDummy.setVisibility(View.GONE);
                        }
                        else{
                            buttonDummy.setVisibility(View.VISIBLE);
                        }
                    }

                }
        );

The thread class

package com.androidsurfaceview;

import android.graphics.Canvas;
import android.view.SurfaceHolder;
public class MySurfaceThread extends Thread {
    private SurfaceHolder myThreadSurfaceHolder;
    private com.androidsurfaceview.test.MySurfaceView  myThreadSurfaceView;
    private boolean myThreadRun = false;

    public MySurfaceThread(SurfaceHolder surfaceHolder, com.androidsurfaceview.test.MySurfaceView surfaceView) {
        myThreadSurfaceHolder = surfaceHolder;
        myThreadSurfaceView = surfaceView;
    }

    public void setRunning(boolean b) {
        myThreadRun = b;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(myThreadRun){
            Canvas c = null;

            try{
                c = myThreadSurfaceHolder.lockCanvas(null);
                synchronized (myThreadSurfaceHolder){
                    myThreadSurfaceView.onDraw(c);
                }
                sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            finally{
                // do this in a finally so that if an exception is thrown
                // during the above, we don't leave the Surface in an
                // inconsistent state
                if (c != null) {
                    myThreadSurfaceHolder.unlockCanvasAndPost(c);
                }
            }
        }
    }
}

The surfaceView & the class for drawing

 package com.androidsurfaceview;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

 public class test extends Activity{

      //     ......
       //   I do a few things here... with this class test.

    public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{

        private MySurfaceThread thread;
        private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        int cx, cy, offx, offy;

        public MySurfaceView(Context context) {
            super(context);
            // TODO Auto-generated constructor stub
            init();
        }

        public MySurfaceView(Context context, AttributeSet attrs) {
            super(context, attrs);
            // TODO Auto-generated constructor stub
            init();
        }

        public MySurfaceView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            // TODO Auto-generated constructor stub
            init();
        }

         private void init(){
              getHolder().addCallback(this);
              thread = new MySurfaceThread(getHolder(), this);

              setFocusable(true); // make sure we get key events

              paint.setStyle(Paint.Style.STROKE);
              paint.setStrokeWidth(3);
              paint.setColor(Color.WHITE);

              cx = 0;
              cy = 0;
              offx = 10;
              offy = 10;

             }

        @Override
        public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
            // TODO Auto-generated method stub

        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            // TODO Auto-generated method stub
            thread.setRunning(true);
            thread.start();

        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            // TODO Auto-generated method stub
            boolean retry = true;
            thread.setRunning(false);
            while (retry) {
                try {
                    thread.join();
                    retry = false;
                } 
                catch (InterruptedException e) {
                }
            }
        }
    ////Just a simple graphic of moving circle.
        @Override
        protected void onDraw(Canvas canvas) {
            // TODO Auto-generated method stub
            canvas.drawRGB(0, 0, 0);
            canvas.drawCircle(cx, cy, 3, paint);
            cx += offx;
            if (cx > getWidth() || (cx < 0)){
                offx *= -1;
                cx += offx;
            }

            cy += offy;
            if (cy > getHeight() || (cy < 0)){
                offy *= -1;
                cy += offy;
            }
        }
    }
    }

Here is the main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
<Button
    android:id="@+id/showhide"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="Toggle The Another Button Show/Hide" />
<Button
    android:id="@+id/dummy"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="a Button" />
<FrameLayout 
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

<com.androidsurfaceview.test.MySurfaceView
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"/>

</FrameLayout>
</LinearLayout>

PROBLEM: The above code works ONLY if I don't have the "MySurfaceView" as nested class. but with the outer class "test" I get the following error. If I remove the "class test" it works fine.

Error/Crash

04-29 11:43:18.977: ERROR/AndroidRuntime(21832): FATAL EXCEPTION: main
04-29 11:43:18.977: ERROR/AndroidRuntime(21832): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.androidsurfaceview/com.androidsurfaceview.androidsurfaceview}: **android.view.InflateException: Binary XML file line #20: Error inflating class com.androidsurfaceview.test.MySurfaceView**
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2663)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at android.app.ActivityThread.access$2300(ActivityThread.java:125)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at android.os.Handler.dispatchMessage(Handler.java:99)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at android.os.Looper.loop(Looper.java:123)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at android.app.ActivityThread.main(ActivityThread.java:4627)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at java.lang.reflect.Method.invokeNative(Native Method)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at java.lang.reflect.Method.invoke(Method.java:521)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at dalvik.system.NativeStart.main(Native Method)
**04-29 11:43:18.977: ERROR/AndroidRuntime(21832): Caused by: android.view.InflateException: Binary XML file line #20: Error inflating class com.androidsurfaceview.test.MySurfaceView**
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:576)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:618)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:621)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at android.view.LayoutInflater.inflate(LayoutInflater.java:407)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:200)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at android.app.Activity.setContentView(Activity.java:1647)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at com.androidsurfaceview.androidsurfaceview.onCreate(androidsurfaceview.java:13)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
04-29 11:43:18.977: ERROR/AndroidRuntime(21832):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)

Any help will be great ...I'm stuck with this.

Answer

rekaszeru picture rekaszeru · Apr 29, 2011

First, you must declare your view as a static type, to be able to be inflated it even when no instance of the holding class is available:

public static class MySurfaceView extends SurfaceView 
    implements SurfaceHolder.Callback

The line

<com.androidsurfaceview.test.MySurfaceView

in your layout xml suggests, that the MySurfaceView class is inside the com.androidsurfaceview.test package, and tries to inflate it from there, which is wrong.

In your layout you should follow the package.class$innerclass form of declaration.

BUT since the "$" is illegal character, you cannot write

<com.androidsurfaceview.test$MySurfaceView

so you must specify your view in the layout xml as follows:

<view class="com.androidsurfaceview.test$MySurfaceView"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"/>

This way it will work.