2014-09-22 56 views
4

附件参考我先前的问题: - Out of memorySQL游标引发内存,同时呼吁的getString

我会尝试尽可能精确。我从我的web服务调用中获得一个长base64字符串的响应。我解码字符串并获得一个包含我的数据的巨大字符串。我反序列化字符串并使用下面的字符串创建我的类的对象。

String decryptedXml = XmlObject.toDecryptedXmlString(gameDetail.getGameData(), app.getSessionEncryptionKey()); 
Game noviceGame = deserialiseGame(decryptedXml, NoviceGamer.class); 

desrialiseGame()只是一个方法,它对数据进行反序列化并创建并返回我的游戏实例。为了将这个对象维护到多个会话(登录/注销),我在数据库中存储了我的整个gameData(我的字符串,其反序列化给了我的Game实例)。

下一次用户登录时,要创建Game实例,我从我的数据库中获取字符串,然后再次尝试去序列化,以便返回我的Game实例。但是当我试图从我的数据库中获取字符串时,在获取字符串时出现'OUT OF MEMORY'异常。

调用以反序列化游戏的方法如下。

private HashMap<String, Game> games = new HashMap<String, Game>(); 

public void load(LocalDatabaseHelper localDbHelper) throws Exception 
{ 
    synchronized(gameLockObject) { 
     GameDetailDAO dao = new GameDetailDAO(localDbHelper); 

     //this will fetch me the all the entities from databse 
     ArrayList<GameDetailEntity> dbGameDetails = dao.getEntities(null, null); 

     for (GameDetailEntity gameDetail : dbGameDetails) { 
      String gameLevel = gameDetail.getDetailLevel();    

      String gameXml = gameDetail.getGameData(); 

      Game game = null; 
      if(gameLevel.equalsIgnoreCase("Novice")) { 
       game = Job.deserialiseJob(gameXml, NoviceLevel.class); 
      } 
      else if (gameLevel.equalsIgnoreCase("Expert")) { 
       game = Job.deserialiseJob(gameXml, ExpertLevel.class); 
      } 

      //set the job version 
      game.setGameversion(gameDetail.getGameVersion()); 
      game.setMagicNumber(gameDetail.getMagicNumber()); 
      game.setInactiveUser(gameDetail.getInactiveUser()); 
      game.setStartTime(gameDetail.getStartTime()); 
      game.setFinishTime(gameDetail.getFinishTime()); 
      game.setGameCompletionTime(gameDetail.getGameCompletionTime()); 
      if (!StringUtils.isNullOrEmpty(gameDetail.getGameStatus())) { 
       game.setGameStatus(GameStatus.valueOf(gameDetail.getGameStatus())); 
      } 

      //add the job to the store 
      games.put(gameDetail.getGameRef().toLowerCase(Locale.getDefault()), game); 
     } 
    } 
} 

我的数据库事务如下:

@Override 
    protected GameEntity getEntityFromCursor(Cursor cursor) 
    { 
     String gameRef = cursor.getString(cursor.getColumnIndex(GAME_REF)); 
     String detailLevel = cursor.getString(cursor.getColumnIndex(DETAIL_LEVEL)); 
     int gameVersion = cursor.getInt(cursor.getColumnIndex(GAME_VERSION)); 
     String gameData = cursor.getString(cursor.getColumnIndex(GAME_DATA)); 
     String status = cursor.getString(cursor.getColumnIndex(GAME_STATUS)); 

     long longStart = cursor.getLong(cursor.getColumnIndex(VISIT_START_TIME)); 
     Date startTime = longStart == -1 ? null : new Date(longStart); 

     long longFinish = cursor.getLong(cursor.getColumnIndex(VISIT_END_TIME)); 
     Date finishTime = longFinish == -1 ? null : new Date(longFinish); 

     long longComplete = cursor.getLong(cursor.getColumnIndex(GAME_COMPLETION_TIME)); 
     Date completionTime = longComplete == -1 ? null : new Date(longComplete); 

     GameEntity entity = new GameEntity(gameRef, detailLevel, gameVersion, gameData,); 
     entity.setGameStatus(status); 
     entity.setStartTime(startTime); 
     entity.setFinishTime(finishTime); 
     entity.setGameCompletionTime(completionTime); 
     return entity; 
    } 

但是当我尝试从数据库@Line String gameData = cursor.getString(cursor.getColumnIndex(GAME_DATA));获取数据,我得到了内存不足的错误。根据我的发现,当我在应用程序标签清单中添加flag largeHeap = true时,我的应用程序变得非常缓慢。而且还developer.android状态

从未要求仅仅是因为你已经用完了内存 一大堆,你需要速战速决,你应该使用它,只有当你确切地知道 您所有的内存被分配和为什么必须保留。 然而,即使你确信你的应用程序可以证明大堆, 你应该避免在任何可能的范围内请求它。

任何人都可以建议我如何避免这种情况。大多数SO问题都没有使用位图。任何帮助将不胜感激。

+0

您为游戏数据列存储的数据有多大? – 2014-09-23 16:40:31

+0

不幸的是它相当大。 – Android 2014-09-24 04:57:48

回答

0

我遇到了问题,原因很简单,字符串的大小很大。巨大。所以我决定减少字符串的大小。我已经从XML分离出图像数据并存储在不同的表格中。这减少了需要反序列化的数据量。我分别重新加载额外的数据。感谢您的宝贵时间和答案。

1

SQLCipher for Android为每个游标窗口分配一个内存缓冲区,最大大小为1 MB。由于您评论说游戏数据文件非常大,因此大小可能会超过游标窗口的最大大小,从而导致内存分配错误。在这种情况下,我们可能会推荐以下两种选择之一:

  1. 将游戏数据标准化为更典型的数据库结构(即多个表,列,行)。
  2. 将游戏数据文件拆分为片段,每个片段小于1 MB,然后在应用程序中重新组装它们。