1

forループの本体である次のコードを最適化する方法についてのアイデアを探しています。

final BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
options.inJustDecodeBounds = false;
ImageButton view = new ImageButton(this);
view.setBackgroundColor(0);
view.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
     finalThis.onBorderClicked(v);
}
});
view.setTag(i); //i is the loop counter

Bitmap big = BitmapFactory.decodeResource(getResources(), borders[i], options);
Bitmap smaller = Bitmap.createScaledBitmap(big, borderDimension, borderDimension, false);

view.setImageBitmap(smaller);

view.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.FILL_PARENT));
((LinearLayout.LayoutParams)view.getLayoutParams()).setMargins(0, 0, -5, 0);
group.addView(view);

big.recycle();

基本的に私は600x600の画像を持っていて、それらを約50dpのサイズにしたいです。したがって、当然、最初にサンプルサイズを4(600/4 = 150)に設定して、不要なメモリを占有しないようにし、次に画像を指定されたサイズにさらにサイズ変更します。次に、それを使用してにロードします。ImageButtonまた、より大きな、現在は役に立たないものをリサイクルしBitmapます。

これは動的なUI作成コードであり、ImageButtonsに追加されHorizontalScrollViewます。あるケースでは、UIに100以上を追加する必要がImageButtonsあり、このコードは非常に低速です。

問題は、どうすればそれをより速く動作させることができるかということです。現在、で実行されていますが、この場合、MainActivityマルチスレッド(おそらくAsyncTask)が役立ちますか?また、ビットマップを目的のサイズにするために、おそらくより高速な方法は他にありますか?このプロセスを大幅に高速化する方法がない場合は、ImageButtonを1つずつ(ただし同じ順序で)段階的に追加して、これらすべてが発生したときにUIがフリーズしないようにする方法はありますか?

4

3 に答える 3

1

自分で画像を拡大縮小する必要はありません。ImageButtonこれを行うには、スケーリングを依頼します。これははるかに高速です。

ImageButton view = new ImageButton(this);
view.setBackgroundColor(0);
view.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
     finalThis.onBorderClicked(v);
}
});
view.setTag(i); //i is the loop counter

view.setAdjustViewBounds(true);
view.setMaxHeight(borderDimension);
view.setMaxWidth(borderDimension);
view.setImageResource(border[i]);

view.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
((LinearLayout.LayoutParams)view.getLayoutParams()).setMargins(0, 0, -5, 0);
group.addView(view);

画像がどのように見えるかわからないため、高さにWRAP_CONTENTを使用するようにレイアウトパラメータを変更しました。レイアウトを少し試すこともできますが、通常はこれでうまくいくはずです。

于 2013-01-24T03:46:54.247 に答える
1

http://developer.android.com/training/displaying-bitmaps/index.htmlで良い解決策を見つけました

次のコードがあり、動的にに設定さBitmapImageViewます。

class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
    private final WeakReference<ImageView> imageViewReference;
    private int data = 0;

public BitmapWorkerTask(ImageView imageView) {
    // Use a WeakReference to ensure the ImageView can be garbage collected
    imageViewReference = new WeakReference<ImageView>(imageView);
}

// Decode image in background.
@Override
protected Bitmap doInBackground(Integer... params) {
    data = params[0];
    return decodeSampledBitmapFromResource(getResources(), data, 100, 100));
}

// Once complete, see if ImageView is still around and set bitmap.
@Override
protected void onPostExecute(Bitmap bitmap) {
    if (imageViewReference != null && bitmap != null) {
        final ImageView imageView = imageViewReference.get();
        if (imageView != null) {
            imageView.setImageBitmap(bitmap);
        }
    }
}
}

これは、次を使用して呼び出すことができます。

public void loadBitmap(int resId, ImageView imageView) {
    BitmapWorkerTask task = new BitmapWorkerTask(imageView);
    task.execute(resId);
}

ここでは、に変更ImageViewしてImageButtonください。

編集:

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
    int reqWidth, int reqHeight) {

    // First decode with inJustDecodeBounds=true to check dimensions
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);

    // Calculate inSampleSize
    options.inSampleSize = 4;

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

取り扱いについて詳しくは、Bitmaps Efficiently こちらをご覧ください。

于 2013-01-24T03:36:19.290 に答える
1

コードをメインスレッドから削除しても、アプリケーションによる画像の処理が速くなることはありませんが、その処理が行われている間、UIがユーザーに応答し続けるため、一度にロードするデータがこれだけ多い場合は絶対に必要な手順です。 。ただし、メインスレッド以外のスレッドからビュー階層を操作することはできないため、この操作全体を。内に配置することはできないことに注意してくださいAsyncTask.doInBackground()。最も時間がかかる行(つまり、yourdecodeResource()createScaledBitmap()calls)を分割する必要がありますが、ビューをインスタンス化して親に追加するコードは、onPostExecute()またはpublishProgress()(タスクロジックの実装方法に応じて)で発生する必要があります。

あるケースでは、UIに100を超えるImageButtonを追加する必要があり、このコードは非常に低速です。

覚えておくべきもう1つの重要なことは、階層内に一度に100を超える画像ベースのビューがあると、それでも大量の無駄なメモリになるということです。プロセスをスピードアップする最善の方法は、すべてのビューを一度に追加するのではなく、必要に応じて(つまり、ユーザーがスクロールしたときに)追加してから、画面に表示されなくなったビューを削除/リサイクルすることです。これがまさにこの理由で実装がどのように機能するかAdapterViewです。必要なメモリのみを使用すると、アプリはより高速かつ効率的になります。

フレームワークにはないことはHorizontalListViewわかっていますが、この機能を提供するサードパーティの実装があります。または、フレームワーククラスの1つのソースを調べて、独自のクラスを構築することもできます。

于 2013-01-24T03:51:30.280 に答える