Problema con DialogFragment

247 views
Skip to first unread message

Miguel Martín

unread,
Aug 18, 2014, 2:23:50 AM8/18/14
to desarrollad...@googlegroups.com


Buenas, llevo tiempo desconectado de la programación en Android, me gustaría volver a ponerme al día, he vuelto a cargar mi vieja aplicación y actualizado Android Studio a su última versión (0.8.6, si ya lo se que no se recomienda para principiantes ya lo se yaaaaaa) y ahora puedo compilarla normalmente y funciona y tal, el problema es cuando quiero generar el apk firmado, el compilador se detiene y me muestra el siguiente error en la creación del dialogfragment:

Error:Error: This fragment inner class should be static (soscall.MenuPrincipal.DialogoConfirmacionSMS) [ValidFragment]

Y este es el código:

public class DialogoConfirmacionSMS extends DialogFragment {

        public DialogoConfirmacionSMS() {
            // Empty Constructor
        }


        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {

            AlertDialog.Builder builder =
                    new AlertDialog.Builder(getActivity());

            builder.setMessage(getApplication().getString(R.string.confirmacion_sms))
                    .setTitle(getString(R.string.confirmacion))
                    .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {

                            enviaSMS();
                            dialog.cancel();
                        }
                    })
                    .setNegativeButton(getString(android.R.string.cancel), new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {

                            Toast.makeText(getApplicationContext(), getString(R.string.cancelada), Toast.LENGTH_SHORT).show();
                            dialog.cancel();
                        }
                    });

            return builder.create();
        }
    }


Si le cambio la declaración a 
static public class DialogoConfirmacionSMS extends DialogFragment {....

Entonces vuelve a darme error al compilar en varios puntos de la misma clase:
Error:(966, 44) error: non-static method getApplicationContext() cannot be referenced from a static context
Error:(959, 29) error: non-static method enviaSMS() cannot be referenced from a static context
Error:(955, 32) error: non-static method getApplication() cannot be referenced from a static context



Como llevo tiempo sin tocar android studio seguro que algo ha cambiado en el funcionamiento del dialogfragment, ¿ podéis echarme una manita con el problemilla este ? gracias.

Rafa Couto

unread,
Aug 18, 2014, 5:28:20 AM8/18/14
to desarrollad...@googlegroups.com

No es problema del Android Studio ni de que haya cambiado el funcionamiento del DialogFragment. Es un problema de como programas Java y la orientación a objetos. El error es autoexplicativo: no puedes llamar a los métodos getApplicationContext(), enviaSMS(), getApplication() desde un contexto (Java) estático, el que estás declarando al cambiar la clase con el modificador 'static'.

Puedes redeclarar el método enviaSMS() estático y salvarás ese error, pero no podrás con los otros 2 porque son métodos heredados de DialogFragment: los métodos estáticos no se pueden sobrecargar.

La pregunta del millón es ¿por qué quieres declarar la clase estática? Date cuenta que un DialogFragment vive en cuanto el contexto de la aplicación está inicializado en tiempo de ejecución. Por contra, una variable estática se crea nada más comenzar el programa.

Se puede hacer un 'apaño' utilizando variables bandera para no usar los métodos estáticos mientras el contexto 'no estático' no esté inicializado, pero es una tarea que da más quebraderos de cabeza que soluciones y es perder todas las ventajas de la herencia y la POO...




--
Para participar es necesario que leas detenidamente las normas del grupo: http://goo.gl/8h8ez2
---
Has recibido este mensaje porque estás suscrito al grupo "desarrolladores-android" de Grupos de Google.
Para anular la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a desarrolladores-a...@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a desarrollad...@googlegroups.com.
Visita este grupo en http://groups.google.com/group/desarrolladores-android.
Para ver esta conversación en el sitio web, visita https://groups.google.com/d/msgid/desarrolladores-android/67f31396-ad7d-4f5f-ae6b-ba418982c80e%40googlegroups.com.
Para acceder a más opciones, visita https://groups.google.com/d/optout.



--
Rafa Couto
GNU/Linux user #99126 - http://bit.ly/LC-99126
GPG key - http://bit.ly/GPG-D76ABDEC

Miguel Martín

unread,
Aug 18, 2014, 5:36:44 AM8/18/14
to desarrollad...@googlegroups.com
Investigando por stackoverflow he encontrado como parchearlo añadiendo la linea
@SuppressLint("ValidFragment")

justo antes de la declaración de la clase, por ahora parece que vuelve a funcionar, eso si, si alguien me puede explicar el porque me ha dado este problema ahora se lo agradecería...



Miguel Martín

unread,
Aug 18, 2014, 5:41:26 AM8/18/14
to desarrollad...@googlegroups.com


El lunes, 18 de agosto de 2014 11:28:20 UTC+2, caligari escribió:


La pregunta del millón es ¿por qué quieres declarar la clase estática? Date cuenta que un DialogFragment vive en cuanto el contexto de la aplicación está inicializado en tiempo de ejecución. Por contra, una variable estática se crea nada más comenzar el programa.




No si yo no quiero declararlo estática, es el android studio el que no me dejaba compilarlo si no lo declaraba estática, si lo compilaba normalmente no me daba problemas, si intentaba generar el apk firmado el compilador se paraba en esa linea y me mostraba el error que puse antes, ahora le he agregado el apaño que comente antes y ha vuelto a compilar el apk firmado, pero no se porque en las versiones anteriores de android si me dejaba hacerlo y ahora he tenido que añadir la linea para que lo hiciera, no se si me he explicado bien caligari

Juan de Dios Maldonado Sánchez

unread,
Aug 18, 2014, 7:01:39 AM8/18/14
to desarrollad...@googlegroups.com
Cuando defines una clase (no estática) Frament dentro de una clase Activity, esta, al instanciarse, mantendrá una referencia a la instancia de la clase de la actividad en la que se definió. De forma que cuando se destruya la actividad, si esa clase frament sigue viva (cacheada o lo cualquier cosa similar), como sigue manteniendo la referencia a la instancia de la clase actividad, esta no será recolectada por el recolector de basura, y tendrás una parte de la memoria que no se liberará hasta que este frament no sea eliminado. A este problema se le llama "memory leak", y si no haces las cosas bien, tu aplicación podría hacer que se consumiera toda la memoria del dispositivo.

La solución más sencilla es definir ese fragment en su propio achivo de clase. Cortas y pegas esa clase (no estática) del frament a un archivo con el mismo nombre que la clase del fragment y listo. No tienes que hacer nada más.

NUNCA ES BUENA IDEA SUPRIMIR LAS ADVERTENCIAS DE LINT. SI ESTÁN AHÍ, SON PARA ALGO. :)


--
Para participar es necesario que leas detenidamente las normas del grupo: http://goo.gl/8h8ez2
---
Has recibido este mensaje porque estás suscrito al grupo "desarrolladores-android" de Grupos de Google.
Para anular la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a desarrolladores-a...@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a desarrollad...@googlegroups.com.
Visita este grupo en http://groups.google.com/group/desarrolladores-android.

Miguel Martín

unread,
Aug 18, 2014, 8:43:34 AM8/18/14
to desarrollad...@googlegroups.com
A ver si aprendo y me quedo como va esto...

Creo una nueva clase de nombre "DialogoConfirmacionSMS", corto el código de clase que tenia antes y lo pego en el nuevo fichero, el fichero se ha quedado así:



import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.widget.Toast;

/**
 * Created by Miguel on 18/08/2014.
 */
public class DialogoConfirmacionSMS extends DialogFragment {

    public DialogoConfirmacionSMS() {
        // Empty Constructor
    }


    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        AlertDialog.Builder builder =
                new AlertDialog.Builder(getActivity());

        builder.setMessage(getApplication().getString(R.string.confirmacion_sms))
                .setTitle(getString(R.string.confirmacion))
                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        enviaSMS();
                        dialog.cancel();
                    }
                })
                .setNegativeButton(getString(android.R.string.cancel), new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {

                        Toast.makeText(getApplicationContext(), getString(R.string.cancelada), Toast.LENGTH_SHORT).show();
                        dialog.cancel();
                    }
                });

        return builder.create();
    }
}


Ahora ya me quede pillado otra vez con más errores,

Error:(37, 40) error: cannot find symbol method getApplicationContext()
Error:(30, 25) error: cannot find symbol method enviaSMS()
Error:(26, 28) error: cannot find symbol method getApplication()


he probado a cambiar enviaSMS() por MenuPrincipal.enviaSMS(); pero tampoco le gusta, me dice...
Error:(30, 38) error: non-static method enviaSMS() cannot be referenced from a static context



;'(





El lunes, 18 de agosto de 2014 13:01:39 UTC+2, juande escribió:
Cuando defines una clase (no estática) Frament dentro de una clase Activity, esta, al instanciarse, mantendrá una referencia a la instancia de la clase de la actividad en la que se definió. De forma que cuando se destruya la actividad, si esa clase frament sigue viva (cacheada o lo cualquier cosa similar), como sigue manteniendo la referencia a la instancia de la clase actividad, esta no será recolectada por el recolector de basura, y tendrás una parte de la memoria que no se liberará hasta que este frament no sea eliminado. A este problema se le llama "memory leak", y si no haces las cosas bien, tu aplicación podría hacer que se consumiera toda la memoria del dispositivo.

La solución más sencilla es definir ese fragment en su propio achivo de clase. Cortas y pegas esa clase (no estática) del frament a un archivo con el mismo nombre que la clase del fragment y listo. No tienes que hacer nada más.

NUNCA ES BUENA IDEA SUPRIMIR LAS ADVERTENCIAS DE LINT. SI ESTÁN AHÍ, SON PARA ALGO. :)
2014-08-18 11:41 GMT+02:00 Miguel Martín <joyst...@gmail.com>:


El lunes, 18 de agosto de 2014 11:28:20 UTC+2, caligari escribió:


La pregunta del millón es ¿por qué quieres declarar la clase estática? Date cuenta que un DialogFragment vive en cuanto el contexto de la aplicación está inicializado en tiempo de ejecución. Por contra, una variable estática se crea nada más comenzar el programa.




No si yo no quiero declararlo estática, es el android studio el que no me dejaba compilarlo si no lo declaraba estática, si lo compilaba normalmente no me daba problemas, si intentaba generar el apk firmado el compilador se paraba en esa linea y me mostraba el error que puse antes, ahora le he agregado el apaño que comente antes y ha vuelto a compilar el apk firmado, pero no se porque en las versiones anteriores de android si me dejaba hacerlo y ahora he tenido que añadir la linea para que lo hiciera, no se si me he explicado bien caligari

--
Para participar es necesario que leas detenidamente las normas del grupo: http://goo.gl/8h8ez2
---
Has recibido este mensaje porque estás suscrito al grupo "desarrolladores-android" de Grupos de Google.
Para anular la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a desarrolladores-android+unsub...@googlegroups.com.

Para publicar en este grupo, envía un correo electrónico a desarrollad...@googlegroups.com.
Visita este grupo en http://groups.google.com/group/desarrolladores-android.

Juan de Dios Maldonado Sánchez

unread,
Aug 18, 2014, 9:24:24 AM8/18/14
to desarrollad...@googlegroups.com
Ni me fijé que hacías referencia a la clase donde definías el DialogFragment... :(
Además tendrás que:

Cambiar:

 builder.setMessage(getApplication().getString(R.string.confirmacion_sms))

Por:

builder.setMessage(getString(R.string.confirmacion_sms);

Cambiar:

enviaSMS();

por:

((MenuPrincipal)getActivity()).enviaSMS();

Cambiar:

Toast.makeText(getApplicationContext(), getString(R.string.cancelada), Toast.LENGTH_SHORT).show();

por:

Toast.makeText(getActivity(), getString(R.string.cancelada), Toast.LENGTH_SHORT).show();

PD: Como bien te han dicho, tu problema no es con Android, sino con JAVA. :(

Para anular la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a desarrolladores-a...@googlegroups.com.

Para publicar en este grupo, envía un correo electrónico a desarrollad...@googlegroups.com.
Visita este grupo en http://groups.google.com/group/desarrolladores-android.

Miguel Martín

unread,
Aug 18, 2014, 10:22:22 AM8/18/14
to desarrollad...@googlegroups.com
Tienes toda la razón Juande, entre lo poco que sabía y los meses que llevo sin tocarlo, ahora no doy pie con bola, voy a cambiar el código, muchas gracias por la paciencia :D
Reply all
Reply to author
Forward
0 new messages