Dentro de OnClickListener no puedo acceder a muchas cosas, ¿cómo abordarlo?

79

Dentro de un OnClickListener no puedo acceder a la mayoría de las variables "fuera" del alcance, así:

findViewById(R.id.Button01).setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                Intent mainApps = new Intent(Intent.ACTION_MAIN);
                mainApps.addCategory(Intent.CATEGORY_LAUNCHER);
                List<ActivityInfo> activities = this.getPackageManager().queryIntentActivities(mainApps, 0);
                /*
                Intent intent = new Intent("com.sygic.drive/com.sygic/drive/.SygicDriveActivity");
                startActivity(intent);*/
            }

        });

en este ejemplo, necesito obtener el PacketManager, y no puedo obtenerlo porque no tengo el Contexto disponible dentro de OnClickListener.

Podría hacer una referencia estática afuera y usarla adentro, pero ¿es eso correcto? ¿Parece extraño tener que hacer eso todo el tiempo?

Ted
fuente

Respuestas:

231

Reemplace thisen su código con MyActivity.thisdonde MyActivity es el nombre de clase de su subclase Activity.

Explicación: Estás creando una clase interna anónima cuando usas esta parte de tu código:
new OnClickListener() {
Las clases internas anónimas tienen una referencia a la instancia de la clase en la que se crearon. Parece que la estás creando dentro de una subclase de Actividad porque findViewById es una Método de actividad. Las actividades son un contexto, por lo que todo lo que necesita hacer es usar la referencia que tiene automáticamente.

Lance Nanek
fuente
1
He estado buscando en Google durante un tiempo solo para encontrar "MyActivity.this". Parece tan simple ahora. Gracias por la info!
TCCV
¿Qué hay de acceder a las variables que dan el error Cannot refer to a non-final variable table inside an inner class defined in a different method? No puedo acceder a esos a través de MyActivity.this.
Michael
Esas son variables locales. Si no cambian, puede cambiar su declaración para tener final en ellos. Si cambian, pero antes de que se defina su clase interna, puede definir una versión final justo antes. Por ejemplo: final int myFinalErrorCode = errorCode. De lo contrario, debe hacer algo como crear y establecer un miembro en la actividad a la que accede o en la clase interna.
Lance Nanek
No entiendo cómo se comporta, pero funciona como dijiste Activity.this.doStg(). ¿Puedes adjuntar aquí @LanceNanek alguna URL con una explicación más detallada? ¿Está relacionado de alguna manera con la programación reactiva?
murt
Vea el ejemplo de "ShadowTest.this" aquí: docs.oracle.com/javase/tutorial/java/javaOO/nested.html
Lance Nanek
10

También puede implementar la interfaz OnClickListener en su clase y evitar la necesidad de una clase interna anónima. Luego, establecería el oyente al hacer clic de esta manera:

findViewById(R.id.Button01).setOnClickListener(this);

Si tiene varios botones que usan un oyente, puede usar una instrucción de cambio con view.getId () (que corresponde a la identificación de la vista en R.id) para distinguir entre ellos.

Alabama.
fuente
4

Hay algunas cosas que puede hacer, puede crear una clase interna que implemente onClickListener y pasar los argumentos necesarios al constructor de la clase. Sigo sin encontrar ese enfoque más limpio. Por lo general, solo creo otro método para realizar mi acción. Entonces, en onClick (View v) haría algo como esto.

onClick(View v){doMyAction(myParams)}

private void doMyAction(Object params){//do stuff}

Y simplemente pase los parámetros necesarios del método de escucha al método fuera del escucha.

broschb
fuente
Ok, es raro que tengas que hacerlo de esa manera, pero supongo que funciona. =)
Ted
0

Cambie el constructor Intent en uso a Intent (contexto, nombre de clase) y use getApplicationContext () en su clase interna. Resolvió mi problema de todos modos.

WayneSplatter
fuente