Error al inflar al extender una clase

188

Estoy tratando de crear una vista personalizada GhostSurfaceCameraViewque se extienda SurfaceView. Aquí está mi archivo de definición de clase

GhostSurfaceCameraView.java:

public class GhostSurfaceCameraView extends SurfaceView implements SurfaceHolder.Callback {
    SurfaceHolder mHolder;
    Camera mCamera;

    GhostSurfaceCameraView(Context context) {
        super(context);

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, acquire the camera and tell it where to draw.
        mCamera = Camera.open();
        try {
            mCamera.setPreviewDisplay(holder);
        } catch (IOException exception) {
            mCamera.release();
            mCamera = null;
            // TODO: add more exception handling logic here
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // Surface will be destroyed when we return, so stop the preview.
        // Because the CameraDevice object is not a shared resource, it's very
        // important to release it when the activity is paused.
        mCamera.stopPreview();
        mCamera.release();
        mCamera = null;
    }   

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // Now that the size is known, set up the camera parameters and begin
        // the preview.
        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPreviewSize(w, h);
        parameters.set("orientation", "portrait");
        // parameters.setRotation(90); // API 5+
        mCamera.setParameters(parameters);
        mCamera.startPreview();
    }
}

Y esto está en mi ghostviewscreen.xml:

<com.alpenglow.androcap.GhostSurfaceCameraView android:id="@+id/ghostview_cameraview"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"/>

Ahora en la actividad que hice:

protected void onCreate(Bundle savedInstanceState) {
    try {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.ghostviewscreen);
    }
}

Cuando setContentView()se llama, se lanza una excepción:

Binary XML file 09-17 22:47:01.958: ERROR/ERROR(337):
ERROR IN CODE:
android.view.InflateException: Binary
XML file line #14: Error inflating
class
com.alpenglow.androcap.GhostSurfaceCameraView

¿Alguien puede decirme por qué me sale este error? Gracias.

excéntrico
fuente

Respuestas:

369

Creo que descubrí por qué esto no estaba funcionando. Solo estaba proporcionando un constructor para el caso de un parámetro 'contexto' cuando debería haber proporcionado un constructor para el caso de dos parámetros 'Contexto, AttributeSet'. También necesitaba dar acceso público al constructor. Aquí está mi solución:

public class GhostSurfaceCameraView extends SurfaceView implements SurfaceHolder.Callback {
        SurfaceHolder mHolder;
        Camera mCamera;

        public GhostSurfaceCameraView(Context context)
        {
            super(context);
            init();
        }
        public GhostSurfaceCameraView(Context context, AttributeSet attrs)
        {
            super(context, attrs);
            init();
        }
        public GhostSurfaceCameraView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            init();
        }
excéntrico
fuente
44
A veces, las cosas más simples pueden ser un problema :) es bueno saber que ambos parámetros se usan para inflar.
Warpzit
55
¡¡Gracias!! ¡En ninguna parte de los ejemplos podría encontrar alguna mención sobre la necesidad de sobrecargar a todos los constructores! Me ahorraste horas (días?) De tiempo.
Scott Biggs
1
¡Muchas gracias! El mensaje de error es bastante inespecífico, lo que me dejó perplejo por un momento, deberían haber incluido la razón (falta de sobrecarga del constructor) en su mensaje de error.
AgentKnopf
1
gracias por esto. ¿Alguien sabe si esto va en todos los ámbitos para las vistas personalizadas? necesita incluir ambos constructores cada vez que realiza una vista personalizada? (contexto, y luego contexto y atributos)
Tim
2
¡Oh, debería haberlo visto antes! El mensaje View is not using the 2- **OR** 3-argument View constructorses un poco engañoso.
Ataque el
45

@Tim: no se requieren los ViewClassName(Context context, AttributeSet attrs )constructores , solo el constructor es necesario. Descubrí esto de la manera dolorosa, después de horas y horas de tiempo perdido.

Soy muy nuevo en el desarrollo de Android, pero estoy haciendo una suposición descabellada aquí, que tal vez se deba al hecho de que como estamos agregando la Viewclase personalizada en el archivo XML, le estamos configurando varios atributos en el XML, que necesita para ser procesado en el momento de la instanciación. Sin embargo, alguien mucho más informado que yo podrá arrojar luz más clara sobre este asunto.

KVNam
fuente
Esto tiene sentido, mi TextView personalizado siempre se construye con ViewClassName (Contexto de contexto, AttributeSet attrs) cuando defino atributos para él en el xml. Si lo instancia sin definir en el archivo xml, se llama al constructor regular con solo contexto, ViewClassName (contexto de contexto). Me preguntaba qué hace el otro constructor y de acuerdo con esto: stackoverflow.com/a/4022916/1505341 respuesta, se supone que debe usarse para establecer un estilo base para la vista.
Kerem
19

Otra posible causa del mensaje "Error al inflar la clase" podría ser escribir mal el nombre completo del paquete donde se especifica en XML:

<com.alpenglow.androcap.GhostSurfaceCameraView android:id="@+id/ghostview_cameraview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"/>

Abrir su archivo XML de diseño en el editor XML de Eclipse debería resaltar este problema.

rmtheis
fuente
2
De hecho, esta fue la solución para mi aplicación. com.zerokol.views.joystickview Se convirtió en com.zerokol.views.JoystickView ¡Y funcionó!
Andy
cierto. Verifique la ortografía o intente trabajar con las intenciones proporcionadas por su IDE, simplemente comience escribiendo el nombre del paquete y todas sus clases disponibles se mostrarán bajo intenciones.
Khay
Este fue mi caso.
Banee Ishaque K
2

Es importante escribir la ruta de clase completa en el xml. Obtuve 'Error al inflar la clase' cuando solo se escribió el nombre de la subclase.

Mykola
fuente
Esto es muy similar a lo que sugiere @rmtheis. Posiblemente mejor comentar su respuesta o incluso editarla con información adicional.
Ilia Barahovski
1

Tuve este error plagándome durante las últimas horas. Resulta que había agregado la vista personalizada lib como un módulo en Android Studio, pero había olvidado agregarla como una dependencia en la aplicación build.gradle.

dependencies {
    ...
    compile project(':gifview')
}
Ionoclast Brigham
fuente
1

fwiw , recibí este error debido a una inicialización personalizada dentro del constructor que intentaba acceder a un objeto nulo.

Tom Howard
fuente
0

Tuve el mismo problema al extender un TextEdit. Para mí, el error fue que no agregué "public" al constructor. En mi caso funciona incluso si defino solo un constructor, el que tiene argumentos Contexty AttributeSet. Lo cableado es que el error se revela solo cuando construyo un APK (chamuscado o no) y lo transfiero a los dispositivos. Cuando la aplicación se ejecuta a través de AndroidStudio -> RunApp en un dispositivo conectado por USB, la aplicación funciona.

Nicola Mingotti
fuente
0

en mi caso agregué dicho recurso cíclico:

<drawable name="above_shadow">@drawable/above_shadow</drawable>

luego cambió a

<drawable name="some_name">@drawable/other_name</drawable>

Y funcionó

Evgenii Vorobei
fuente
0

En mi caso, copié mi clase de otro lugar y no noté de inmediato que era una abstractclase. No puedes inflar clases abstractas.

IsaiahJ
fuente
0

Lo que hay que entender aquí es que:

Se ViewClassName(Context context, AttributeSet attrs )llama al constructor al inflar customView a través de xml. Verá que no está utilizando la nueva palabra clave para crear una instancia de su objeto, es decir, no lo está haciendo new GhostSurfaceCameraView(). Al hacer esto , está llamando al primer constructor, es decir public View (Context context).

Mientras que al inflar la vista desde XML, es decir, al usar setContentView(R.layout.ghostviewscreen);o usar findViewById, usted, NO, ¡no usted! , el sistema android llama al ViewClassName(Context context, AttributeSet attrs )constructor.

Esto es claro al leer la documentación: "Constructor que se llama al inflar una vista desde XML". Ver: https://developer.android.com/reference/android/view/View.html#View(android.content.Context,%20android.util.AttributeSet)

Por lo tanto, nunca olvide el polimorfismo básico y nunca olvide leer la documentación. Se ahorra un montón de dolor de cabeza.

kush
fuente