Erro ao inflar ao estender uma classe

188

Estou tentando criar uma exibição personalizada GhostSurfaceCameraViewque se estende SurfaceView. Aqui está o meu arquivo de definição de classe

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();
    }
}

E isso está no meu ghostviewscreen.xml:

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

Agora na atividade que fiz:

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

Quando setContentView()é chamado, uma exceção é lançada:

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

Alguém pode me dizer por que recebo esse erro? Obrigado.

excentricbiped
fonte

Respostas:

369

Acho que descobri por que isso não estava funcionando. Eu estava fornecendo apenas um construtor para o caso de um parâmetro 'contexto' quando deveria ter fornecido um construtor para o caso de dois parâmetros 'Context, AttributeSet'. Eu também precisava dar acesso ao construtor (es) público. Aqui está a minha correção:

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();
        }
excentricbiped
fonte
4
Às vezes, as coisas mais simples podem ser um problema :) É bom saber que os dois parâmetros são usados ​​para inflar.
Warpzit
5
Obrigado!! Em nenhum lugar dos exemplos eu pude encontrar alguma menção sobre a necessidade de sobrecarregar todos os construtores! Você me salvou horas (dias?) De tempo.
22812 Scott Biggs #
1
Muito obrigado! A mensagem de erro é bastante inespecífica, o que me deixou perplexo por um momento; eles deveriam ter incluído o motivo (falta de sobrecarga do construtor) em sua mensagem de erro.
AgentKnopf
1
obrigado por isso. alguém sabe se isso se aplica a visualizações personalizadas? você precisa incluir os dois construtores sempre que criar uma exibição personalizada? (contexto, e em seguida contexto e atributos)
Tim
2
O, deveria ter visto isso antes! A mensagem View is not using the 2- **OR** 3-argument View constructorsé meio enganosa.
Attacktive
45

@ Tim - Ambos os construtores não são necessários, apenas o ViewClassName(Context context, AttributeSet attrs )construtor é necessário. Descobri isso da maneira dolorosa, depois de horas e horas perdidas.

Sou muito novo no desenvolvimento do Android, mas estou fazendo um palpite aqui, que talvez seja devido ao fato de que, como estamos adicionando a Viewclasse personalizada no arquivo XML, estamos definindo vários atributos no XML, o que precisa para ser processado no momento da instanciação. Alguém muito mais experiente que eu será capaz de lançar uma luz mais clara sobre esse assunto.

KVNam
fonte
Isso faz sentido, meu TextView personalizado sempre é construído com ViewClassName (contexto de contexto, AttributeSet attrs) quando eu defino atributos para ele no xml. Se eu instanciar sem definir no arquivo xml, o construtor regular é chamado apenas com o contexto ViewClassName (contexto de contexto). Eu queria saber o que o outro construtor faz e, de acordo com isso: stackoverflow.com/a/4022916/1505341 resposta, ele deveria ser usado para definir um estilo de base para a exibição.
Kerem
19

Outra causa possível da mensagem "Erro ao inflar classe" pode estar digitando incorretamente o nome completo do pacote, onde está especificado em XML:

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

A abertura do arquivo XML de layout no editor XML do Eclipse deve destacar esse problema.

rmtheis
fonte
2
Essa foi realmente a correção para o meu aplicativo. com.zerokol.views.joystickview Tornou-se com.zerokol.views.JoystickView E funcionou!
Andy
verdade. Verifique a ortografia ou tente trabalhar usando as intenções fornecidas pelo seu IDE, basta digitar o nome do pacote e todas as suas classes disponíveis serão mostradas nas intenções.
Khay 27/02
esse foi o meu caso.
Banee Ishaque K
2

É importante escrever o caminho completo da classe no xml. Recebi 'Erro ao inflar a classe' quando apenas o nome da subclasse foi escrito.

Mykola
fonte
Isso é muito parecido com o que @rmtheis está sugerindo. Talvez seja melhor comentar sua resposta ou até mesmo editá-la com informações adicionais.
Ilia Barahovski
1

Eu tive esse erro me atormentando nas últimas horas. Acontece que eu adicionei a lib de exibição personalizada como um módulo no Android Studio, mas deixei de incluí-la como uma dependência nos aplicativos build.gradle.

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

fwiw , recebi esse erro devido a alguma inicialização personalizada dentro do construtor tentando acessar um objeto nulo.

Tom Howard
fonte
0

Eu tive o mesmo problema ao estender um TextEdit. Para mim, o erro foi não adicionar "público" ao construtor. No meu caso, funciona mesmo se eu definir apenas um construtor, aquele com argumentos Contexte AttributeSet. O problema é que o bug só se revela quando eu construo um APK (chamuscado ou não) e o transfiro para os dispositivos. Quando o aplicativo é executado via AndroidStudio -> RunApp em um dispositivo conectado por USB, o aplicativo funciona.

Nicola Mingotti
fonte
0

no meu caso, adicionei esse recurso cíclico:

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

então mudou para

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

e funcionou

Evgenii Vorobei
fonte
0

No meu caso, copiei minha classe de outro lugar e não percebi imediatamente que era uma abstractaula. Você não pode inflar classes abstratas.

IsaiahJ
fonte
0

O que se deve entender aqui é o seguinte:

O construtor ViewClassName(Context context, AttributeSet attrs )é chamado ao inflar o customView via xml. Você vê que não está usando a nova palavra-chave para instanciar seu objeto, ou seja, não está fazendo new GhostSurfaceCameraView(). Fazendo isso, você está chamando o primeiro construtor, ie public View (Context context).

Enquanto que ao inflar a visualização do XML, ou seja, ao usar setContentView(R.layout.ghostviewscreen);ou usar findViewById, você NÃO, você não! , o sistema Android chama o ViewClassName(Context context, AttributeSet attrs )construtor.

Isso fica claro ao ler a documentação: "Construtor chamado ao inflar uma exibição do XML". Consulte: https://developer.android.com/reference/android/view/View.html#View(android.content.Context,%20android.util.AttributeSet)

Portanto, nunca se esqueça do polimorfismo básico e nunca se esqueça de ler a documentação. Isso economiza uma tonelada de dor de cabeça.

kush
fonte