12

Android のデフォルトのギャラリー ウィジェットはビューをリサイクルしません。新しい位置のビューが呼び出されるたびに、ウィジェットは常にnullgetViewに設定されたアダプターのメソッドを呼び出します。convertView

前後にスクロールすると、多くのビューが作成されてしまいます。ギャラリーがそれらを保存するリサイクラー コンポーネントは、OOM 状況につながる十分な速度でそれらをリサイクルしていないようです。

これは、いくつかの大きな画像をギャラリー アイテムとして使用して簡単にテストできますが、最終的には TextView だけで問題が発生します。また、アダプターのメソッドにカウンターを含むログステートメントを配置して、getView作成された新しいビューの数を確認します。

ギャラリーのように動作するが、ビューのリサイクルも実装するサードパーティのウィジェットは存在しますか?

4

5 に答える 5

24

最終的に、私の解決策は、ギャラリーのソースコードを変更するという@CommonsWareの提案に従うことでした。これには、次のファイルのコピーも必要です。

  • AdapterView
  • AbsSpinner

しかし、これらは非常に単純です。

その後、次のようにコードを変更しました。

RecycleBin( AbsSpinner)

  • リサイクラーにオブジェクトを配置するのではなく、位置に従って配置する
  • 要求された位置に関係なく、リサイクラーの下部からオブジェクトを取得します
  • 既存の実装では、アダプタ内のそれぞれの異なる位置が一意のビューになると想定していました。上記の変更は、ギャラリーに 1 種類のアイテムしか含まれていない場合にのみ有効です。そうでない場合は、アイテムの種類と必要な種類の量に基づいて、何らかのキーを追加する必要があります。

Gallery

  • リフレクション (ugh) を使用して のプライベートmGroupFlags変数を変更ViewGroupし、子の並べ替えを許可しました。コンポーネントを使用する前にテストしたフィールド アクセスが成功したかどうかを示すブール値も設定しました。
  • へのすべての呼び出しを削除しましたmRecycler.clear()
  • ギャラリーがスクロールするにつれて表示する必要があるアイテムの数が変化し、既存の実装では、(a) setSelection が呼び出されたときに (b) モーション スクロールが発生したときにリサイクラーがクリアされます。

newViewこれらの変更により、アダプターのメソッドのカウンターが... 7 に達しました。

コードは次のとおりです ( http://en.wikipedia.org/wiki/WTFPLの下のパブリックドメイン 2013/08/07 に配置)

于 2011-05-04T11:54:47.680 に答える
0

http://code.google.com/p/android/issues/detail?id=3376#c19のパッチを使用しました

于 2012-05-03T19:32:12.503 に答える
0

パーティーには大遅刻ですが、EcoGallery を修正して、さらにいくつかのことを行うようにしました (そして、いくつかのクラッシュを回避しました)。

私はそれをTimelineGalleryと呼んでいますが、それは Gallery と同じがらくたですが、スムーズなスクロールを行うことができ、画像が非同期で読み込まれるときに奇妙なことをしません。

それを実証するために、サンプルでは Picasso と PullToRefresh を使用しています。

元のコード、著作権などは Google に属しているため、このようなくだらないウィジェットを作成したことは Google のせいです。

最後の注意: ギャラリーの使用はお勧めしません。古く、バグが多く、ハッキーであり、おそらくメンテナンスされることはありません。問題はバグを修正することではなく、Gallery のアーキテクチャ全体が間違っていることです。そのため、さらにハックを導入しないと修正できません。

Google はこれを認識し、非推奨にしました。ViewPager または Horizo​​ntalScrollList を使用して、それぞれの制限に対処してください。

それでもこの「ギャラリー」を使用したい場合は、ご自由にどうぞ。機能しますが、アプリがクラッシュし、イライラする可能性があります。

于 2014-01-13T23:25:29.563 に答える
-1

OutOfMemory の問題に対するもう 1 つの迅速な回避策は、画像をデコードするコードを試行/キャッチすることです。OutOfMemory 例外がスローされた場合は、解像度を小さくして再度デコードを試みます。

このようなもの:

private static Bitmap decodeFile(File f, int size, int suggestedScale) {

    int scale = 1;
    Bitmap bmp = null;
    try {
        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(new FileInputStream(f), null, o);

        // Find the correct scale value. It should be the power of 2.
        int width_tmp = o.outWidth, height_tmp = o.outHeight;

        if(suggestedScale > 0)
            scale = suggestedScale;
        else {
            if (width_tmp >= height_tmp) {
                scale = Math.round((float)(width_tmp) / size);
            } else {
                scale = Math.round((float)(height_tmp) / size);
            }
        }

        if(scale < 2)
            return BitmapFactory.decodeFile(f.getPath()); 

        Debug.i(TAG, "width: " + width_tmp + "  height: " + height_tmp + "  scale: " + scale);


        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        bmp = BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
    } catch (FileNotFoundException e) {

    } catch(OutOfMemoryError e) {
        Debug.i(TAG, "we retry it cause of an OutOfMemoryException");
        return decodeFile(f, size, scale+1);
    } catch(Exception e){
        Debug.w(TAG, e);
    }
    return bmp;
}

もちろん、同じ画像を異なる時間に異なる解像度で表示することは可能です。ただし、少なくともギャラリーがクラッシュすることはなくなり、常に可能な限り最高の解像度で表示されます。

于 2011-05-30T11:16:36.993 に答える