Loop AsyncTask class and select Json and save as object in list
I want to connect to an Api that returns me JSON values depending on what I entered as a GET request. This JSON structure is always exactly the same, only the values from these properties are different. All of these JSON values are then built into a list of objects and from there the users in the application will be added.
With help I now have working code that concatenates and reads the values JSON
from HttpEntity
and stores them in new JSONObject
. This object is sent to another function, where the object is split, and then constructed
to Object list
for later use in the application.
This code works . Except that this Api link only shows 50 results, depending on what was entered as the query GET
. If there are more than 50 results, a new page is created that can be accessed by the number at the end of the URL. All of these pages that might exist (not necessarily as his search query) must also be added to the list of objects.
Question . How do I go through an extended class AsyncTask
with a new url to fetch JSON data from?
I note again that this code works for one page, but I cannot figure out how to iterate over all existing pages and add them to the same list of objects.
Let's start with Activity.java
String userSearchRequest = search_activity_data.getString("userSearchRequest");
String URL = "http://www.gw2spidy.com/api/v0.9/json/item-search/" + userSearchRequest + "/";
// example api url:
//http://www.gw2spidy.com/api/v0.9/json/item-search/Iron/0"
//The last number is the page you are viewing, every 50 results a new page is created. With 51 results there will be a page 0 and 1 to access.
AsyncFetch AsyncFetch = new AsyncFetch(this);
AsyncFetch.setOnResponse(this);
AsyncFetch.execute(URL);
Here, the URL is passed to the AsyncFetch class for the function doInBackground
as parameters.
public class AsyncFetch extends AsyncTask<String, Void, JSONObject> {
public AsyncFetch(Context context) {
this.context = context;
}
private Context context;
private JSONObject jsonObject;
private onResponse onResponse;
public void setOnResponse (onResponse onResponse) {
this.onResponse = onResponse;
}
@Override
protected JSONObject doInBackground(String... params ) { //Incompatible return type
// TODO Auto-generated method stub
try {
HttpGet get = new HttpGet(params[0]);
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(get);
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity);
jsonObject = new JSONObject(result);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return jsonObject;
}
@Override
protected void onPostExecute(JSONObject result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
this.onResponse.onResponse(result);
}
public interface onResponse {
public void onResponse(JSONObject object);
}
}
In onPostExecute
in class, the AsyncFetch
object is then sent back to activity.java
public void onResponse(JSONObject object) {
Log.i("gw2Log", object.toString());
apiRootObject resultClass = new apiRootObject();
try {
resultClass.setCount(object.getInt("count"));
resultClass.setPage(object.getInt("page"));
resultClass.setLast_page(object.getInt("last_page"));
resultClass.setTotal(object.getInt("total"));
JSONArray list = new JSONArray(object.getString("results"));
for (int i = 0; i < resultClass.getCount(); i++) {
JSONObject resultsObject = list.getJSONObject(i);
apiResults temp = new apiResults();
temp.setData_id(resultsObject
.getInt("data_id"));
temp.setName(resultsObject
.getString("name"));
temp.setRarity(resultsObject
.getInt("rarity"));
temp.setRestriction_level(resultsObject
.getInt("restriction_level"));
temp.setImg(resultsObject
.getString("img"));
temp.setType_id(resultsObject
.getInt("type_id"));
temp.setSub_type_id(resultsObject
.getInt("sub_type_id"));
temp.setPrice_last_changed(resultsObject
.getString("price_last_changed"));
temp.setMax_offer_unit_price(resultsObject
.getInt("max_offer_unit_price"));
temp.setMin_sale_unit_price(resultsObject
.getInt("min_sale_unit_price"));
temp.setOffer_availability(resultsObject
.getInt("offer_availability"));
temp.setSale_availability(resultsObject
.getInt("sale_availability"));
temp.setSale_price_change_last_hour(resultsObject
.getInt("sale_price_change_last_hour"));
temp.setOffer_price_change_last_hour(resultsObject
.getInt("offer_price_change_last_hour"));
resultClass.addObject(temp);
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for(int i = 0; i < resultClass.count; i++) {
Log.i("gw2Log", resultClass.getObject(i).name);
}
}
Now I can access the list resultClass
and loop through all objects and display their properties and values.
How can I make this work for multiple pages with the same JSON structure?
EDIT: I have this code that works in C #. This is the same project, but now in Android java. So the goal is exactly the same, but I cannot get it to work
public static RootObject objFromApi_idToName(string spidyApiUrl, int page){
RootObject rootObject = null;
RootObject tempRootObject = null;
do{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(spidyApiUrl + "/" + page);
WebResponse response = request.GetResponse();
using (Stream responseStream = response.GetResponseStream()){
StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);
var jsonReader = new JsonTextReader(reader);
var serializer = new JsonSerializer();
tempRootObject = serializer.Deserialize<RootObject>(jsonReader);
if (rootObject == null){
rootObject = tempRootObject;
}
else{
rootObject.results.AddRange(tempRootObject.results);
rootObject.count += tempRootObject.count;
}
}
page++;
}
while (tempRootObject != null && tempRootObject.last_page != tempRootObject.page);
return rootObject;
}
source to share
Well, I don't think it's a good idea what you are trying to do, because you might have OutOfMemoryError
if the amount of server data is too large.
Otherwise, this is my suggestion to load all data:
1) Make two class variables (in your activity), first for the number of pages and the second for your counter:
private static final int PAGES_NUMBER = 38; // i think last page is 38 in your api
private int mPagesCounter = 0;
2) Add JSONObject as a class variable (in your activity) to save your pages:
JSONObject mAllData = new JSONObject();
3) Change yours onPostExecute()
to call onResponse()
only when all pages are loaded:
@Override
protected void onPostExecute(JSONObject result) {
super.onPostExecute(result);
mAllData.put("page"+mPagesCounter, result);// save your current page with "pageX" as key
mPagesCounter++;
if(mPagesCounter <= PAGES_NUMBER){// create another task to load next page
AsyncFetch AsyncFetch = new AsyncFetch(YourActivity.this);
AsyncFetch.setOnResponse(YourActivity.this);
AsyncFetch.execute(URL+mPagesCounter);
} else {// all pages are loaded -> call onResponse() method
this.onResponse.onResponse(mAllData);
}
}
4) Change the method onResponse()
to handle the new json format.
To create loopback pages, you can do it like this:
Iterator it = object.keys();
while (it.hasNext()) {
String key = (String)it.next();
try {
JSONObject jsonPage = object.get(key);// here you get your page
// do the rest of stuff with the page
} catch (JSONException e) {
e.printStackTrace();
}
}
source to share
AsyncTask
, as the name suggests, is a good tool when you are trying to complete a single task asynchronously.
What you are trying to do seems to be Job For ThreadPool
, which is a tool designed to process a job queue using a given number of worker threads (or executors). You can do each task by adding the next task to the queue, or queue the entire batch right away.
This is a very powerful template.
The official example is here (the example is split into several pages, navigation is at the bottom).
source to share