.NET MAUIでListView操作

基本的なことは理解している前提で。
ListView.ItemsSourceに大きい配列を入れると、フリーズしちゃって画面に反映されなかった話。
iPhone13なら大丈夫だった。
Xperia Ace II(Android 13)だと5分以上待ってもフリーズしてた。
50件のリストでもややもっさりするくらい。

初期に読み込む件数に制限をかけるとして

50件のリストならもっさりする程度だったので、仮に最初に50件表示したとして。
51件目以降のデータをいつ読むんだ?

下までスクロールしたら?

Scrollイベントハンドラを実装して、e.ScrollYから求めようとしたが失敗。
このScrollYの詳細説明が見つけられなかったが、ピクセルっぽいんだよな。
1行あたりの高さが決まっているなら計算できるかもしれないが、RowHeightが-1の状態では無理だった。

なんか、こう、あっても良くない?
「今、この行が見えているかどうか」みたいなプロパティ…。

これがリストじゃなくて、ただ単に利用規約を最後まで読ませたい、とかならやりようはある。
ScrollViewの中に、利用規約を表示するLabelを配置する。
これならLabelの高さがわかるので、計算できる。

double d = label.Height - scrollView.Height;
if (e.ScrollY >= d - 1)
{
    // 最後まできた!
}

だが、今回はListViewを使いたい。

次の50件を読み込むボタンを置く?

要はページ送り的な。
無難な方法よね。
できればね。
ボタンを設置できない要件だったら終わる。

別スレッドで読み込んでいく?

ListView.ItemsSourceに紐づけたObservableCollectionのメンバに、Timerで1件ずつ追加していく?

ただ、Timerが曲者で、OnAppearingから開始すると、ひょんなことから止まっちゃう。
OnSizeAllocatedまでいったら起動するとか?
ただ、裏でひたすら追加されていくので、画面がカクカクする。
そもそもいつ止まるかよくわからんTimerに頼るのはどうなの?
1秒ごとに更新してたら遅すぎるし、100ミリ秒だと画面がほとんどフリーズしちゃう。
このチューニングも、きっと端末ごとに適切な値は違うんだろうな。
うーん。

private ObservableCollection<int> _list = new ObservableCollection<int>();
private Timer _timer = null;

protected override void OnAppearing()
{
    base.OnAppearing();

    // ここで_listに最初の50件のデータを入れておく
    listView.ItemsSource = _List;
}

protected override void OnSizeAllocated(double width, double height)
{
   if(_timer == null)
   {
       // 固まらないように5秒後から1秒ごとに次を追加
       Task.Run(() =>
       {
           new Timer((state) => { AddData(); }, null, 5000, 1000);
       });
    }
}

private void AddData()
{
    // 更新の必要がなければ終了
    if (_logList.Count == 10000) return;

    // 1件追加
    _list.Add(_list.Count);
}

BindingのModeをOnTimeにする

OneWayなら8倍、OneTimeなら20倍、本当か?

プロパティ変更通知を使用するコンパイル済みのバインド (つまり、OneWayOneWayToSource、または TwoWay バインド) は、従来のバインドより約 8 倍の速さで解決されます。

プロパティ変更通知を使用しないコンパイル済みのバインド (つまり、OneTime バインド) は、従来のバインドより約 20 倍の速さで解決されます。

コンパイル済みのバインディング

試してみたけど、一気にItemsSourceに指定するには耐えれきれてない。
裏で1行ずつ追加するパターンと併せてみても、カクつきも変わらないような・・・。

最後に読取用の行を追加する?

例えば初期50行+更に読み込む用のダミー行を追加しておく。
ItemSelectedイベントハンドラを実装して、ダミー行を選択したら、次の50行を追加する、とか?
ダミー行を設置できるようなデザインなら良いけどね。

BindingのModeをOnTimeにしても問題ないならやりつつ、ボタン配置説か、最後に読取用の行を追加説が有力かな。


他にもニッチなIT関連要素をまとめていますので、よければ一覧記事もご覧ください。

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)