Windows8ファイルシステム内の画像表示とメモリ(JS+HTML)その2

先ほどの投稿では伝えたいことをなにも伝えてませんでした(^^;)
では続きから
ListViewでFileSystemの画像表示は?
ってことなんですけど。
ここから先ではListViewについて基本的なことは分かっている前提で話を進めます。
分からない人はここを見てください。

http://msdn.microsoft.com/ja-jp/library/windows/apps/hh465496.aspx

でListViewで画像表示させるにはどうすんの???

ここではpictureライブラリの中の画像のtest.jpgとtest1.jpgを読みこむとします。

さきほどのドキュメントとか見る限りこんな感じでいけるんじゃ、

javascript

var list = new WinJS.Binding.List();
var loadNames = ["test.jpg","test1.jpg"];

loadNames.forEach(function(fileName){
  Windows.Storage.KnownFolders.picturesLibrary.getFileAsync(fileName).
   then(pushList);
}

function pushList(file){
  var imageURL = URL.createObjectURL(file)
  list.push({
    title: "FileName",
    image: imageURL
  });
    URL.revokeObjectURL(imageURL);
}

html

<div id="testImageView" data-win-control="WinJS.Binding.Template">
        <div style="width: 150px; height: 100px;">
            <!-- Displays the "picture" field. -->
            <img src="#" style="width: 150px; height: 150px;" 
                 data-win-bind="alt: title; src: image" />
        </div>
</div>

はい!これでは動きません。
なぜか、これではのsrcにURLが設定される前にURL.revokeObjectURLが呼ばれているので
srcに値が設定される頃にはすでにimageURLからバイナリへの参照はできません。

まぁ考えてみれば当たり前。
じゃあ
revokeObjectURLしなければいいんじゃない???
確かに、revokeObjectURLしなければ動きます。では確保したメモリいつ解放しますか?って状態になります。
ここまでは何となく納得。
次に
createObjectURLでURLを生成するときに便利なオプションがあることを知ります。
oneTimeOnlyオプションです。
どうやらtrueにすると一度表示した画像を自動的にrevokeしてくれるらしいです。
こんな感じ
createObjectURL(file,{oneTimeOnly: true});
よしこれなら!!!
・・・・・これを信じきってしまったのがダメだったんですね
↑これに気づくのに大分時間かかった。。。

どうやらBindingTemplateを使うと上のオプションも無効なようです。

えっ!?じゃあListViewで表示するときどうすりゃいいのさ!?

テンプレートの使用にBinding.Templateではなくtemplate関数を使えばいいのです。

詳しくはここ
http://msdn.microsoft.com/ja-jp/library/windows/apps/jj585523.aspx

書くほどのことじゃないかもしれないけどテンプレート関数はこんな感じ
テンプレートとは言うもののただの関数なのでこの関数内でrevokeすることも可能なのでurlを
srcに設定した後、revokeしています。

  function itemTemplateFunction(itemPromise) {

       return itemPromise.then(function (item) {
           var div = document.createElement("div");

           var img = document.createElement("img");
           img.src = item.data.image;
           img.alt = item.data.title;
           div.appendChild(img);
      URL.revokeObjectURL(item.data.image);

           return div;
       });
    };

これをlistViewのテンプレートに設定することで、ファイルシステムの画像表示からちゃんとメモリ解放までできます。
えっoneTimeOnlyで生成したのにメモリ解放されてないっぽいよ!?
って人は、まずここを疑ってください。

何度もいいますが、
ファイルシステムの画像を表示するListViewを作るときは、テンプレートにWinJS.Binding.Templateクラス(HTML)を使わずテンプレート関数を使ってください。

ギャラリー系のアプリを使うと必ずメモリ管理がネックになってきます。
なので、解放し忘れ等には十分気をつけましょう。

PS.
メモリ系のテストはめんどくさかったですww
そのために画像をアプリに100枚登録したり....

ちなみに、画像をたくさん表示させるアプリとは、このアプリです。

「ClosetCordinater」
家にある服(買った服)を登録していろいろなコーディネートを作るアプリです。
http://apps.microsoft.com/webpdp/app/closetcordinater/e91f7fb1-e6a2-4040-bbe4-8ff09d65c147

ぜひ使ってみてください!!



追記ーーーーーーー

画像表示に必要だと思うdocumentのリンクを以下に貼ります
ファイルシステムのアクセス効率化
  http://msdn.microsoft.com/ja-jp/library/windows/apps/hh781216.aspx
・画像の選択から表示
  http://msdn.microsoft.com/ja-jp/library/windows/apps/hh465499.aspx

ーーーーーーーーー