大きなjson文字列をダウンロードする必要があります。これにはaQueryを使用しています。次に、この文字列をオブジェクトのリスト (10k +) で解析し (これには Gson ライブラリを使用しています)、このリストをデータベース (GreenDAO で作成) に挿入する必要があります。しかし、挿入する前に、このリストをオブジェクトの文字列フィールドでソートする必要があります。このフィールドは異なる言語である可能性があるため、並べ替えに Collator クラスを使用しています。問題は、できるだけ少ないメモリを使用してそのようなことを行うにはどうすればよいかということです。
今のところ、文字列をダウンロードし(+文字列、ストリームも使用しようとしました)、それを解析し(+リスト)、ソートします(さらにいくつかのオブジェクト)。別のスレッドで実行していますが、完了してもメモリは解放されません。データが既にデータベースにあるときにデータを並べ替えることができれば(データを選択するときではなく、遅いです)、これを解決できると思いますが、方法がわかりません。
ここにいくつかのコードがあります。ファイルからのデータ読み込みです。JSON文字列をメモリに入れる代わりにInputStreamを使用しているファイルからロードするときも、メモリに同じ問題があります。
public static void getEnciclopediaDataFromFile() {
mRequestStates.put("enc", true);
try {
EncyclopediaParser parser = new EncyclopediaParser(ResourceManager.getResourceManager().loadFile("enc_data"),
ResourceManager.getResourceManager().loadFile("enc_data"),
1361531132);
parser.start();
} catch (Exception e) {
mRequestStates.put("enc", false);
EventBus.getDefault().post(EVENT_ENCYCLOPEDIA_DOWNLOAD_COMPLETE);
}
}
ここにパーサースレッドがあります。コンストラクターは 2 つあります。1 つは Web からのロード用 (文字列パラメーター) で、もう 1 つはファイルからのロード用 (InputStream パラメーター) です。
private static class EncyclopediaParser extends Thread {
// -----------------------------------------------------------------------
//
// Fields
//
// -----------------------------------------------------------------------
private String mJsonData;
private Reader mTitlesReader;
private Reader mContentReader;
private long mUpdateTime;
// -----------------------------------------------------------------------
//
// Constructor
//
// -----------------------------------------------------------------------
public EncyclopediaParser(String jsonData, long updateTime) {
mJsonData = jsonData;
mUpdateTime = updateTime;
this.setPriority(Thread.NORM_PRIORITY - 1);
}
public EncyclopediaParser(Reader titlesReader, Reader contentReader, long updateTime) {
mTitlesReader = titlesReader;
mContentReader = contentReader;
mUpdateTime = updateTime;
this.setPriority(Thread.NORM_PRIORITY - 1);
}
// -----------------------------------------------------------------------
//
// Methods
//
// -----------------------------------------------------------------------
@Override
public void run() {
Type type;
try {
List<ArticleContent> content = null;
type = new TypeToken<Collection<ArticleContent>>(){}.getType();
if(mContentReader == null)
content = new Gson().fromJson(mJsonData, type);
else
content = new Gson().fromJson(mContentReader, type);
List<ArticleTitle> titles = null;
type = new TypeToken<Collection<ArticleTitle>>(){}.getType();
if(mTitlesReader == null)
titles = new Gson().fromJson(mJsonData, type);
else
titles = new Gson().fromJson(mTitlesReader, type);
for(ArticleTitle title : titles)
title.setTitle(title.getTitle().trim());
TitlesComparator titlesComparator = new TitlesComparator();
Collections.sort(titles, titlesComparator);
for(int i = 0; i < titles.size(); ++i) //sorting enc data
titles.get(i).setOrderValue((long)i);
//create sections data
Collator collator = Collator.getInstance(Locale.GERMAN);
collator.setStrength(Collator.PRIMARY);
ArrayList<String> sectionNamesList = new ArrayList<String>();
ArrayList<Integer> sectionIndexesList = new ArrayList<Integer>();
String prevLetter = "";
for (int i = 0; i < titles.size(); ++i) {
if(titles.get(i).getTitle().length() > 0){
if(!Character.isLetter(titles.get(i).getTitle().charAt(0))) {
if( !sectionNamesList.contains("#")) {
sectionNamesList.add("#");
sectionIndexesList.add(i);
}
}
else if(collator.compare(titles.get(i).getTitle().substring(0, 1), prevLetter) > 0) {
sectionNamesList.add(titles.get(i).getTitle().substring(0, 1).toUpperCase(Locale.GERMAN));
sectionIndexesList.add(i);
}
prevLetter = titles.get(i).getTitle().substring(0, 1);
}
}
String[] sectionNames = new String[sectionNamesList.size()]; //use lists instead
Integer[] sectionIndexes = new Integer[sectionIndexesList.size()];
sectionNamesList.toArray(sectionNames);
sectionIndexesList.toArray(sectionIndexes);
AppData.setSectionIndexes(Utils.convertIntegers(sectionIndexes));
AppData.setSectionNames(sectionNames);
GreenDAO.getGreenDAO().insertArticles(titles, content);
AppData.setEncyclopediaUpdateTime(mUpdateTime);
mRequestStates.put("enc", false);
if(mTitlesReader != null)
mTitlesReader.close();
if(mContentReader != null)
mContentReader.close();
} catch (Exception e) {
Log.e("Server", e.toString());
} finally {
EventBus.getDefault().post(EVENT_ENCYCLOPEDIA_DOWNLOAD_COMPLETE);
}
}
}
すべての GreenDAO オブジェクトは静的です。解析は、最初の起動時 (ファイルから) と「更新」ボタンのクリック (Web から) によってのみ行われます。最初の (ファイルからの) 解析が完了した後にアプリを再起動しても、解析が初めて行われた後と同じくらい多くのメモリを使用することに気付きました。