私は特に でこれを行うことを検討していますCardScrollAdapter
が、カードをタイムラインに公開するときの LiveCard の状況についても知っておくとよいでしょう。volley またはその他のネットワーク ライブラリを使用して、ジェネリックCard
クラスを使用して画像をロードする方法はありますか?
4 に答える
NetworkImageView
Volley のクラスを で直接使用することはできませんがCard
(Card
が独自のレイアウトを管理するため)、Volley の他の機能を使用して画像の遅延読み込みを処理できるはずです。
大まかに言えば、次のようなアプローチを使用できます。
- を作成するときに
Card
、目的の画像がまだ利用できない (どこかにキャッシュされている) 場合は、最初にプレースホルダー画像を使用します。Card
どこかのインスタンスを追跡します(たとえば、アダプター内)。 - イメージをロードするリクエストをキューに入れます。
- 画像が取得されたら、画像をアプリケーションのキャッシュ ディレクトリに書き出し、
file:
URL を使用してカードに追加します。 Card.toView()
カードのビューを再生成し、必要に応じて UI を更新するには、再度呼び出します。
「更新: 10 個以上の画像を含むリストの読み込みが遅くなります。各画像の読み込み後に updateViews() を呼び出すためかどうかはわかりません。」
CardScrollAdapter getView() メソッドが呼び出しのたびに画像をロードしようとしないことを確認してください。
例えば:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if ( getCards() == null ) return null;
MyCard card = getCards().get(position);
if (! card.isImageLoaded()) {
CardImageLoader.loadCardImage(...);
}
return card.toView();
}
それを行う方法はありますが、少し複雑です。getView()
秘訣は、通常は Android で行うように、アダプターの非同期イメージ ロード タスクをディスパッチできないことです。試してみると、イメージをロードする準備が整うまでに、ImageView
によって返されたが GC されることがわかります。card.toView()
GDK のバグのようですが、それが設計されている方法なのかもしれませんが、よくわかりません。
現在の XE12 GDK がサポートするのはcard.addImage(Uri)
、ローカル リソースとファイルの URI のみであるという、さらに複雑な点があります。したがって、上記の警告に加えて、カード イメージとして追加する前に、イメージをファイルにダウンロードする必要があります。
イメージのダウンロード タスクを支援するために、 Android Universal Image Loaderを使用します。すべてを行うクラスは次のとおりです。
public class CardImageLoader {
private static final String TAG = CardImageLoader.class.getSimpleName();
private static final boolean DEBUG = false;
private static final int MAX_IMAGE_LOAD_RETRIES = 3;
private static Map<String, Integer> mLoadFailures = new ConcurrentHashMap<String, Integer>();
public static void init(Context context) {
File cacheDir = StorageUtils.getCacheDirectory(context);
DisplayImageOptions options = new DisplayImageOptions.Builder()
.cacheOnDisc(true)
.build();
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
.discCache(new UnlimitedDiscCache(cacheDir))
.defaultDisplayImageOptions(options)
.build();
ImageLoader.getInstance().init(config);
}
public static void loadCardImage(final Card card, final String imageUri, final CardScrollView cardScrollView) {
card.setImageLayout(Card.ImageLayout.FULL);
int failures = mLoadFailures.containsKey(imageUri) ? mLoadFailures.get(imageUri) : 0;
if (failures > MAX_IMAGE_LOAD_RETRIES) {
if (DEBUG) Log.i(TAG, "Exceeded max retries on imageUri=" + imageUri);
return;
}
File file = ImageLoader.getInstance().getDiscCache().get(imageUri);
if (file != null && file.exists() && file.length() > 0) {
Uri uri = Uri.fromFile(file);
card.addImage(uri);
}
else {
ImageLoader.getInstance().loadImage(imageUri, new ImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {
if (DEBUG) Log.i(TAG, "onLoadingStarted");
}
@Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
if (DEBUG) Log.i(TAG, "onLoadingFailed");
int failures = mLoadFailures.containsKey(imageUri) ? mLoadFailures.get(imageUri) : 0;
mLoadFailures.put(imageUri, ++failures);
}
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
File file = ImageLoader.getInstance().getDiscCache().get(imageUri);
if (DEBUG) Log.i(TAG, "onLoadingComplete uri=" + imageUri + " file=" + file
+ " len=" + (file == null ? 0 : file.length()));
if (file != null && file.exists() && file.length() > 0) {
if (DEBUG) Log.i(TAG, "onLoadingComplete scheduling update of scroll views");
if (cardScrollView != null)
cardScrollView.updateViews(true);
}
}
@Override
public void onLoadingCancelled(String imageUri, View view) {
if (DEBUG) Log.i(TAG, "onLoadingCancelled");
}
});
}
}
}
仕組みは次のとおりです。アダプタのgetView()
で、ロードする URL を見つけます。既に画像がキャッシュされているかどうかを画像ローダーに問い合わせます。存在する場合は、ローカル ファイルの Uri を見つけて を呼び出しcard.addImage(Uri)
、完了です。画像がキャッシュされていない場合、displayImage()
前述の理由により、通常の画像ローダー呼び出しを使用できません。代わりに、loadImage()' and if successful, ask the
CardScrollView' を使用してファイルをダウンロードし、それ自体を再表示します (final
変数を使用しても、ここでカードを設定しようとしないでください。そうしないと、何も起こりません)。これにより、getView()
が再度呼び出されることになりますが、今回のみファイルがキャッシュされます。したがって、画像がカードに追加され、カードが適切に表示されます。
CardScrollView
失敗したダウンロードの再表示のループを防ぐために、失敗したダウンロードの追跡も少しあります。
どうやって使うんですか?とても簡単。最初に、次onCreate()
の行で画像ローダーを初期化する必要があります。
CardImageLoader.init(this);
次に、アダプターgetView()
メソッドで、カードに画像をロードする場合は、次のメソッドを呼び出します。
CardImageLoader.loadCardImage(card, url, mCardScrollView);
画像が表示されたカードが表示されます。これまでに見つけた唯一の注意点は、一度に 20 枚以上の画像を読み込まないことです。そうしないと、パフォーマンスの問題が発生し始める可能性があります。150個のクラッシュガラスをロードするので、注意してください。それに加えて、うまく機能しています。
更新: 10 個以上の画像を含むリストの読み込みが遅くなります。updateViews()
画像が読み込まれるたびに呼び出すためなのか、それとも何なのかはわかりません。
「現在の XE12 GDK では、ローカル リソースとファイル URI を持つ card.addImage(Uri) しかサポートされていないという、さらに複雑な点があります。したがって、上記の警告に加えて、イメージをファイルとして追加する前に、イメージをファイルにダウンロードする必要があります。カード画像」
XE16+ は card.addImage(bitmap) をサポートするようになったので、ファイルを一時キャッシュとして使用する必要がなくなるかもしれません。