1

セルがイメージ (HD からロード) を表示している UICollectionView を使用すると、パフォーマンスの問題が発生しました。

バックグラウンドで画像をロードすることでその問題を解決しました。

基本的に、「GetCell」メソッドで、画像が ImageCache にあるかどうかを確認します。

  • その場合は、セルの ImageView に画像を設定します。
  • そうでない場合は、バックグラウンドで画像をロードし、その特定のアイテムのリロードを要求します (セルがその間にリサイクルされるかどうかわからないため、リロードを要求するため、画像を直接設定するのは安全ではありません)

私のバックグラウンドプロセスのスニペット:

ThreadPool.QueueUserWorkItem (delegate { 
                    ImagesCache.AddImageToCache(""+indexPath.Row,ImageForPosition(indexPath.Row));
                    InvokeOnMainThread (delegate { 
                        collectionView.ReloadItems(Converter.ToIndexPathArray(indexPath));
                    });
                }); 

問題なく動作しますが、速くスクロールすると、これらすべての非同期タスクが読み込まれ、問題はリクエストを順番に実行することです (FIFO)。したがって、高速でスクロールすると、非表示セルの画像が表示セルの画像の前に読み込まれます。

このプロセスを最適化してユーザーエクスペリエンスを向上させる方法を知っている人はいますか? これを拡張してインターネットからの画像を含めると、問題が悪化するためです (ダウンロードのため)。

同時スレッドの最大数を増やすと、後で追加されたスレッドをすぐに開始できますが、全体的なパフォーマンス/ダウンロード速度が低下するため、これも実際の解決策ではありません。

ありがとう、マット

4

1 に答える 1

0

つまり、私のプロジェクトの解決策は、サポートthread付きの画像をダウンロードすることです。さらに、再利用のためにデキューされていないことqueueをターゲット コントロールでチェックします。UI

長いバージョン:

  • queueメソッドStart/で実装しますStop。が呼び出しているとき、ビジー ループ ( ) でキューから要求をデキューしようとするStartバックグラウンド スレッドを開始します。while true { DoSomething(); }デキューされていない場合は、少しスリープします。デキューされた場合は、それを実行します (イメージのダウンロード)。Stopメソッドは、ループを終了するスレッドを指定する必要があります。
public void Start()
{
    if (started) {
        return;
    }
    started = true;

    new Thread (new ThreadStart (() => {
        while (started) {
            var request = GetRequest();
            if (request != null) {
                request.State = RequestState.Executing;
                Download (request);
            } else {
                Thread.Sleep (QueueSleepTime);
            }
        }
    })).Start ();
}

public void Stop()
{
    started = false;
}
  • queue次に、そのようなロジックでイメージをダウンロードするためのプライベート メソッドを作成します。ファイル キャッシュ内のイメージをチェックします。ファイルが利用可能な場合は、それを読み取って返します。そうでない場合は、ダウンロードしてファイルに保存し、それを返す ( を呼び出すAction<UIImage> onDownload) か、エラーを返す ( を呼び出すAction<Exception> onError)。queueのビジー ループでこのメソッドを呼び出します。名前を付けますDownload:
public Download(Request request)
{
    try {
        var image = GetImageFromCache(request.Url);
        if (image == null) {
            image = DownloadImageFromServer(request.Url); // Could be synchronous
        }
        request.OnDownload(image);
    } catch (Exception e) {
        request.OnError(e);
    }
}
  • 次に、リクエストをキューに追加する public メソッドを作成します。パターンCommandは、キューのリクエストをラップするのに役立ちます: storage Actions、 current State。名前を付けますDownloadImageAsync:
public DownloadImageAsync(string imageUrl, Action<UIImage> onDownload, Action<Exception> onError)
{
    var request = MakeRequestCommand(imageUrl, onDownload, onError);
    queue.Enqueue(request);
}
  • 画像の表示とUITableViewCellダウンロードのリクエストの準備中:
// Custom UITableViewCell method, which is called in `UITableViewSource`'s `GetCell`
public void PrepareToShow()
{
    var imageURLClosure = imageURL;
    queue.DownloadImageAsync(imageURL, (UIImage image) => {
        if (imageURLClosure == imageURL) {
            // Cell was not dequeued. URL from request and from cell are equals.
            imageView.Image = image;
        } else {
            // Do nothing. Cell was dequeued, imageURL was changed.
        }
    }, (Exception e) => {
        // Set default image. Log.
    });
}

(imageURLClosure == imageURL) をチェックすることはUIImageView、スクロールが速いときに複数の画像を 1 つに表示することを避けるために重要です。1 つのセルで複数の要求を初期化できますが、最後の 1 つの結果のみを使用する必要があります。

さらなる改善:

  • LIFO実行。リクエストがまだ実行されていない場合は、新しいリクエストを追加して開始します。
  • クロスプラットフォーム コードの互換性Action<byte[]> onDownloadのために代わりに使用します。Action<UIImage> onDownload
  • download imageセルが見えなくなったときにリクエストをキャンセルできるようになりました ( WillMoveToSuperview)。まあ、それはあまり必要ではありません。最初のダウンロード後、イメージはキャッシュに保存されるため、それ以降のイメージのリクエストは高速に処理されます。キャッシュのおかげです。
  • メモリ内キャッシュ。したがって、最悪の場合、チェーンは次のようになります。

Find image in in-memory cache-> Find image in file cache-> Downloading from server.

于 2013-07-04T08:10:05.747 に答える