Java 垃圾收集导致应用程序由于对象分配而跳过帧
我目前正在编写一个简单的应用程序,它执行API调用并在ListView中显示结果数据。我使用AsyncTask在一个单独的线程中从API下载JSON,然后将此JSON转换为许多产品对象,以便在ListView适配器中使用 然而,每当我执行此操作时,监视器中就会出现以下警告:Java 垃圾收集导致应用程序由于对象分配而跳过帧,java,android,json,multithreading,parsing,Java,Android,Json,Multithreading,Parsing,我目前正在编写一个简单的应用程序,它执行API调用并在ListView中显示结果数据。我使用AsyncTask在一个单独的线程中从API下载JSON,然后将此JSON转换为许多产品对象,以便在ListView适配器中使用 然而,每当我执行此操作时,监视器中就会出现以下警告: I/Choreographer: Skipped 405 frames! The application may be doing too much work on its main thread. 显然,这会导致UI在
I/Choreographer: Skipped 405 frames! The application may be doing too much work on its main thread.
显然,这会导致UI在几秒钟内没有响应,这并不理想。我发现这种延迟是由于分配给内存的对象太多而执行垃圾收集造成的。以下多次出现的信息使我相信这就是问题所在:
I/zygote: WaitForGcToComplete blocked for 49.752ms for cause ObjectsAllocated
我知道,从JSON>Java对象开始需要一些内存分配,但是我不会认为将235个对象分配到内存应该是一个太大的问题
我找错地方了吗?是否是我获取数据导致了速度减慢?或者我的模拟器没有正确分配内存
任何帮助都将不胜感激
编辑:
我发现了罪魁祸首,当我将JSON转换为Java对象时,似乎存在一个问题,即我创建的对象比我应该创建的要大得多。例如,每个产品都有一个或多个类别和属性。在解析JSON时,我监视其中有多少已被读取,以及有多少已被实际保存,并出现以下输出:
I/System.out: 2 categories in categories array for product Nieto Malbec, Mendoza
I/System.out: 2 attributes in attributes array for product Nieto Malbec, Mendoza
I/System.out: 9 categories being saved for product Nieto Malbec, Mendoza
I/System.out: 8 attributes being saved for product Nieto Malbec, Mendoza
随着产品列表的进一步深入,该误差幅度会持续恶化:
I/System.out: 1 categories in categories array for product: Clearspring Organic Rapeseed Oil
I/System.out: 1 attributes in attributes array for product Clearspring Organic Rapeseed Oil
I/System.out: 360 categories being saved for product Clearspring Organic Rapeseed Oil
I/System.out: 315 attributes being saved for product Clearspring Organic Rapeseed Oil
我假设我有某种失控的计数器,它不断为每个产品获取更多相同的类别和属性,但似乎无法跟踪它。我使用以下代码获取和解析JSON:
protected ArrayList<Product> doInBackground(Integer... params) {
int imageSize = params[0].intValue();
// TO-DO ensure no JSON read can result in a null pointer reference
// TO-DO change API call to adjust for screen size and JSOn transform to not use static size
String url = "https://api.gousto.co.uk/products/v2.0/products?includes[]=categories&includes[]=attributes&image_sizes[]=" + imageSize;
//Use JSONParser to download the JSON
JSONParser jsonParser = new JSONParser();
JSONObject jsonObject = jsonParser.makeHttpRequest(
url, "GET", new HashMap<String, String>());
// Initialise empty arrays to be populated
ArrayList<Product> productArrayList = new ArrayList<>();
ArrayList<Category> categoryArrayList = new ArrayList<>();
ArrayList<Attribute> attributeArrayList = new ArrayList<>();
try {
// Get JSON array representing all elements within the data array
JSONArray dataArray = jsonObject.getJSONArray("data");
System.out.println("There are " + dataArray.length() + " product objects in the data array");
// For each product
for (int x = 0; x < dataArray.length(); x++) {
// JSON object representing single product
JSONObject productitem = dataArray.getJSONObject(x);
// TO-DO initialise zero box limit to be used for null
int boxLimit = 0;
// Read the variables from each product
String id = productitem.getString("id");
String sku = productitem.getString("sku");
String title = productitem.getString("title");
String description = productitem.getString("description");
double listPrice = productitem.getDouble("list_price");
boolean isVatable = productitem.getBoolean("is_vatable");
boolean isForSale = productitem.getBoolean("is_for_sale");
boolean isAgeRestricted = productitem.getBoolean("age_restricted");
boolean alwaysOnMenu = productitem.getBoolean("always_on_menu");
// Check for null on box_limit
if (!productitem.isNull("box_limit")) {
boxLimit = productitem.getInt("box_limit");
}
// Get JSON array representing category(s)
JSONArray categoriesArray = productitem.getJSONArray("categories");
System.out.println(categoriesArray.length() + " categories in categories array for product: " + title);
// For each category in categoriesArray
for(int i = 0; i < categoriesArray.length(); i++) {
// JSON object representing each category
JSONObject categoryObject = categoriesArray.getJSONObject(i);
// TO-DO initialise zero box limit to be used for null
int categoryBoxLimit = 0;
// Read the variables from the category
String categoryId = categoryObject.getString("id");
String categoryTitle = categoryObject.getString("title");
boolean categoryIsDefault = categoryObject.getBoolean("is_default");
boolean categoryIsRecentlyAdded = categoryObject.getBoolean("recently_added");
boolean categoryIsHidden = categoryObject.getBoolean("hidden");
// Check for null on box_limit
if(!categoryObject.isNull("box_limit")) {
categoryBoxLimit = categoryObject.getInt("box_limit");
}
// Initialise new Category and add to the ArrayList
Category category = new Category(categoryId, categoryTitle, categoryBoxLimit, categoryIsDefault, categoryIsRecentlyAdded, categoryIsHidden);
categoryArrayList.add(category);
}
// JSON array representing attribute(s)
JSONArray attributesArray = productitem.getJSONArray("attributes");
System.out.println(attributesArray.length() + " attributes in attributes array for product " + title);
// For each attribute in attributesArray
for(int y = 0; y < attributesArray.length(); y++) {
// JSON object representing a single attribute
JSONObject attributeObject = attributesArray.getJSONObject(y);
// String for null value on unit
String attributeUnit = "N/A";
// Read variables for
String attributeId = attributeObject.getString("id");
String attributeTitle = attributeObject.getString("title");
String attributeValue = attributeObject.getString("value");
// Check for null on unit value
if (!attributeObject.isNull("unit")) {
attributeUnit = attributeObject.getString("unit");
}
// Initialise new Attribute and add to attributes array
Attribute attribute = new Attribute(attributeId, attributeTitle, attributeUnit, attributeValue);
attributeArrayList.add(attribute);
}
// JSON object representing images
JSONObject imagesObject = productitem.getJSONObject("images");
// TO-DO initialise empty product image
ProductImage productImage = null;
// TO-DO Check for null on 1080
if (!imagesObject.isNull("1080")) {
// JSON object representing single image
JSONObject imageObject = imagesObject.getJSONObject("1080");
// Read variables from image object
String imageSource = imageObject.getString("src");
String imageUrl = imageObject.getString("url");
int width = imageObject.getInt("width");
// ProductImage with variables
productImage = new ProductImage(imageSource, imageUrl, width);
} else {
// ProductImage without variables
// TO-DO set as null and perform check on read
productImage = new ProductImage("Broken", "Broken", 0);
}
System.out.println(categoryArrayList.size() + " categories being saved for product " + title);
System.out.println(attributeArrayList.size() + " attributes being saved for product " + title);
// Add new product to products array
productArrayList.add(new Product(id, sku, title, description, listPrice, isVatable, isForSale, isAgeRestricted, boxLimit, alwaysOnMenu, categoryArrayList, attributeArrayList, productImage));
}
} catch (JSONException e) {
System.out.println(e.toString());
}
return productArrayList;
}
受保护的ArrayList doInBackground(整数…参数){
int imageSize=params[0].intValue();
//确保JSON读取不会导致空指针引用
//TO-DO更改API调用以调整屏幕大小,并将JSOn转换为不使用静态大小
字符串url=”https://api.gousto.co.uk/products/v2.0/products?includes[]=类别和包括[]=属性和图像大小[]=“+图像大小;
//使用JSONParser下载JSON
JSONParser JSONParser=新的JSONParser();
JSONObject JSONObject=jsonParser.makeHttpRequest(
url,“GET”,新的HashMap();
//初始化要填充的空数组
ArrayList productArrayList=新的ArrayList();
ArrayList categoryArrayList=新的ArrayList();
ArrayList attributeArrayList=新建ArrayList();
试一试{
//获取表示数据数组中所有元素的JSON数组
JSONArray dataArray=jsonObject.getJSONArray(“数据”);
System.out.println(“数据数组中有“+dataArray.length()+”产品对象”);
//每种产品
对于(int x=0;x