【问题标题】:Loop AsyncTask class and fetch Json and store as object in list循环 AsyncTask 类并获取 Json 并作为对象存储在列表中
【发布时间】:2015-07-03 13:38:52
【问题描述】:

我想连接到一个 Api,它根据我作为 GET 请求输入的内容返回 JSON 值。此 JSON 结构始终完全相同,只是这些属性的值不同。然后将所有这些 JSON 值构造成一个对象列表,并从那里进一步在应用程序中使用用户。

在帮助下,我现在有了一个工作代码,可以连接并读取 JSONHttpEntity 的值,并将这些值存储在 new JSONObject 中。该对象被发送到另一个函数,在该函数中该对象被剥离,然后将constructed 转换为Object list 以供以后在应用程序中使用。

此代码工作。除了此 Api 链接仅显示 50 个结果,具体取决于输入为 GET 请求的内容。当结果超过 50 个时,将创建一个新页面,可以通过 url 末尾的数字访问该页面。所有这些可能存在的页面(不必作为用户搜索请求)也必须添加到对象列表中。

问题:如何使用新的 url 遍历扩展的 AsyncTask 类以从中获取 JSON 数据?

我再次注意到,此代码适用于单个页面,但我不知道如何遍历所有现有页面并将它们添加到同一个对象列表中。

我们从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);

从这里将 URL 传递给 AsyncFetch 类,以将 doInBackground 作为参数。

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);
    }


}

AsyncFetch 类中的onPostExecute 中,然后将对象发送回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);

        }

    }

现在我可以从这里访问resultClass 列表并遍历所有对象并显示它们的属性和值。

我怎样才能使这适用于具有完全相同 JSON 结构的多个页面?

编辑:我有这个在 c# 中工作的代码。这是我的完全相同的项目,但现在在 Android java 中。所以目标是完全一样的,但我不能让它工作

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;
        }

【问题讨论】:

  • 尝试将AsyncFetch.execute(URL);改为AsyncFetch.execute(URL+YourPageNumber);(例如:AsyncFetch.execute(URL+5);加载第5页)
  • @Rami 我需要自动循环浏览所有页面,而不是手动执行。

标签: java android json list object


【解决方案1】:

好吧,我认为这不是一个好主意,因为如果服务器数据量太大,你可以拥有OutOfMemoryError

否则,这是我加载所有数据的建议:

1) 创建两个类变量(在您的活动中),第一个用于页数,第二个用于您的计数器:

private static final int PAGES_NUMBER = 38; // i think last page  is 38 in your api
private int mPagesCounter = 0;

2) 添加一个 JSONObject 作为类变量(在您的活动中)以保存您的页面:

JSONObject mAllData = new JSONObject();

3) 将您的onPostExecute() 更改为仅在加载所有页面时调用onResponse()

    @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) 更改 onResponse() 方法以处理新的 json 格式。

要循环页面,您可以这样做:

    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();
        }
    }

【讨论】:

  • 我只是有时间尝试这个,我真的不知道这段代码中发生了什么。
  • 当你调用你的 AsyncTask 时,它不会直接调用 onResponse() 方法来传递数据,它会保存(当前页面的)结果并启动另一个任务来获取下一页...当您到达最后一页时,任务调用 onResponse() 方法将结果(所有页面)传递给您的界面。
【解决方案2】:

AsyncTask,顾名思义,是您尝试异步执行单个任务时的好工具。

您尝试做的似乎是ThreadPool 的工作,这是一个旨在使用一组工作线程(或执行程序)处理任务队列的工具。您可以让每个任务将下一个任务添加到队列中,或者一次将整个批次排队。

这是一个非常强大的模式。

官方example here(示例分为几页,导航在底部)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-01
    • 2023-01-02
    • 1970-01-01
    • 2012-01-11
    • 2022-01-26
    • 2017-09-20
    • 2023-03-03
    • 1970-01-01
    相关资源
    最近更新 更多