我正在解析几个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();
}
}
我需要更改什么才能让产品在一个列表中相互添加?
答案 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();
}
}
}