1

Hola buenas estoy haciendo un ejercicio de clase de leer y escribir en la tarjeta sd y me salta un nullpointerexception cuando solo estoy referenciando a un boton

package com.dinaprise.ejercicio.ejercicioficherosexternos;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;


/**
 * Clase principal del programa el cual utiliza el metodo on create para iniciar la app
 * @author  Antonio
 */
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MainActivity activida = new MainActivity();
        activida.mostrarDatos();

    }

    /**
     * Metodo el cual agrega los diferentes datos que se mostraran en la APP
     */
    private void mostrarDatos() {
        //Comprobamos el estado de la memoria externa (tarjeta SD)
        String estado = Environment.getExternalStorageState();
        //Compruebo que este montada para poder escribir en la sd
        if (estado.equals(Environment.MEDIA_MOUNTED)) {
            //Creo un boton con la referencia al boton de la vista
            Button btnEscribirSD = findViewById(R.id.escribirSd);
            //Creo un oyente para crear un evento
            btnEscribirSD.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    try {
                        //Creo un edit text con la referencia en la vista
                        EditText texto = findViewById(R.id.etTexto);
                        //Creo un fichero que sera el que se cree
                        File f = new File(getExternalFilesDir(null), "prueba_sd.txt");
                        //Creo el fichero en el sistema de archivos de android
                        OutputStreamWriter fout =
                                new OutputStreamWriter(
                                        new FileOutputStream(f));
                        //Escribo en el archivo el texto indicado por el usuario
                        fout.write(texto.toString());
                        fout.close();
                    } catch (Exception ex) {
                        Log.e(getString(R.string.ficheros), getString(R.string.error_al_escribir));
                    }
                }
            });

            Button btnEscribirSdPublic = findViewById(R.id.escribirSdPublic);
            btnEscribirSdPublic.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    try {
                        EditText texto = findViewById(R.id.etTexto);
                        File f = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath());

                        OutputStreamWriter fout =
                                new OutputStreamWriter(
                                        new FileOutputStream(f));

                        fout.write(texto.toString());
                        fout.close();
                    } catch (IOException ioe) {
                        Log.e(getString(R.string.ficheros), getString(R.string.error_not_found));
                    }
                }
            });

        } else if (estado.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
            Button btnLeerSD = findViewById(R.id.LeerSd);
            btnLeerSD.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    try {
                        File file = new File(getExternalFilesDir(null), "prueba_sd.txt");
                        BufferedReader br = new BufferedReader(
                                new InputStreamReader(
                                        new FileInputStream(file)));
                        String texto = br.readLine();
                        br.close();
                    } catch (IOException ioe) {
                        Log.e(getString(R.string.ficheros), getString(R.string.error_not_found));
                    }

                }
            });

        }

    }

}

Ahora os muestro el codigo de la vista

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/escribirSd"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/escribir" />

    <Button
        android:id="@+id/LeerSd"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignEnd="@+id/escribirSd"
        android:layout_alignRight="@+id/escribirSd"
        android:layout_marginEnd="-116dp"
        android:layout_marginRight="-116dp"
        android:text="@string/leer_sd" />

    <Button
        android:id="@+id/escribirSdPublic"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/LeerSd"
        android:layout_alignEnd="@+id/escribirSd"
        android:layout_alignRight="@+id/escribirSd"
        android:layout_marginTop="-46dp"
        android:layout_marginEnd="-322dp"
        android:layout_marginRight="-322dp"
        android:text="@string/escribir_sd_publica" />

    <EditText
        android:id="@+id/etTexto"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/escribirSdPublic"
        android:layout_marginTop="5dp"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="Introduce el texto" />

</RelativeLayout>

Muestro el error que me sale en la terminal de android studio

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.dinaprise.ejercicio.ejercicioficherosexternos, PID: 5118
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.dinaprise.ejercicio.ejercicioficherosexternos/com.dinaprise.ejercicio.ejercicioficherosexternos.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.Window$Callback android.view.Window.getCallback()' on a null object reference
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
    at android.app.ActivityThread.-wrap12(ActivityThread.java)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6077)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
 Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.Window$Callback android.view.Window.getCallback()' on a null object reference
    at androidx.appcompat.app.AppCompatDelegateImpl.<init>(AppCompatDelegateImpl.java:249)
    at androidx.appcompat.app.AppCompatDelegate.create(AppCompatDelegate.java:182)
    at androidx.appcompat.app.AppCompatActivity.getDelegate(AppCompatActivity.java:520)
    at androidx.appcompat.app.AppCompatActivity.findViewById(AppCompatActivity.java:191)
    at com.dinaprise.ejercicio.ejercicioficherosexternos.MainActivity.mostrarDatos(MainActivity.java:44)
    at com.dinaprise.ejercicio.ejercicioficherosexternos.MainActivity.onCreate(MainActivity.java:31)
    at android.app.Activity.performCreate(Activity.java:6662)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2599)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707) 
    at android.app.ActivityThread.-wrap12(ActivityThread.java) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:154) 
    at android.app.ActivityThread.main(ActivityThread.java:6077) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756) 

Vamos el error lo muestra en la linea en la cual estoy haciendo Button btnEscribirSD = findViewById(R.id.escribirSd); y no se porque realmente da el error ese, cuando unicamente estoy haciendo una referencia al boton. Muchas gracias por la ayuda, y lo siento si no se explicarme porque no se mucho de android studio, gracias!

Ruslan López
  • 10,060
  • 11
  • 35
  • 68
  • 3
    ¿Responde esto a tu pregunta? [¿Cuál es la solución a todos los errores NullPointerException presentes, pasados y futuros?](https://es.stackoverflow.com/questions/42977/cu%c3%a1l-es-la-soluci%c3%b3n-a-todos-los-errores-nullpointerexception-presentes-pasados) – BetaM Feb 02 '20 at 18:58
  • ¿Cómo se llama el archivo XML donde está el botón? – A. Cedano Feb 02 '20 at 19:24
  • activity_main.xml – Antonio Jesús Feb 02 '20 at 19:26
  • No entiendo por qué creas una instancia de `MainActivity` siendo que estás ya en ella ¿? Prueba a borrar estas dos líneas: `MainActivity activida = new MainActivity(); activida.mostrarDatos();` y pon solamente esto: `mostrarDatos();` – A. Cedano Feb 02 '20 at 19:33
  • Muchas gracias era eso, pero porque daba error?, y sorry es que tampoco he tocado mucho android studio y el año pasado con java lo haciamos asi y pues no habia problemas, muchas gracias – Antonio Jesús Feb 02 '20 at 19:35
  • 1
    Me parece que no funciona porque al usar una instancia de la clase, te falta el contexto, el cual es fundamental para las clases de tipo `Activity`. De cualquier modo, no tiene sentido instanciar una clase en la que ya estás para usar sus propios métodos mediante esa instancia. No sé, es como si estás casado con una mujer y te compras un peluche para dispensarle todas tus atenciones, cuando tu mujer real está ahí. – A. Cedano Feb 02 '20 at 19:44
  • AH pues tambien es verdad jajajaja y buen ejemplo ajajajjaa, muchas gracias estaba ya volviendome loco de ver el fallo, llevaba aqui 4 horas y no sabia como arreglarlo – Antonio Jesús Feb 02 '20 at 19:46

1 Answers1

1

Tu fallo está aquí:

    MainActivity activida = new MainActivity();
    activida.mostrarDatos();

Estando ya en MainActivity, estás creando una nueva instancia de la clase en la que ya estás para invocar sus métodos.

Si Android no interpreta esto como un despropósito, al menos será necesario que pases también el contexto, porque será como usar la clase MainActivity como si estuvieras fuera de ella.

El asunto crucial es que no necesitas crear una instancia de MainActivity, ¡porque ya estás en MainActivity! y por tanto puedes invocar al método directamente.

Solución

Borra esto:

    MainActivity activida = new MainActivity();
    activida.mostrarDatos();

Y pon solo esto:

    mostrarDatos();

El método onCreate debería quedar así:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mostrarDatos();
}
A. Cedano
  • 86,578
  • 19
  • 122
  • 221