数据库
首页 > 数据库> > android – SQL Cursor在调用getString时抛出内存不足

android – SQL Cursor在调用getString时抛出内存不足

作者:互联网

附件参考我之前的问题: – Out of memory

我会尽量保持精确.我从我的web服务调用得到一个长base64字符串的响应.我解码字符串并得到一个包含我的数据的巨大字符串.我反序列化字符串并使用如下字符串创建我的类的对象.

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

desrialiseGame()只是一种解析数据并创建和返回我的游戏实例的方法.为了将这个对象保持为多个会话(登录/注销),我将我的整个gameData(我的字符串,其反序列化给了我的游戏实例)存储在数据库中.

下次用户登录时,为了创建Game实例,我从我的DB中获取字符串,然后再次尝试反序列化,以便我回到我的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));我内存不足错误.根据我的发现,当我在应用程序标记的清单中添加标志largeHeap = true时,我的应用程序变得非常缓慢.还有developer.android声明

Never request a large heap simply because you’ve run out of memory
and you need a quick fix—you should use it only when you know exactly
where all your memory is being allocated and why it must be retained.
Yet, even when you’re confident your app can justify the large heap,
you should avoid requesting it to whatever extent possible.

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

解决方法:

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

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

标签:android,out-of-memory,sqlcipher,xml-deserialization
来源: https://codeday.me/bug/20190708/1403468.html