Comment faire un tableau quand le fichier JSON n'en a pas et seulement des objets

J'essaye de faire une application qui obtient des données d'URL sur Android. J'ai remarqué que les fichiers JSON sont différents. Certains d'entre eux commencent par un nom d'arrach et d'autres non. Ceux qui ont le nom de tableau comme ceci dont "user" est le nom du tableau fonctionne dans mon application mais ceux qui n'ont pas de nom de tableau ne fonctionnent pas. Par exemple ceci .

C'est le code que j'essaie de créer un objet mais il ne fonctionne pas pour le second fichier JSON car il ne trouve pas le nom du tableau:

//URL to get JSON Array
private static String url = "http://api.worldbank.org/countries/ir?format=json";

//JSON Node Names 
private static final String TAG_USER = "user";
private static final String TAG_ID = "id";
private static final String TAG_NAME = "name";
private static final String TAG_EMAIL = "email";

JSONArray user = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

   //Creating new JSON Parser
    JSONParser jParser = new JSONParser();

   //Getting JSON from URL
    JSONObject json = jParser.getJSONFromUrl(url);

    try {
       //Getting JSON Array
        user = json.getJSONArray(TAG_USER);
        JSONObject c = user.getJSONObject(0);

       //Storing  JSON item in a Variable
        String id = c.getString(TAG_ID);
        String name = c.getString(TAG_NAME);
        String email = c.getString(TAG_EMAIL);

        //Importing TextView
        final TextView uid = (TextView)findViewById(R.id.uid);
        final TextView name1 = (TextView)findViewById(R.id.name);
        final TextView email1 = (TextView)findViewById(R.id.email);

        //Set JSON Data in TextView
        uid.setText(id);
        name1.setText(name);
        email1.setText(email);

} catch (JSONException e) {
    e.printStackTrace();
}

}

Donc cet exemple est pour la première partie JSON. Pouvez-vous me dire comment avoir un code similaire, mais pour le deuxième fichier JSON s'il vous plaît?

0
@Octoshape Juste n'importe quoi. Je veux seulement apprendre à traiter ce genre de fichiers qui ont des tableaux et non un objet. J'obtiendrais des données comme, id, nom, région, iso2Code
ajouté l'auteur user2977338, source
Comme cette question est plus sur AsyncTask et pas le problème de tableau de cette application. Je vais créer un nouveau post spécifiquement pour le problème de tableau.
ajouté l'auteur user2977338, source
@Otoshape Merci pour votre aide. J'ai essayé votre solution n'a pas fonctionné malheureusement. Ce serait génial si vous fournissez un exemple de code pour AsyncTask car je n'ai aucune idée à ce sujet. Un aussi pourquoi learn2crack ne l'a pas utilisé asyncTask?! Ce qu'il a utilisé est une manière différente? ou parce que le fichier json est petit?!
ajouté l'auteur user2977338, source
@Octoshape Oui, j'utilise la bibliothèque learn2crack. Mais j'ai remarqué que la plupart des JSONParser ont le même code pour HTTP.
ajouté l'auteur user2977338, source
@Octoshape oui c'est le catlog: FATAL EXCEPTION: main java.lang.RuntimeException: Impossible de démarrer l'activité ComponentInfo {com.example.worldbank/com.example.worldbank.Ma & zwnj; inActivity}: android.os.NetworkOnMainThreadException Mais je crois que le problème est tout à propos de la façon dont je fais des tableaux et des objets.
ajouté l'auteur user2977338, source
@ user2977338 Je vais vous expliquer l'AsyncTask plus en détail dans ma réponse, il n'y a rien dans le code de learn2crack qui soit faux. Je vais l'expliquer.
ajouté l'auteur Octoshape, source
Quelles informations du deuxième fichier vous intéressent?
ajouté l'auteur Octoshape, source
Alors as-tu fait tourner AsyncTask maintenant? Serait heureux si vous pouviez sélectionner une réponse :)
ajouté l'auteur Octoshape, source
Utilisez-vous la bibliothèque learn2crack pour JSONParser ou l'avez-vous écrite vous-même?
ajouté l'auteur Octoshape, source
@ user2977338 J'ai mis à jour ma réponse, jetez un oeil à la section entre Modifier et [/ EDIT].
ajouté l'auteur Octoshape, source
Ah je vois .. oui vous devez utiliser AsyncTasks, mais l'analyseur ne peut pas non plus analyser JSONArrays .. Je vais inclure une solution aux deux problèmes dans ma réponse ci-dessous.
ajouté l'auteur Octoshape, source
Ok .. Je vais jeter un oeil à leur analyseur. Avez-vous des exceptions lorsque vous essayez l'URL pour le second fichier?
ajouté l'auteur Octoshape, source
@ user2977338 Si vous avez besoin d'un exemple de code pour vous aider à démarrer sur AsyncTask, laissez-moi savoir que je peux en ajouter quelques-unes à ma réponse ci-dessous.
ajouté l'auteur Octoshape, source
@ user2977338 vous pouvez utiliser Octoshape ou ma solution. Les deux solutions ont leur propre unicité :)
ajouté l'auteur saiful103a, source
@ user2977338 vous devez utiliser thread/asynctask lorsque vous effectuez une opération réseau comme Octoshape suggéré.
ajouté l'auteur saiful103a, source

2 Réponses

Donc tout d'abord, vous n'êtes pas autorisé à faire des choses réseau sur le thread principal car ces choses ont tendance à durer longtemps (si le serveur ne répond pas ou si la connexion est mauvaise ou le fichier que vous essayez d'extraire) sur le thread principal, il va bloquer l'application sur le téléphone. Si votre application ne réagit pas trop longtemps, elle sera automatiquement supprimée du système d'exploitation Android. Afin d'éviter de telles choses, vous devez utiliser AsyncTasks. Ce sont des tâches qui peuvent fonctionner en arrière-plan pendant que votre thread principal réagit toujours aux entrées de l'utilisateur.

Vous pouvez en savoir plus sur AsyncTasks ici .

[MODIFIER] Donc, en répondant à votre commentaire sur votre question: La raison pour laquelle vous obtenez un NetworkOnMainThreadException est parce que vous appelez jParser.getJSONFromUrl (url); dans votre thread principal (celui où vous exécuter du code normalement). La raison pour laquelle cela n'est pas autorisé est que dans la méthode getJSONFromUrl() vous faites une requête HTTP et vous devez attendre une réponse de l'URL donnée. Cela peut prendre beaucoup de temps comme je l'ai expliqué ci-dessus et bloquerait votre application au téléphone avec les conséquences déjà expliquées. Maintenant, pour résoudre ce problème, vous devez faire quelque chose comme ceci:

Avant (mauvais):

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

// Creating new JSON Parser
JSONParser jParser = new JSONParser();

// Getting JSON from URL
JSONObject json = jParser.getJSONFromUrl(url);

// get the data from your JSONObject

}

Mieux:

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

// Getting JSON from URL
new JsonRequest().execute(url);

}

private class JsonRequest extends AsyncTask
// I will talk about the parameters to AsyncTask below
    @Override
    protected JSONObject doInBackground(String... urls) {
       //Creating new JSON Parser
        JSONParser jParser = new JSONParser();

       //Getting JSON from URL
        JSONObject json = jParser.getJSONFromUrl(url);

        return json;
    }


    @Override
    protected void onPostExecute(JSONObject result) {

       //Get the array
        JSONArray array = result.getJSONArray("data");

       //Display the data
       //Import textviews
       //and so on..
    }

Maintenant à propos des paramètres de AsyncTask :

  1. This type is the type of the parameters given to doInBackground
  2. This type is used for showing a progress bar for example if you download many things you can override a function called onProgressUpdate and could show how many things already have been downloaded on your app so the user knows that something is happening.
  3. This type is the type that doInBackground will return and that onPostExecute has as a parameter.

De cette façon, votre thread principal continuera de fonctionner et l'utilisateur ne remarquera pas ce qui se passe en arrière-plan car il s'agit d'une tâche séparée qui s'exécute. J'espère que cela sera très clair si ce n'est pas le cas, laisse juste un autre commentaire et je t'expliquerai plus. :)

[\MODIFIER]

Ensuite, le deuxième problème est que le JSONParser de learn2crack ne peut pas analyser JSONArrays, en d'autres termes la fonction getJSONFromUrl() essaie simplement de créer un nouveau JSONObject provenant du String provient de l'URL donnée.

Il ya plusieurs façons de résoudre ce problème, j'ai fait un peu de piratage (il n'invoque que peu de code mais vous aurez besoin de plus de temps pour accéder aux données par la suite). J'ai ajouté les lignes suivantes dans la méthode getJSONFromUrl() :

if (json.startsWith("[")) {
   //We have a JSONArray
    try {
        jObj = new JSONObject();
        jObj.put("data", new JSONArray(json));
    } catch (JSONException e) {
        Log.d("JSON Parser", "Error parsing JSONArray " + e.toString());
    }
    return jObj;
}

Ces lignes doivent être ajoutées juste au-dessus de cette partie:

// try parse the string to a JSON object
try {
    jObj = new JSONObject(json);
} catch (JSONException e) {
    Log.e("JSON Parser", "Error parsing data " + e.toString());
}

Fondamentalement, ce que vous finirez avec, c'est que vous pouvez simplement appeler getJSONFromUrl() sur n'importe quelle URL, et si elle contient un JSONObject , contient un JSONArray vous obtiendrez un JSONObject avec un seul champ appelé data </​​code> qui contiendra votre JSONArray . Donc, vous pouvez faire quelque chose comme ça:

JSONObject json = jParser.getJSONFromUrl(url);

JSONArray array = json.getJSONArray("data");

Et puis vous avez votre tableau (bien sûr entouré d'une tentative d'essai pour JSONException ).

2
ajouté
Merci de votre aide. Vraiment utile et fait fonctionner mon application
ajouté l'auteur user2977338, source
Merci pour votre message. Juste une question. J'ai ajouté le if-statement et essayez {jObj .... dans la méthode getJSONFromUrl . mais il est arrivé avec une erreur comme json et jObj ne sont pas définis et déclarés. Pourquoi donc ?
ajouté l'auteur user2977338, source
@ user2977338 Pouvez-vous me poster votre code de méthode complet getJSONFromUrl dans votre question ci-dessus?
ajouté l'auteur Octoshape, source
J'ai aussi aimé votre solution. Je pensais plus en termes d'interface, donc je peux retourner un objet à la place de deux objets de getJSONFromUrl. Votre est plus court :)
ajouté l'auteur saiful103a, source

Autant que je sache, il n'y a pas de façon spécifique de dire si vous obtenez un objet json array ou json après l'avoir analysé.

La façon dont je résoudrais ceci, est de chercher le caractère de départ des données de chaîne à partir de la réponse.

Dans votre méthode getJSONFromUrl, vous obtenez la chaîne de réponse, puis vous commencez à l'analyser dans un JsonObject. Avant d'analyser, recherchez le caractère de départ en fonction du caractère de départ, décidez si vous souhaitez utiliser JsonObject ou JsonArray.

Je ne suis pas sûr si leur est un moyen plus court pour résoudre ce problème, mais votre problème est un problème :) Beaucoup d'autres choses doivent être traitées puisque vous ne savez pas à l'avance si vous allez obtenir jsonobject ou jsonarray.

Voici ce que j'ai mis ensemble:

public interface JsonListener {

     public boolean isJsonObejct();

}

Créez une classe en étendant JSONObject et en implémentant l'interface ci-dessus.

import org.json.JSONException;
import org.json.JSONObject;

public class CustomJSONObject extends JSONObject implements JsonListener {

public CustomJSONObject(String json) throws JSONException {
   //TODO Auto-generated constructor stub
    super(json);
}

@Override
public boolean isJsonObejct() {
   //TODO Auto-generated method stub
    return true;
}

 }

Créez une autre classe en étendant JSONArray et en implémentant l'interface ci-dessus.

import org.json.JSONArray;
import org.json.JSONException;

public class CustomJSONArray extends JSONArray implements JsonListener{

public CustomJSONArray(String json) throws JSONException {
   //TODO Auto-generated constructor stub
    super(json);
}

@Override
public boolean isJsonObejct() {
   //TODO Auto-generated method stub
    return false;
}

 }

Modifiez vous jsonparseclass afin qu'il ne retourne pas jsonobject ou jsonarray à la place il retournera Object du type JsonListener.

public class JSONParser {

static InputStream is = null;
static JsonListener jObj = null;
static String json = "";

// constructor
public JSONParser() {

}

public JsonListener getJSONFromUrl(String url) {

   //Making HTTP request
    try {
       //defaultHttpClient
        DefaultHttpClient httpClient = new DefaultHttpClient();
        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());
    }

   //try parse the string to a JSON object
    try {
        if(json.startsWith("{")){
            jObj = new CustomJSONObject(json);
        }else{
            jObj = new CustomJSONArray(json);
        }

    } catch (JSONException e) {
        Log.e("JSON Parser", "Error parsing data " + e.toString());
    }

   //return JSON String
    return jObj;

}
 }

Maintenant, ajustez votre code pour utiliser ceux-ci:

// Creating new JSON Parser
            JSONParser jParser = new JSONParser();

           //Getting JSON from URL
            JsonListener json = jParser.getJSONFromUrl(url);
            if(json.isJsonObejct()){
                Log.i("Got","JsonObject "+((CustomJSONObject)json).toString());
            }else{
                Log.i("Got","JsonArray "+((CustomJSONArray)json).toString());
            }   

J'espère que vous aurez un aperçu de cela.

2
ajouté
Merci pour votre message. Mais cela n'a pas fonctionné. Juste quelques questions pour m'assurer que je l'ai fait correctement. Où dois-je ajouter mon JSONListener? Je l'ajoute à la fin de Main_Activity. et dois-je également supprimer cette ligne? value = json.getJSONArray (VALUE);
ajouté l'auteur user2977338, source
@ saiful103a merci pour la publicité: D je préfère toujours votre solution sur la mienne à cause de la généricité en retournant un JsonListener ...
ajouté l'auteur Octoshape, source
Bonne utilisation des interfaces. Comme l'idée!
ajouté l'auteur Octoshape, source
JSONListener sera un fichier séparé. Et pour obtenir des données de json, vous devez utiliser ((CustomJSONObject) json) .get [Type de données dont vous avez besoin] ou ((CustomJSONArray) json) .get [Type de données dont vous avez besoin]. Vous trouverez tous les getters dans la documentation. Je pense que c'est mieux si vous utilisez la solution @Octoshape parce que c'est beaucoup plus léger que le mien en termes de code que vous avez à écrire. Mais pour savoir comment vous pourriez profiter de l'interface dans cette situation, vous pouvez utiliser celui-ci. :)
ajouté l'auteur saiful103a, source