2

このカスタムImageViewクラスを開発して、私のニーズに合わせてデフォルトの動作の一部をオーバーライドしました。この習慣が何をするのか説明しましょうImageView...

フォルダーとフォルダーGridViewの両方に表示するアイコンがたくさんあるとします。それぞれのサイズは 48x48px と 72x72px です。フォルダに使用できるアイコンはありません。属性は、すべてのアイコンのサイズが 48x48dp になるように設定されています (これは、mpdi、hdpi、および xhdpi 密度に対してそれぞれ 48px、72px、および 96px に変換されます)。drawable-mdpidrawable-hdpidrawable-xhdpiGridView

フォルダーにはアイコンがないためdrawable-xhdpi、このアプリがそのような密度のデバイスで実行されると、アイコンはフォルダーからプルされdrawable-hdpiます。また、それらは 72 ピクセルしかなく、xhdpi デバイスは 96 ピクセルの画像を想定しているため、アイコンは引き伸ばされて残りのピクセルを埋めます。

これは、私のカスタムImageViewがオーバーライドしようとしている動作です。カスタム コンポーネントを使用すると、画像が単純に引き伸ばされなくなります。たとえば、私のクラスを使用した上記の例では、ImageView内部のそれぞれGridViewは 96x96px のままですが (48x48dp のサイズが定義されているため)、使用される画像drawable-hdpiは 72x72px のフォルダーからのものです。何が起こるかというと、drawable-hdpiフォルダーのこれらの画像はImageView、ビュー全体のサイズに合わせて画像を引き伸ばすことなく、サイズが 96x96 ピクセルの の中央に配置されます。

上記がわかりにくい場合は、いくつかの写真で試してみましょう。以下の例では を使用していませんGridView。カスタム クラスの背後にあるアイデアを単純化しようとしています。これらは、この例で使用しているソース画像です。

ソースファイル

これは、HDPIデバイスでの結果です。

hdpi-デモ

そして、これはXHDPIデバイスでの結果です:

xhdpi-デモ

上記のスクリーンショットのレイアウトのコードは次のとおりです。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="10dp"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Standard ImageView:"
        android:textAppearance="?android:attr/textAppearanceLarge"/>

    <ImageView
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_margin="10dp"
        android:scaleType="center"
        android:background="#FFEEEE"
        android:src="@drawable/ic_female"/>
    <ImageView
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_margin="10dp"
        android:scaleType="center"
        android:background="#FFEEEE"
        android:src="@drawable/ic_male"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Custom UnscaledImageView:"
        android:textAppearance="?android:attr/textAppearanceLarge"/>

    <com.sampleapp.widget.UnscaledImageView
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_margin="10dp"
        android:scaleType="center"
        android:background="#FFEEEE"
        android:src="@drawable/ic_female"/>
    <com.sampleapp.widget.UnscaledImageView
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_margin="10dp"
        android:scaleType="center"
        android:background="#FFEEEE"
        android:src="@drawable/ic_male"/>

</LinearLayout>

より明確になりましたか?これは私がやりたいことであり、これはうまく機能していますが、小さなパフォーマンスの問題を除けば...このようなカスタムコンポーネントに使用しているコードを投稿しましょう:

attrs.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="UnscaledImageView">
        <attr name="android:src" />
    </declare-styleable>

</resources>

UnscaledImageView.java:

public class UnscaledImageView extends ImageView {

    private int mDeviceDensityDpi;

    public UnscaledImageView(Context context) {
        super(context);

        mDeviceDensityDpi = getResources().getDisplayMetrics().densityDpi;
    }

    public UnscaledImageView(Context context, AttributeSet attrs) {
        super(context, attrs);

        mDeviceDensityDpi = getResources().getDisplayMetrics().densityDpi;

        TypedArray styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.UnscaledImageView);
        int resourceId = styledAttrs.getResourceId(R.styleable.UnscaledImageView_android_src, 0);

        if(resourceId != 0) {
            setUnscaledImageResource(resourceId);
        }

        styledAttrs.recycle();
    }

    public void setUnscaledImageResource(int resId) {
        setImageBitmap(decodeBitmapResource(resId));
    }

    @SuppressWarnings("deprecation")
    public void setUnscaledBackgroundResource(int resId) {
        BitmapDrawable drawable = new BitmapDrawable(null, decodeBitmapResource(resId));
        drawable.setTargetDensity(mDeviceDensityDpi);
        drawable.setGravity(Gravity.CENTER);

        setBackgroundDrawable(drawable);
    }

    private Bitmap decodeBitmapResource(int resId) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inDensity = mDeviceDensityDpi;

        return BitmapFactory.decodeResource(getResources(), resId, options);
    }

}

したがって、このクラスは、UnscaledImageViewビューが XML レイアウトで使用されているか、コードで直接初期化されている場合に機能します。また、2 つのメソッドを用意して、画像が引き伸ばされないようにしながら、コードで画像を変更できるようにしました。ご覧のとおり、これらのメソッドはリソース ID のみを受け取ります。これまでのところ、ドローアブルやビットマップを直接使用する必要性を感じたことはありません。

今、私がこれで抱えている本当の問題は...

このクラスが何らかのレイアウトで単一の画像ビューとして使用される場合、問題はありません。1 つの画像をデコードするだけです。ただし、GridView40 個のアイコン (xhdpi デバイスで実行されているアプリで実際に発生することからこの値を取得しています) が同時に表示される可能性がある場所で使用される場合、スクロールは非常GridViewに遅くなります。ありとあらゆるイメージ。decodeBitmapResource()BitmapFactory.decodeResource()

これは私の問題であり、それが私の質問です。これを最適化するにはどうすればよいですか?できれば全然...

4

2 に答える 2

1

これらの画像を に配置すると、res/drawable-nodpi/必要なことができます (異なる解像度の画像を並べて配置すると言っています)。

描画しようとしている特定の画像に最適なリソースを見つけるには、おそらく命名規則に従う必要があるため、少し注意が必要です。おそらく、名前で画像を検索する必要がありますが、これはリソースを取得する効率的な方法ではありません。

私が想像する方法は次のとおりです。レイアウト (または他の場所) で、使用する画像リソースの名前 (ID ではなく文字列!) を指定します。

その nodpi フォルダーには、目的の画面密度の接尾辞が付いた画像があります。

次に、setter メソッドで、利用可能な最適なリソースを見つけるために、さまざまな組み合わせを試す必要があります。

あなたが考える問題: 画像を縮小している場合はどうなるでしょうか? リソースは、描画するビューよりも大きくなります!

于 2012-10-15T22:29:13.543 に答える
0

Pedro Loureiroによる答えは可能な解決策かもしれませんが、私は何かを実現した後、別のアプローチを取ることにしました...

もちろん、非科学的に、ネイティブのImageView読み込みと読み込みUnscaledImageViewの両方の時間を計りGridViewましたが、クラスがすべての画像をネイティブの画像よりも少し速く読み込むことに気づきました。たぶん、ネイティブメソッドはリソースをデコードする以外に何か他のことが起こっているかもしれません(彼らはまだそれをしなければなりませんよね?)私のクラスは単にリソースをデコードします(を使用してBitmapFactory)そしてそれは基本的にそれです。

GridViewスクロール中に少し遅くなったのは私のクラスだと思いましたが、さらにいくつかのテストを行った後、ImageView微調整なしでオリジナルを使用すると、スクロール中に少し途切れがちであることがわかりましたGrivView

この問題を解決するために私が見つけた解決策(私のクラスまたはネイティブのもののいずれか)は、アイコンをにキャッシュすることでした。そのために、画像をキャッシュするための推奨される方法であるGridViewを使用しました。LruCacheGridView

これが、問題を解決するために使用するソリューションです。詳細については、公式トレーニングガイドを参照してください:http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html

参考までに、次のチュートリアルも役立ちます。http: //andrewbrobinson.com/2012/03/05/image-caching-in-android/

于 2012-10-17T17:10:50.173 に答える