Search code examples
androidsqliteandroid-volleyjsonobjectrequest

Requesting JSON with Volley


I'm trying to do an application that display some article stored in a SQLite database. I use a php function on my server to get a JSON file containing my database. In my Android app I want to get that JSON and put it in a JSONObject, I did the following :

private void initDataset() {
    mDataset = new ArrayList<>();
    Log.d("InitDataset", String.valueOf(mDataset.size()));
    getArticles();
    Log.d("InitDataset", String.valueOf(mDataset.size()));


}

public void getResponse(int method, String url, JSONObject jsonValue, final VolleyCallback callback) {
    StringRequest strreq = new StringRequest(method, url, new Response.Listener < String > () {

        @Override
        public void onResponse(String Response) {
            callback.onSuccessResponse(Response);
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError e) {
            e.printStackTrace();
            Toast.makeText(getContext(), e + "error", Toast.LENGTH_LONG).show();
        }
    });

    AppController.getInstance().addToRequestQueue(strreq);
}

public void getArticles() {
    getResponse(Request.Method.GET, AppConfig.URL_ARTICLE, null,
            new VolleyCallback() {
                @Override
                public void onSuccessResponse(String result) {
                    for (int i = 1; i < 3; i++) {
                        try {
                            Article article = new Article();

                            JSONObject response = new JSONObject(result);

                            // Now store the articles in SQLite
                            JSONObject articleObj = response.getJSONObject("article" + i);
                            article.setArticle_id(i);
                            article.setPicture_url(articleObj.getString("picture_url"));
                            article.setName(articleObj.getString("name"));
                            article.setDescription(articleObj.getString("description"));
                            article.setQuantity(Float.parseFloat(articleObj.getString("quantity")));
                            article.setPrice(Float.parseFloat(articleObj.getString("price")));
                            mDataset.add(article);

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

                    }
                }
            });
}

public interface VolleyCallback {
    void onSuccessResponse(String result);
}

But in the Log, the size of mDataset is always 0. Or if I Log for example the name of the article in onResponse() I can see every name is in the database. (thus the connection and php function are alright I think)

Any idea ?

Here is the php file :

<?php
require_once 'include/DB_Functions.php';
$db = new DB_Functions();

// JSON response array
$response = array("error" => FALSE);

$article = $db->getAllArticles();

if ($article != false) {
    // use is found
    $response["error"] = FALSE;

    while($row = $article->fetch_assoc()) {
        $response["article".$row["article_id"]]["article_id"] = $row["article_id"];
        $response["article".$row["article_id"]]["picture_url"] = $row["picture_url"];
        $response["article".$row["article_id"]]["name"] = $row["name"];
        $response["article".$row["article_id"]]["description"] = $row["description"];
        $response["article".$row["article_id"]]["quantity"] = $row["quantity"];
        $response["article".$row["article_id"]]["price"] = $row["price"];
    }
    echo json_encode($response);

    $fp = fopen('results.json', 'w');
    fwrite($fp, json_encode($response));
    fclose($fp);

} else {
    $response["error"] = TRUE;
    $response["error_msg"] = "Error";
    echo json_encode($response);
}
?>

And the JSON I get when executing the php :

{
  "error": false,
  "article1": {
    "article_id": "1",
    "picture_url": "https://static.webshopapp.com/shops/019852/files/024106649/600x600x2/brasserie-dachouffe-la-chouffe-33cl.jpg",
    "name": "Chouffe",
    "description": "Ceci est une description de la chouffe.",
    "quantity": "33",
    "price": "2.54"
  },
  "article2": {
    "article_id": "2",
    "picture_url": "https://www.latelierdesbieres.fr/1266-large_default/biere-belge-noel-n-ice-chouffe-33-cl.jpg",
    "name": "Chouffe de Noel",
    "description": "Ceci est une description de la chouffe de Noel.",
    "quantity": "33",
    "price": "3.23"
  }
}

Solution

  • You're misunderstanding some asynchronous execution ordering.

    You need to rewrite your method to wait for the returned results, not immediately log the list size twice without letting the network call finish

    getArticles(new VolleyCallback() {
        @Override
        public void onSuccessResponse(String result) {
            // parse result 
            // print list size <-- shouldn't be empty 
        } 
    });
    // your list will be empty here still
    

    Where the method is defined as

    public void getArticles(VolleyCallback  vcb) {
        getResponse(Request.Method.GET, AppConfig.URL_ARTICLE, null, vcb);
    }
    

    However, that seems really pointless to wrap two methods when you could just call getResponse directly with the correct parameters