"NullPointerException" error when running an AsyncTask on Android

11

I am working on an Android activity that consults a database to fill a ListView, I leave the code:

    private class EjecutoConsulta extends AsyncTask<Void,Void,List<Comunicado>>{
    @Override
    protected void onPostExecute(List<Comunicado> datos) {
       if (datos!=null){
           rellenaDatos(datos);
       }
    }

    @Override
    protected List<Comunicado> doInBackground(Void... params) {

        DefaultHttpClient httpclient=new DefaultHttpClient();
        String url="http://192.168.0.193/estructuraNueva/scripts/leerComunicados.php";


        HttpGet httpGet=new HttpGet(url);

        String respuesta;


        JSONObject json=null;
        JSONArray jArray=null;

        try {


            ResponseHandler<String> responseHandler=new BasicResponseHandler();

            respuesta=httpclient.execute(httpGet,responseHandler);
            json=new JSONObject(respuesta);

            jArray=json.getJSONArray("datos");

        }catch (Exception e){


            System.out.println("YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY");


        }

        ArrayList<Comunicado> datos=new ArrayList();


        for (int i=0;i<jArray.length();i++){

            JSONObject object=null;

            try {

                object=jArray.getJSONObject(i);

                Comunicado comunicado=new Comunicado(object.getString("id"),object.getString("titulo"),object.getString("texto")
                ,object.getString("imagen"),object.getString("link"));


                datos.add(comunicado);


            }catch (Exception e){
                System.out.println("VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV");

            }

        }

        return datos;
    }
}

When I unplug the server, I get this error:

06-08 09:05:02.413 24754-29704/com.example.oftecnica2.appcorporativa E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: com.example.oftecnica2.appcorporativa, PID: 24754
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:309)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
at java.util.concurrent.FutureTask.run(FutureTask.java:242)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int org.json.JSONArray.length()' on a null object reference
at com.example.oftecnica2.appcorporativa.ComunicadosListado$EjecutoConsulta.doInBackground(ComunicadosListado.java:149)
at com.example.oftecnica2.appcorporativa.ComunicadosListado$EjecutoConsulta.doInBackground(ComunicadosListado.java:100)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
at java.lang.Thread.run(Thread.java:818)

I understand that it jumps when not being able to consult, but if I have everything between try{}catch(){} , I do not understand why it stops the app. Any way that even if I could not consult, keep running like that? (Logically with the empty list).

    
asked by Sergio Cv 08.06.2016 в 09:18
source

5 answers

4

You can determine the problem if you check the message:

  

Caused by: java.lang.NullPointerException: Attempt to invoke virtual   method 'int org.json.JSONArray.length ()' on a null object reference

The problem is caused when you try to access the method length() of the instance jArray that is null.

 for (int i=0;i<jArray.length();i++){
...

It is usually validated with exception handling.

...
...

ArrayList<Comunicado> datos=new ArrayList();
   try {
        for (int i=0;i<jArray.length();i++){

            JSONObject object=null;

                object=jArray.getJSONObject(i);

                Comunicado comunicado=new Comunicado(object.getString("id"),object.getString("titulo"),object.getString("texto")
                ,object.getString("imagen"),object.getString("link"));


                datos.add(comunicado);

              }
     }catch (Exception e){
              System.out.println("Ocurrion un problema: " + e.getMessage());    
     }              

        return datos;
...
...

This is "solved", but it is best to avoid that value is null to not cause problems later in the flow of your application.

  

Any way that even if I could not consult, keep running like   if nothing?

I suggest two options, the first: you can perform a validation through a tertiary operator, if you do not find the array "data", create an empty array and with that you avoid manipulating null values:

//jArray=json.getJSONArray("datos");
   JSONArray  jArray = jObject.has("datos") ? jObject.getJSONArray("datos") : new JSONArray();
 for (int i=0;i<jArray.length();i++){
 ...
 ...

The second one: which I consider the most important, is to review because your request does not obtain data or if it contains data, because it does not contain the json array "data".

respuesta=httpclient.execute(httpGet, responseHandler);
json=new JSONObject(respuesta);         
jArray=json.getJSONArray("datos");

The correct solution would be if no data is found, your request returns the empty "data" array.

Another point that has nothing to do with the question is that it is recommended to stop using the class DefaultHttpClient for connection, since it is a class marked as obsolete:

DefaultHttpClient httpclient=new DefaultHttpClient();
        String url="http://192.168.0.193/estructuraNueva/scripts/leerComunicados.php";
HttpGet httpGet=new HttpGet(url);

instead use HttpUrlConection , I recommend seeing the implementation of this class in Asynctask of @VickyVicent's response.

    
answered by 08.06.2016 / 14:35
source
2

The exception is giving you why when you do the whole down jArray is null and can not get the length property (as this try catch is inside the loop does not take that exception into account), so that it works for you You should take the try catch out of the for loop as well:

try {
for (int i=0;i<jArray.length();i++){

        JSONObject object=null;



            object=jArray.getJSONObject(i);

            Comunicado comunicado=new Comunicado(object.getString("id"),object.getString("titulo"),object.getString("texto")
            ,object.getString("imagen"),object.getString("link"));


            datos.add(comunicado);




}
}catch (Exception e){
            System.out.println("VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV");

        }
    
answered by 08.06.2016 в 09:44
2

If it's any good, I'll take data from a JSON file that a server sends me, I use the following AsyncTask . I have modified it with your data so you can use it directly, although I pass parameters from the onCreate() to the AsyncTask , you can code it.

Call from onCreate() ;

@Override
    public void onCreate() {
        // Iniciamos constantes
        // Nombre el array del JSON. EN tu caso será "datos"
        ARRAY_JSON_ROOT = "datos";
        // URL del archivo PHP que manda los datos en JSON
        URL_PHP = "http://192.168.0.193/estructuraNueva/scripts/leerComunicados.php";
        // Ejecución del AsyncTask
        new getData().execute(URL_PHP);

    }

Class AsyncTask :

public class getData extends AsyncTask<String, Void, ArrayList<Comunicado>> {

        @Override
        protected ArrayList doInBackground(String... params) {
            HttpURLConnection connection = null;
            try {
                // Se declara un ArrayList para guardar los datos que necesitamos
                 ArrayList<Comunicado> datos = new ArrayList();

                // Se establece una conexión a través de la URL_PHP pasada en la llamada al AsycnTask
                URL url = new URL(params[0]);
                connection = (HttpURLConnection) url.openConnection();
                connection.connect();

                // Si esta conexión se establece correctamente, continuará con el proceso. Si no
                // retornara null
                if (connection.getResponseCode() == 200) {

                    // Se almacena los datos recibidos de la petición en un buffer (espacio de
                    // memoria reservado del sistema) y lo convierte en una cadena de String con
                    // StringBuilder.
                    StringBuilder builder = new StringBuilder();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(
                            connection.getInputStream()));
                    String line = "";
                    while ((line = reader.readLine()) != null) {
                        builder.append(line);
                    }

                    // Como el resultado será una cadena de String con formato JSON, debemos
                    // convertir esta esta cadena en un objeto JSON para poder manipularlo. En este
                    // caso lo convertimos finalmente en un JSON Array para poder seleccionar solo
                    // los campos de datos que necesitamos.
                    JSONObject jObject = new JSONObject(builder.toString());
                    JSONArray jArray = jObject.getJSONArray(ARRAY_JSON_ROOT);

                    // Añadimos tantos add como datos queramos coger del JSON y con el tipo de 
                    // valor, ya sea "getString()", "getInt()", "getBoolean"...
                    for (int i=0; i<jArray.length(); i++){

                        Comunicado comunicado = new Comunicado(item.getString("id"), item.getString("titulo"), item.getString("texto"), item.getString("imagen"), item.getString("link"));

                        datos.add(comunicado);

                    }
                    // Devuelve al método "onPostExecute" el ArrayList con los datos
                    return datos; 
                }

            } catch (IOException e) {
                Log.i("IOException", e.getMessage());
            } catch (JSONException e) {
                Log.i("JSONException", e.getMessage());
            } finally {
                if (connection != null) connection.disconnect();
            }

            return null;
        }

        @Override
        protected void onPostExecute(List<Comunicado> datos) {
           if (datos!=null){
               rellenaDatos(datos);
           }
        }
}

I have not answered your question, but I gave you a AsyncTask more complete and with which I have never had any problems. I hope you do not give them to you either.

Anyway, check the code in case I left something of your code that I do not know.

If it is still null once you have implemented the code that I leave you, check the file PHP , the fault may be there.

And to finish just tell you that the failure that is giving you is because your jArray is null and can be for two things:

  • Because you are not receiving anything from the file PHP .
  • Because the try{}catch(){} are affected and in any case it would have to include all the code in one.

Good luck and if you have any questions, ask without fear.

Good luck with your app !!

    
answered by 08.06.2016 в 10:35
1

Here I leave another way that I usually use a lot to check if a value that contains a JSON exists:

   jArray = json.has("datos") ? json.getJSONArray("datos") : null;

   if(jArray!=null){
   // do something
   }

Greetings

    
answered by 08.06.2016 в 15:09
1

You are trying to access jArray.length() when jArray is null. One way to fix it could be by modifying the condition of the loop:

for (int i=0;jArray != null && i<jArray.length();i++){

You could also include all the code within the same try{}catch{} .

Greetings.

    
answered by 08.06.2016 в 09:43