2012-03-21 35 views
8

Tôi đang nhập dữ liệu JSON từ cơ sở dữ liệu công khai URI http://data.seattle.gov/api/views/3k2p-39jp/rows.json và các hàng đi xa tới 445454. Sử dụng mã sau đây Tôi đang xây dựng đối tượng JSON của toàn bộ dữ liệu.Java/Android: java.lang.OutOfMemoryError khi xây dựng một đối tượng JSON

HttpGet get = new HttpGet(uri); 
    HttpClient client = new DefaultHttpClient(); 
    HttpResponse response = client.execute(get); 
    BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8")); 
    StringBuilder builder=new StringBuilder(); 
for(String line=null;(line = reader.readLine()) != null;){ 
     builder.append(line).append("\n"); 
    } 
    JSONTokener jsonTokener=new JSONTokener(builder.toString()); 
    JSONObject finalJson=new JSONObject(jsonTokener); 
    JSONArray data=finalJson.getJSONArray("data"); 

Bởi vì dữ liệu quá lớn, tôi đang nhận 03-21 03:41:49.714: E/AndroidRuntime(666): Caused by: java.lang.OutOfMemoryError chỉ nguồn gốc của lỗi tại buildr.append(line).append("\n"). Có anyway tôi có thể xử lý các tập dữ liệu lớn mà không nhận được vấn đề phân bổ bộ nhớ?

+0

đọc các phần của nó thay vì toàn bộ nội dung ..? – JoxTraex

Trả lời

5

JSON đó rất lớn!

Bạn chắc chắn cần phải sử dụng trình phân tích cú pháp JSON trực tuyến. Có hai ứng dụng cho Android: GSON và Jackson.

GSON streaming được giải thích tại địa chỉ: https://sites.google.com/site/gson/streaming

Tôi thích cách GSON giải thích các vấn đề bạn đang gặp phải:

Hầu hết các ứng dụng chỉ nên sử dụng mô hình đối tượng API. Luồng JSON hữu ích chỉ trong một vài trường hợp:

Khi không thể hoặc không mong muốn tải toàn bộ mô hình đối tượng vào bộ nhớ. Điều này có liên quan nhất trên nền tảng di động nơi bộ nhớ bị hạn chế.

Jackson streaming là tài liệu tại địa chỉ: http://wiki.fasterxml.com/JacksonInFiveMinutes#Streaming_API_Example

+0

Tôi thích GSON. Vì vậy, bạn đang nói thay vì sử dụng 'BufferedReader' và' StringBuilder' tôi nên làm 'JSONReader' và' Danh sách 'để có một lợi thế hơn các vấn đề bộ nhớ? – jmishra

+0

Đúng. JSONReader sẽ lấy inputStream của bạn, do đó sẽ thay thế cả BufferedReader và StringBuilder trong mã của bạn. Lưu ý rằng Message là một lớp mẫu. Nhìn vào JSON đó, bạn có thể muốn thay thế bằng lớp PoliceResponse của riêng mình. Vì JSON không chỉ là một mảng lớn như trong các ví dụ, bạn sẽ phải điều hướng đến mảng chứa các phản hồi của cảnh sát trước, sau đó bạn có thể bắt đầu lặp qua mảng đó. – louielouie

1

Nếu chỉ có thể yêu cầu các phần của dữ liệu - điều này cũng làm giảm thời gian cho mạng io và do đó tiết kiệm pin.

Nếu không, bạn có thể cố gắng không giữ dữ liệu đến trong bộ nhớ, nhưng để 'truyền' dữ liệu vào thẻ sd. Khi nó được lưu trữ ở đó, bạn có thể lặp lại nó. Nhiều khả năng điều này có nghĩa là sử dụng trình mã hóa JSON của riêng bạn mà không xây dựng một cây đầy đủ, nhưng có thể (giống như trình phân tích cú pháp SAX) chỉ xem một phần của cây đối tượng tại một thời điểm.

Bạn có thể xem Jackson, có chế độ phát trực tuyến có thể áp dụng.

1

Truyền pull phân tích cú pháp là đường đi. Tôi khuyên bạn nên GSON, vì điều này có footpring bộ nhớ nhỏ (chỉ cần kéo phân tích là khoảng 16K, jackson là cách lớn hơn)

Mã của bạn là có vấn đề vì bạn phân bổ:

  • đệm để giữ tất cả các dữ liệu chuỗi đến từ dịch vụ
  • tất cả các đối tượng DOM của DOM

và điều này rất chậm và cho bạn suy thoái bộ nhớ.

Trong trường hợp bạn cần đối tượng java ra khỏi dữ liệu JSON của bạn, bạn có thể thử nhỏ xây dựng thư viện liên kết dữ liệu của tôi trên GSON (shameles tự quảng cáo off):

https://github.com/ko5tik/jsonserializer

0

tôi đã làm nó khác một chút, My Mã JSON đang chờ trạng thái, đến cuối cùng. Vì vậy, tôi đã sửa đổi mã để trả về trước đó.

// try to get formattedAddress without reading the entire JSON 
     String formattedAddress; 
     while ((read = in.read(buff)) != -1) { 
      jsonResults.append(buff, 0, read); 
      formattedAddress = ((String) ((JSONObject) new JSONObject(
        jsonResults.toString()).getJSONArray("results").get(0)) 
        .get("formatted_address")); 
      if (formattedAddress != null) { 
       Log.i("Taxeeta", "Saved memory, returned early from json") ; 
       return formattedAddress; 
      }    
     } 
JSONObject statusObj = new JSONObject(jsonResults.toString()); 
     String status = (String) (statusObj.optString("status")); 
     if (status.toLowerCase().equals("ok")) { 
      formattedAddress = ((String) ((JSONObject) new JSONObject(
        jsonResults.toString()).getJSONArray("results").get(0)) 
        .get("formatted_address")); 
      if (formattedAddress != null) { 
       Log.w("Taxeeta", "Did not saved memory, returned late from json") ; 
       return formattedAddress; 
      }   
     } 
Các vấn đề liên quan