将多个HTTP请求的结果聚合到单个列表中

时间:2016-04-25 18:11:25

标签: java android

我正在解析几个Json链接,并尝试将所有输出添加到一个List。但是,列表总是被覆盖,而只包括其中一个链接的结果:

public class GetShopifyJsonData extends GetRawData {
    private String LOG_TAG = GetShopifyJsonData.class.getSimpleName();
    private List<Product> mProduct;
    private Uri mDestination;

    public GetShopifyJsonData(int page) {
        super(null);
        createUri(page);
        mProduct = new ArrayList<Product>();
    }

    public void execute(){
        super.setRawUrl(mDestination.toString());
        DownloadShopifyData downloadShopifyData = new DownloadShopifyData();
        Log.v(LOG_TAG, "Built URI = " + mDestination.toString());
        downloadShopifyData.execute(mDestination.toString());
    }

    public boolean createUri(int page) {
        final String SHOPIFY_BASE_URL = "";
        final String SHOPIFY_PAGE_PARAM = "page";

        mDestination = Uri.parse(SHOPIFY_BASE_URL).buildUpon()
                .appendQueryParameter(SHOPIFY_PAGE_PARAM, String.valueOf(page)).build();

        return mDestination != null;
    }

    public void processResults() {

        if(getDownloadStatus() != DownloadStatus.OK){
            Log.e(LOG_TAG, "Error Downloading Raw Data");
            return;
        }

        final String SH_PRODUCTS = "products";
        final String SH_TYPE = "product_type";
        final String SH_VARIANTS = "variants";
        final String SH_TITLE = "title";
        final String SH_PRICE = "price";
        final String SH_GRAMS = "grams";

        try {
            JSONObject jsonData = new JSONObject(getData());
            JSONArray productsArray = jsonData.getJSONArray(SH_PRODUCTS);
            for (int i=0; i<productsArray.length(); i++ ) {
                JSONObject jsonProduct = productsArray.getJSONObject(i);
                String productType =jsonProduct.getString(SH_TYPE);
                String title = jsonProduct.getString(SH_TITLE);

                JSONArray variantsArray = jsonProduct.getJSONArray(SH_VARIANTS);
                JSONObject variantProduct = variantsArray.getJSONObject(0);
                String variantTitle = variantProduct.getString(SH_TITLE);
                double price = variantProduct.getDouble(SH_PRICE);
                int grams = variantProduct.getInt(SH_GRAMS);

                if (productType.equals("Keyboard") || productType.equals("Computer")) {
                    Product productObject = new Product(title, price, grams, productType, variantTitle);
                    this.mProduct.add(productObject);
                }
            }

            for(Product singleProduct : mProduct){
                Log.v(LOG_TAG, singleProduct.toString());
                Log.v(LOG_TAG, String.valueOf(mProduct.size()));
            }
        } catch (JSONException jsone) {

            jsone.printStackTrace();
            Log.e(LOG_TAG, "Error Processing JSON data");
        }
    }
}

来自MainActivity的电话:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    for (int i=1; i<6; i++) {
        GetShopifyJsonData jsonData = new GetShopifyJsonData(i);
        jsonData.execute();
    }
}

我需要更改什么才能让产品在一个列表中相互添加?

2 个答案:

答案 0 :(得分:6)

每次遍历此循环时,您都会覆盖jsonData,而不会将每个先前循环的结果存储在其他位置。

for (int i=1; i<6; i++) {
    GetShopifyJsonData jsonData = new GetShopifyJsonData(i); // throws out results of previous iteration and creates a new List each time
    jsonData.execute();
}

你应该在这个循环之外保留一个List,你可以在每次迭代后添加所有结果:

ArrayList<Product> allProducts = new ArrayList<Product>();
for (int i=1; i<6; i++) {
    GetShopifyJsonData jsonData = new GetShopifyJsonData(i);
    jsonData.execute();
    allProducts.addAll(jsonData.getProducts()) // add a method that gets all of the products from each iteration
}

修改

由于您使用线程来收集JSON数据,因此可以使用GetShopifyJsonData对象列表来维护对这些线程的引用;

ArrayList<GetShopifyJsonData> allJSONData = new ArrayList<GetShopifyJsonData>();
for (int i=1; i<6; i++) {
    allJSONData.add(new GetShopifyJsonData(i));
    allJSONData.get(i).execute(); // executes each task as discrete instances
}

从那里,您可以检查线程的状态,并在完成时从列表中检索JSON数据。以下是一个不太好的例子,为了说明起见:

ArrayList<Product> allProducts = new ArrayList<Product>();
for (int i=1; i<6; i++) {
    while(!allJSONData.get(i).isComplete()){ // add a method that checks if a task has been completed
        //this is a busy wait, don't do this!
    }
    allProducts.addAll(jsonData.get(i).getProducts()) // add a method that gets all of the products from each iteration
}

现在,我不是专家,但快速浏览AsyncTask的文档会告诉我onPostExecute(Result)getStatus()可能会有用。如果我是正确的,我希望您实际上可以将JSON数据添加到onPostExecute()内的列表中,并通过将主列表传递到ArrayList<GetShopifyJsonData>来完全跳过execute();类似的东西:

ArrayList<Product> allProducts = new ArrayList<Product>();
for (int i=1; i<6; i++) {
    GetShopifyJsonData jsonData = new GetShopifyJsonData(i);
    jsonData.execute(allProducts); // pass the reference to your list in execute()
}

// in your AsyncTask class:
private ArrayList<Product> products; // private List instance

execute(ArrayList<Product> allProducts){
    products = allProducts;
    // do other logic
    ...
}

onPostExecute(List<Product> dataFromJSON){
    products.addAll(dataFromJSON); // add the results to the instance variable, which also updates the master list
}

但这是过于简单化了。您必须确保线程不会同时尝试添加到列表中,因为如果允许它们可能会发生错误的事情。文档说明onPostExecute()在UI线程上运行,但我不知道这意味着什么。

答案 1 :(得分:2)

每个GetShopifyJsonData都有自己的List<Product>,您需要通过单个GetShopifyJsonData实例请求所有产品或将MainActivity汇总为请求完成。这种方法实现了后者。

GetShopifyJsonData添加一个回调接口,并要求它的实例作为构造函数中的参数。我只在下面的代码中包含了更改。其他一切都是一样的。

public class GetShopifyJsonData extends GetRawData {
    public interface OnResultsReadyListener {
        void onResultsReady(List<Product> products);
    }

    private OnResultsReadyListener mResultsListener;

    public GetShopifyJsonData(int page, OnResultsReadyListener resultsListener) {
        super(null);
        createUri(page);
        mProduct = new ArrayList<Product>();
        mResultsListener = resultsListener;
    }

    public void processResults() {
        // Add this to the end of the method
        if(mResultsListener != null) {
            mResultsListener.onResultsReady(mProduct);
        }
    }
}

然后更新MainActivity以实现此新界面,并在请求完成时将结果添加到其列表中。

public class MainActivity extends Activity
        implements GetShopifyJsonData.OnResultsReadyListener {
    private List<Product> allproducts;

    @Override
    void onResultsReady(List<Product> products) {
        // allProducts contains products for all requests that have completed so far
        allProducts.addAll(products);
        Log.v(LOG_TAG, allProducts.size() + " total products downloaded.");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        allProducts = new ArrayList<>();

        for (int i=1; i<6; i++) {
            GetShopifyJsonData jsonData = new GetShopifyJsonData(i, this);
            jsonData.execute();
        }
    }
}