2017-05-05 72 views
1

我使用谷歌API GSON解析爲我的Android項目一個JSON文件,但我的表現的問題。解析JSON在Android的飛行

這裏是源代碼我用來與谷歌GSON API解析JSON:

public void loadJsonInDb(String path){ 
    InputStream isJson = context.getAssets().open(path); 
    if (isJson != null) { 
     int sizeJson = isJson.available(); 
     byte[] bufferJson = new byte[sizeJson]; 
     isJson.read(bufferJson); 
     isJson.close(); 
     String jsonStr = new String(bufferJson, "UTF-8"); 

     JsonParser parser = new JsonParser(); 
     JsonObject object = parser.parse(jsonStr).getAsJsonObject(); 
     JsonArray array = object.getAsJsonArray("datas"); 

     Gson gson = new Gson(); 
     for(JsonElement jsonElement : array){ 
      MyEntity entity = gson.fromJson(jsonElement, MyEntity.class); 
      // Do insert into Db stuffs 
     } 
    } 
} 

這樣做的問題是,解析後,我必須去通過JsonArray一個for循環並執行所需的動作(這是SQLite數據庫中的ORMLite數組中的每個元素的插入),我想知道是否有可能在解析期間在航班上執行插入,而不是等待數組計算。我在文檔中看到JsonStreamParser可以完成這項工作,但我不知道如何使用它。

+1

數據庫插入可能是瓶頸。你使用內容提供者還是直接插入?你使用beginTransaction()endTRansaction()嗎? –

+0

Indead DB插入是瓶頸之一,實際上我測量的是處理時間。對於JSON解析:17秒,對於數據庫插入:50秒。這就是爲什麼我想在解析期間在數據庫中插入數據到數據庫中,這將是一種並行處理(解析+數據庫插入)。我不使用beginTransaction或endTRansaction,它會提高性能嗎? – Mouss

+0

我有類似的問題。約1000條記錄的Json數組。如果使用內容提供者插入時間〜1分鐘。如果直接訪問db(無內容提供者)並插入單個事務需要大約10秒。 –

回答

1

我有關於使用GSON和其他東西的幾個音符。

  • 你應該關閉我在finally塊/ O資源,以確保你沒有資源泄漏(availableread可能拋出,防止資源被close d除外)。 (我也不敢肯定,如果使用available這裏是一個不錯的主意。)
  • 你只是沒有在這種情況下使用String秒。字符串通常是這種情況下的性能/記憶殺手(很大程度上取決於它們的結果大小),因爲字符串會累積到內存中,因此您將首先將它們全部收集到內存中,從而失去了您的即時創意。在最壞的情況下,它可以通過OutOfMemoryError完成您的申請。
  • 您可以使用指定的編碼讀取輸入流,因此不需要字符串緩衝。
  • JsonParser旨在返回JSON樹:JsonElement包含整個 JSON樹在內存中。聽起來類似於上面的琴絃情況,對嗎?這裏的另一個表現處罰
  • 創建Gson情況下可能有些昂貴(取決於如何比較,當然),你可以實例化一次:這是線程安全的。
  • JsonStreamParser也不是一個選項,因爲每個next()都會在內存中生成另一個JSON樹分支(同樣取決於您的JSON文檔及其元素的大小)。
  • Gson.fromJson使用查找,以找到最佳類型的適配器,你問一個Gson實例的類型的適配器一次,然後不浪費時間查找了。類型適配器通常也是完全線程安全的,因此可以被緩存。

綜上所述,你可以按如下方式實現:

private static final Gson gson = new Gson(); 
private static final TypeAdapter<MyEntity> myEntityTypeAdapter = gson.getAdapter(MyEntity.class); 
private static void loadJsonInDb(final String path) 
     throws IOException { 
    // Java 7 language features can be easily converted to Java 6 try/finally 
    // Note the way how you can decorate (wrap) everything: an input stream (byte streams) to a reader (character streams, UTF-8 here) to a JSON reader (more high-level character reader) 
    try (final JsonReader jsonReader = new JsonReader(new InputStreamReader(context.getAssets().open(path), "UTF-8"))) { 
     // Ensure that we're about to open the root object 
     jsonReader.beginObject(); 
     // And iterate each object property 
     while (jsonReader.hasNext()) { 
      // And check it's name 
      final String name = jsonReader.nextName(); 
      // Another Java 7 language feature 
      switch (name) { 
      // Is it datas? 
      case "datas": 
       // The consume it's opening array token 
       jsonReader.beginArray(); 
       // And iterate each array element 
       while (jsonReader.hasNext()) { 
        // Read the current value as an MyEntity instance 
        final MyEntity myEntity = myEntityTypeAdapter.read(jsonReader); 
        // Now do what you want here 
       } 
       // "Close" the array 
       jsonReader.endArray(); 
       break; 
      default: 
       // If it's something other than "datas" -- just skip the entire value -- Gson will do it efficiently (I hope, not sure) 
       jsonReader.skipValue(); 
       break; 
      } 
     } 
     // "Close" the object 
     jsonReader.endObject(); 
    } 
} 

簡單的講,你只需要編寫一個解析器消耗每個令牌。現在,具有下列JSON文檔:

{ 
    "object": { 
    }, 
    "number": 2, 
    "array": [ 
    ], 
    "datas": [ 
     { 
      "k": "v1" 
     }, 
     { 
      "k": "v2" 
     }, 
     { 
      "k": "v3" 
     } 
    ] 
} 

解析器上述將提取$.datas.*僅消耗較少的資源成爲可能。代// Now do what you want hereSystem.out.println(myEntity.k);會產生:

V1
V2
V3

假設MyEntityfinal class MyEntity{final String k=null;}。請注意,您也可以使用這種方法處理無限的JSON文檔。

+0

Thanx爲這次更新,我將嘗試它。但是,你可以告訴我什麼對應myEntityTypeAdapter? – Mouss

+0

@Mouss對不起,我忘了附上。請參閱編輯。 –

0

我有兩個建議,在這裏:

  1. Deserealize在3線整個集合:

    Gson gson = new Gson(); 
        Type listType = new TypeToken<ArrayList<MyEntity>>(){}.getType(); 
        List<MyEntity> listOf = gson.fromJson(jsonStr, listType); 
    
  2. 當你有實體的整個列表使用bulkInsert單交易。 There you can get the idea how do use it

附: 要使用bulkInsert您必須從您的實體創建ContentValues列表。