IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Android Discussion :

Asynctask et JSONParsing depuis une URL : NullPointerException


Sujet :

Android

  1. #1
    Candidat au Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    Janvier 2015
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2015
    Messages : 7
    Points : 4
    Points
    4
    Par défaut Asynctask et JSONParsing depuis une URL : NullPointerException
    Bonsoir,

    J'ai récréé une appli simplifiée qui illustre le problème auquel je suis confronté sur ma véritable application. Son but final est de parser différents JSONObjects à des URL différents pour les afficher selon le JSONObject renvoyé.
    Elle contient :


    Un JSONParser on ne peut plus classique :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    public class JSONParser {
    static InputStream is = null;
    static JSONObject jObj = null;
    static String json = "";
    // constructor
    public JSONParser() {
    }
    public JSONObject getJSONFromUrl(String url) {
        // Making HTTP request
        try {
            // defaultHttpClient
            HttpParams params = new BasicHttpParams();
            params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
            HttpClient httpClient = new DefaultHttpClient(params);
            HttpPost httpPost = new HttpPost(url);
            HttpResponse httpResponse = httpClient.execute(httpPost);
            HttpEntity httpEntity = httpResponse.getEntity();
            is = httpEntity.getContent();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    is, "iso-8859-1"), 8);
            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
            is.close();
            json = sb.toString();
        } catch (Exception e) {
            Log.e("Buffer Error", "Error converting result " + e.toString());
        }

    Une classe MainActivity :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class MainActivity extends ActionBarActivity {
     
    private TextView tv;
    private static final String urllisteemplois = "l'url qui contient le json des emplois";
     
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.text);
        JParse jParse = new JParse(urllisteemplois);
        jParse.execute();
        String result = jParse.concat();
        tv.setText(result);
    }

    Et enfin une classe JParse qui extends AsyncTask :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    public class JParse extends AsyncTask<String, String, JSONObject> {
    private String url;
    private JSONObject json;
     
    public JParse(String url) {
        this.url=url;
    }
     
     
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }
     
    @Override
    protected JSONObject doInBackground(String... args) {
        JSONParser jParser = new JSONParser();
        JSONObject json2 = jParser.getJSONFromUrl(url);
        return json2;
    }
     
    @Override
    protected void onPostExecute(JSONObject json2) {
        this.json=json2;
    }
     
    public String concat()
    {
        String result = this.json.toString()+"hello";
        return result;
    }

    L'erreur est liée au fait que this.json est null dans la méthode concat() :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    01-20 03:18:43.797    2298-2298/com.badak.bdk.app E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.badak.bdk.ryadencule, PID: 2298
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.badak.bdk.app/com.badak.bdk.app.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String org.json.JSONObject.toString()' on a null object reference

    Je peux pour l'instant affirmer que :
    -le this.json dans le onPostExecute est bien à jour.
    -ayant fait le test avec des integer au lieu des JSON (et n'ayant pas parsé ces integer depuis une url), l'appli fonctionne.
    -je ne saurais pas dire pourquoi mais parfois le onPostExecute ne se lance pas de lui même et je dois le lancer manuellement.

    Autre problème qui n'a rien à voir, il m'arrive fréquemment de modifier des instructions dans mon code, et quand j'execute je me rends compte dans le logcat qu'elles n'ont pas été prises en compte. Une idée de comment régler ce problème (du coup ça m'empêche d'avancer dans mes tests en plus...). J'utilise android studio, dernière version, et je teste mes codes sur emulateur.


    Voilà, merci d'avance pour l'attention que vous porterez à ce problème qui me rend dingue depuis une semaine 8). Si vous avez des questions n'hésitez pas.

  2. #2
    Modérateur
    Avatar de Hizin
    Homme Profil pro
    Développeur mobile
    Inscrit en
    Février 2010
    Messages
    2 180
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Développeur mobile

    Informations forums :
    Inscription : Février 2010
    Messages : 2 180
    Points : 5 072
    Points
    5 072
    Par défaut
    C'est tout à fait normal que tu aies une NullPointerException (NPE).

    Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        JParse jParse = new JParse(urllisteemplois); // création de l'AsyncTask
        jParse.execute(); // lancement de l'AsyncTask, celle-ci réalise son travail dans un thread séparé, et n'est pas bloquante
        String result = jParse.concat(); // utilisation du résultat de l'AsyncTask alors qu'elle est en train de faire son boulot

    Utilise AsyncTask#onPostExecute(T) en le combinant avec un pattern Observer notifier la fin du parsing. Tu dois attendre la fin de celui-ci, et lui réagir.

    Citation Envoyé par badakzz
    Autre problème qui n'a rien à voir, il m'arrive fréquemment de modifier des instructions dans mon code, et quand j'execute je me rends compte dans le logcat qu'elles n'ont pas été prises en compte. Une idée de comment régler ce problème (du coup ça m'empêche d'avancer dans mes tests en plus...). J'utilise android studio, dernière version, et je teste mes codes sur emulateur.
    Je ne comprends pas vraiment. Dis-tu que AS ne sauvegarde pas tes modifications ? Si c'est le cas... ça me paraît étrange et n'ait jamais été confronté ni entendu parler de ce problème.
    C'est Android, PAS Androïd, ou Androïde didiou !
    Le premier est un OS, le second est la mauvaise orthographe du troisième, un mot français désignant un robot à forme humaine.

    Membre du comité contre la phrase "ça marche PAS" en titre et/ou explication de problème.

    N'oubliez pas de consulter les FAQ Android et les cours et tutoriels Android

  3. #3
    Candidat au Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    Janvier 2015
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2015
    Messages : 7
    Points : 4
    Points
    4
    Par défaut
    Merci pour la réponse !

    J'ai compris pourquoi je recevais une NullPointerException. En réalité j'avais déjà compris que mon thread ne se terminait pas, j'avais testé de rajouter un while(jParse.getStatus==Status.FINISHED) mais ça ne donnait rien (je sais pas si mon thread tournait à l'infini ou si mon traitement était incorrect, c'était dans un autre exemple et comme je t'ai précisé mon AS semble avoir du mal à enregistrer mes modifications).

    Cependant, j'ai regardé un peu comment s'utilisait le pattern Observer notifier, apparament il faudrait que ma classe JParse extends Observer pour pouvoir notifier mon observateur que serait MainActivity ? Le problème étant que JParse extends Asynctask.

    Peux-tu tu m'éclairer un peu sur la démarche à suivre ?


    Pour mon problème avec AS, je devrais peut être essayer de le réinstaller, parce qu'en général quand ce problème m'arrive j'ai pas d'autre choix que de recréer un projet android, et encore j'ai le droit qu'à une exécution, sinon les prochains changements ne seront pas pris en compte. Je vais me renseigner un peu.


    Merci d'avance

  4. #4
    Modérateur
    Avatar de Hizin
    Homme Profil pro
    Développeur mobile
    Inscrit en
    Février 2010
    Messages
    2 180
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Développeur mobile

    Informations forums :
    Inscription : Février 2010
    Messages : 2 180
    Points : 5 072
    Points
    5 072
    Par défaut
    Crée une interface ParsingListener qui possède une seule méthode parsingComplete.
    Modifie ton AsyncTask pour qu'elle prenne en paramètre de constructeur un objet ParsingListener.
    Met cet objet en attribut.
    Dans onPostExecute, invoque la méthode parsingComplete du listener.
    Fait implémenter cette nouvelle interface par ton activité.

    Fini
    C'est Android, PAS Androïd, ou Androïde didiou !
    Le premier est un OS, le second est la mauvaise orthographe du troisième, un mot français désignant un robot à forme humaine.

    Membre du comité contre la phrase "ça marche PAS" en titre et/ou explication de problème.

    N'oubliez pas de consulter les FAQ Android et les cours et tutoriels Android

  5. #5
    Candidat au Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    Janvier 2015
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2015
    Messages : 7
    Points : 4
    Points
    4
    Par défaut
    Rebonsoir,

    J'ai du mal m'y prendre puisque j'ai toujours une NullPointerException. Voici les modifications que j'ai apporté à mon appli :

    Classe MainActivity :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class MainActivity extends ActionBarActivity implements ParsingListener {
     
        private TextView tv;
        private static final String urllisteemplois = "http://www.myc2v.com/mobile/emplois.php";
        ParsingListener parsingListener;
        JParse jParse = new JParse(urllisteemplois, parsingListener);
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            tv = (TextView) findViewById(R.id.text);
            jParse.execute();
        }
     
        public void parsingComplete()
        {
            String result = jParse.concat();
            tv.setText(result);
        }
    }

    Classe JParse :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    public class JParse extends AsyncTask<String, String, JSONObject>
    {
        private String url;
        private JSONObject json;
        private ParsingListener parsingListener;
     
        public JParse(String url, ParsingListener parsingListener) {
            this.url=url;
            this.parsingListener=parsingListener;
        }
     
     
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }
     
        @Override
        protected JSONObject doInBackground(String... args) {
            Log.i(TAG, "doInBackground");
            JSONParser jParser = new JSONParser();
            JSONObject json2 = jParser.getJSONFromUrl(url);
            return json2;
        }
     
        @Override
        protected void onPostExecute(JSONObject json2) {
            this.json=json2;
            parsingListener.parsingComplete();
        }
     
        public String concat()
        {
            String result = this.json.toString()+"hello";
            return result;
        }
    }

    Interface ParsingListener :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    public interface ParsingListener {
     
        public void parsingComplete();
    }

    L'erreur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    01-20 22:10:32.453    2452-2452/com.badak.bdk.app E/AndroidRuntime﹕ FATAL EXCEPTION: main
        Process: com.badak.bdk.app, PID: 2452
        java.lang.NullPointerException: Attempt to invoke interface method 'void com.badak.bdk.app.ParsingListener.parsingComplete()' on a null object reference
                at com.badak.bdk.app.JParse.onPostExecute(JParse.java:44)
                at com.badak.bdk.app.JParse.onPostExecute(JParse.java:12)
                at android.os.AsyncTask.finish(AsyncTask.java:632)
                at android.os.AsyncTask.access$600(AsyncTask.java:177)
                at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
                at android.os.Handler.dispatchMessage(Handler.java:102)
                at android.os.Looper.loop(Looper.java:135)
                at android.app.ActivityThread.main(ActivityThread.java:5221)
                at java.lang.reflect.Method.invoke(Native Method)
                at java.lang.reflect.Method.invoke(Method.java:372)
                at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

    Désolé, je suis novice en matière de programmation, en réalité je n'ai débuté qu'en mai 2014. Veuillez pardonner mon ignorance Senpai !


    NB : j'aime pas spécialement le new JParse dans le MainActivity mais sans ça soit je le faisais dans mon onCreate auquel cas mon parsingComplete ne le connaissait pas, soit je faisais un new JParse dans chaque méthode ce qui ne me plaisait pas trop non plus.


    Encore merci pour ton aide !

  6. #6
    Modérateur
    Avatar de Hizin
    Homme Profil pro
    Développeur mobile
    Inscrit en
    Février 2010
    Messages
    2 180
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Développeur mobile

    Informations forums :
    Inscription : Février 2010
    Messages : 2 180
    Points : 5 072
    Points
    5 072
    Par défaut
    Normal

    Une classe s'initialise dans cette ordre :
    • création de la hiérarchie de la classe : de la plus générale (Object) à celle que tu souhaites créer
    • initialisation des attributs statique : attribut en avec le mot-clef static
    • initialisation des blocs de code statique : bloc de code de la forme static { ... } au même niveau de déclaration que les attributs & méthodes
    • initialisation des attributs : création des attributs et initialisation soit à la valeur par défaut (0, null...), soit à la valeur demandée
    • passage dans le constructeur : c'est ici que se fait le passage dans le constructeur, en passant par celui de chacune des classes-mères de la hiérarchie (remarque : super() est une ligne implicite dans chaque constructeur s'il n'y en a pas, ou qu'un this() est absent)
    • fin : classe créée


    Ton problème est que tu crée ton listener dans ton onCreate, donc après toute la création de la classe, mais que tu l'utilises durant l'initialisation des attributs.
    Modifie donc ton JParse jParse = new JParse(urllisteemplois, parsingListener); en JParse jParse; et initialise jParse dans ton onCreate.

    Remarque : selon les conventions Java, les constantes sont en MAJUSCULES_SEPAREES_PAR_DES_TIRETS_BAS
    C'est Android, PAS Androïd, ou Androïde didiou !
    Le premier est un OS, le second est la mauvaise orthographe du troisième, un mot français désignant un robot à forme humaine.

    Membre du comité contre la phrase "ça marche PAS" en titre et/ou explication de problème.

    N'oubliez pas de consulter les FAQ Android et les cours et tutoriels Android

  7. #7
    Candidat au Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    Janvier 2015
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2015
    Messages : 7
    Points : 4
    Points
    4
    Par défaut
    Je dois être stupide parce que j'ai toujours la même erreur...


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class MainActivity extends ActionBarActivity implements ParsingListener {
     
        private static final String URL_LISTE_EMPLOIS = "http://www.myc2v.com/mobile/emplois.php";
        private TextView tv;
        private JParse jParse;
        private ParsingListener parsingListener;
     
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            tv = (TextView) findViewById(R.id.text);
            jParse = new JParse(URL_LISTE_EMPLOIS, parsingListener);
            jParse.execute();
        }
     
        public void parsingComplete()
        {
            String result = jParse.concat();
            tv.setText(result);
        }
    }

    J'ai pas du bien comprendre tes explications. Le constructeur de MainActivity c'est onCreate ? Ou il s'agit d'un constructeur par défaut ?
    Un autre truc qui me tracasse : le logcat me dit que mon parseListener est null, ce qui est normal car je ne l'ai jamais initialisé ? J'avais cru comprendre qu'on on pouvait typer un objet avec une interface, mais pas l'initialiser...
    Y'a clairement quelque chose qui m'échappe.

  8. #8
    Modérateur
    Avatar de Hizin
    Homme Profil pro
    Développeur mobile
    Inscrit en
    Février 2010
    Messages
    2 180
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Développeur mobile

    Informations forums :
    Inscription : Février 2010
    Messages : 2 180
    Points : 5 072
    Points
    5 072
    Par défaut
    Passe lui "this" comme paramètre plutôt
    C'est ton activité elle-même l'observateur, dans ce cas-là.
    C'est Android, PAS Androïd, ou Androïde didiou !
    Le premier est un OS, le second est la mauvaise orthographe du troisième, un mot français désignant un robot à forme humaine.

    Membre du comité contre la phrase "ça marche PAS" en titre et/ou explication de problème.

    N'oubliez pas de consulter les FAQ Android et les cours et tutoriels Android

  9. #9
    Candidat au Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    Janvier 2015
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2015
    Messages : 7
    Points : 4
    Points
    4
    Par défaut
    Heyyyy, ça fonctionne !


    En revanche je ne suis pas certain d'avoir bien saisi la différence entre mettre mon attribut de classe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    private ParsingListener parsingListener;
    et ..?


    L'attribut de classe serait null, tandis que this représenterait l'objet issu de la classe MainActivity, mais typé avec l'interface ParsingListener ?



    En tout cas un grand merci pour ton aide ! Je vais tester cette méthode sur mon application principale à présent.


    EDIT : tout fonctionne ! merci encore pour ton aide !

  10. #10
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    private ParsingListener parsingListener;
    est juste un déclaration.

    Cette ligne dit: toute instance de "MainActivity" contient une référence appelée "parsingListener" vers une interface de type "ParsingListener".
    Par défault, si elle n'est pas *initialisée* cette référence est "nulle"

    Mais comme le dit Hizin, là en l'occurence, le "ParsingListener" on le connait déjà puisque c'est l'instance de la MainActivity.

    Hors pour avoir une référence sur sa propre instance, on utilise "this"... comme par exemple quand tu fais "this.json = ...." dans le JParser tu dis "affecte .... à la référence 'json' de *cette* instance de JParser".
    N'oubliez pas de cliquer sur mais aussi sur si un commentaire vous a été utile !
    Et surtout

Discussions similaires

  1. Récupérer depuis une url l'image via script
    Par Sayrus dans le forum Langage
    Réponses: 2
    Dernier message: 23/02/2007, 19h54
  2. Charger un fichier en mémoire depuis une URL
    Par ValyGator dans le forum C++
    Réponses: 11
    Dernier message: 12/01/2007, 16h16
  3. Enregistrer une image depuis une url
    Par joeyinbox dans le forum Windows
    Réponses: 2
    Dernier message: 23/10/2006, 20h00
  4. [FLASH 8] Charger dynamiquement des bmp depuis une url
    Par matN59 dans le forum Intégration
    Réponses: 1
    Dernier message: 24/04/2006, 15h24
  5. Recupération de données XML depuis une URL
    Par tonymo dans le forum Format d'échange (XML, JSON...)
    Réponses: 27
    Dernier message: 21/11/2005, 13h48

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo