19

特定のポイントに関する情報を表示するために最終的にいくつかのマーカーを持つパノラマ画像を表示するアプリを作成しています。

大きな画像がアプリをクラッシュさせたので (大きな地図を表示しているアプリにも別のアクティビティがあります)、ViewPager を使用して一連のページとしてパノラマを表示しようとしています。

画像を 6 ビットで表示することができ、うまくいっていると思っていましたが、数回 (7 ~ 8 回) スワイプすると、メモリが不足してアプリがクラッシュします。

アイテムが画面から消えると破壊されると思っていたのに、なぜそうなのかについて髪を引っ張っていますか?? 私は絶対的な初心者であり、時間を無駄にしている場合は申し訳ありません. 私は一日中、ここや他の場所から解決策を読んで試してみましたが、賢明ではありません.

これが私のコードです:アクティビティPanoramaView

public class PanoramaView extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.panorama);
    MyPagerAdapter adapter = new MyPagerAdapter();
    ViewPager myPager = (ViewPager) findViewById(R.id.mysixpanelpager);
    myPager.setAdapter(adapter);
    myPager.setCurrentItem(2);
}


}

MyPagerAdapter

public class MyPagerAdapter extends PagerAdapter {
    public int getCount() {
        return 6;
    }
    public Object instantiateItem(View collection, int position) {
        LayoutInflater inflater = (LayoutInflater) collection.getContext()
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        int resId = 0;
        switch (position) {
        case 0:
            resId = R.layout.farleft;
            break;
        case 1:
            resId = R.layout.left;
            break;
        case 2:
            resId = R.layout.middle;
            break;
        case 3:
            resId = R.layout.right;
            break;
        case 4:
            resId = R.layout.farright;
            break;
        case 5:
            resId = R.layout.farfarright;
            break;
        }
        //ImageView imageView = new ImageView(getApplicationContext());
        //imageView.findViewById(R.id.imageView);
        //imageView.setImageBitmap(BitmapFactory.decodeResource(getResources(), ids[position]));

        View view = inflater.inflate(resId, null);
        ((ViewPager) collection).addView(view, 0);
        return view;
    }
    @Override
    public void destroyItem(View collection, int position, Object o) {
        View view = (View)o;
        ((ViewPager) collection).removeView(view);
        view = null;
    }

    @Override
    public boolean isViewFromObject(View arg0, Object arg1) {
        return arg0 == ((View) arg1);
    }
    @Override
    public Parcelable saveState() {
        return null;
    }
}

私のメインレイアウトファイル

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<android.support.v4.view.ViewPager
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/mysixpanelpager"/>
</LinearLayout>

私はこれからも有益なメンバーになることを約束します (実際に自分が何をしているのかを知ったらなおさらです)。

編集: - 最初のアクティビティでは、552kb の画像を表示しています。- このアクティビティ (PanoramaView) で表示している 6 つの画像は、309 ~ 500kb です。- Eclipse でアロケーション トラッカーを使用しましたが、メモリがいっぱいになっていることがわかりましたが、正確なデータは明確ではありませんでした - クラッシュは、7 または 8 個の画像を表示した後に発生します (基本的には、前後に数回スワイプした後)。

farfarright.xml のコードは次のとおりです。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >

<ImageView 
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/imageView"
    android:src="@drawable/panorama6"
    android:adjustViewBounds="true"
    android:contentDescription="@string/panorama" >

</ImageView>
</LinearLayout>

画面外のページ制限を設定しようとしましたが、役に立ちませんでした。

別の投稿でメモリ管理に関するこのリンクを見つけたので、今夜見てみましょう。

編集:ここにLogCat出力があります

11-28 21:17:42.551: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed 51K, 53% free 2558K/5379K, external 2002K/2137K, paused 65ms
11-28 21:17:43.261: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed 1K, 53% free 2557K/5379K, external 3297K/4118K, paused 44ms
11-28 21:17:47.741: W/KeyCharacterMap(328): No keyboard for id 0
11-28 21:17:47.741: W/KeyCharacterMap(328): Using default keymap: /system/usr/keychars/qwerty.kcm.bin
11-28 21:17:49.141: D/DFSAPP(328): my button id before is 2
11-28 21:17:49.691: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed 36K, 52% free 2614K/5379K, external 15576K/15708K, paused 50ms
11-28 21:17:54.571: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed 12K, 52% free 2616K/5379K, external 17386K/17735K, paused 39ms
11-28 21:17:54.661: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed 0K, 52% free 2616K/5379K, external 17386K/17735K, paused 61ms
11-28 21:17:54.711: I/dalvikvm-heap(328): Clamp target GC heap from 25.629MB to 24.000MB
11-28 21:17:54.711: D/dalvikvm(328): GC_FOR_MALLOC freed <1K, 52% free 2616K/5379K, external 18975K/21023K, paused 42ms
11-28 21:18:03.751: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed 6K, 52% free 2616K/5379K, external 18269K/20317K, paused 46ms
11-28 21:18:03.822: I/dalvikvm-heap(328): Clamp target GC heap from 25.628MB to 24.000MB
11-28 21:18:03.852: D/dalvikvm(328): GC_FOR_MALLOC freed <1K, 52% free 2615K/5379K, external 18975K/20317K, paused 32ms
11-28 21:18:04.131: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed <1K, 52% free 2615K/5379K, external 17386K/19434K, paused 49ms
11-28 21:18:04.191: I/dalvikvm-heap(328): Clamp target GC heap from 25.628MB to 24.000MB
11-28 21:18:04.201: D/dalvikvm(328): GC_FOR_MALLOC freed 0K, 52% free 2615K/5379K, external 18975K/19434K, paused 34ms
11-28 21:18:07.301: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed 1K, 52% free 2616K/5379K, external 18269K/19434K, paused 46ms
11-28 21:18:07.381: I/dalvikvm-heap(328): Clamp target GC heap from 25.801MB to 24.000MB
11-28 21:18:07.401: D/dalvikvm(328): GC_FOR_MALLOC freed <1K, 52% free 2616K/5379K, external 19152K/19434K, paused 38ms
11-28 21:18:07.611: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed <1K, 52% free 2615K/5379K, external 18159K/19434K, paused 47ms
11-28 21:18:07.681: I/dalvikvm-heap(328): Clamp target GC heap from 25.801MB to 24.000MB
11-28 21:18:07.681: D/dalvikvm(328): GC_FOR_MALLOC freed 0K, 52% free 2615K/5379K, external 19152K/19434K, paused 36ms
11-28 21:18:18.901: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed 5K, 52% free 2616K/5379K, external 18269K/19434K, paused 57ms
11-28 21:18:18.972: I/dalvikvm-heap(328): Clamp target GC heap from 25.802MB to 24.000MB
11-28 21:18:18.991: D/dalvikvm(328): GC_FOR_MALLOC freed <1K, 52% free 2616K/5379K, external 19152K/19434K, paused 33ms
11-28 21:18:19.181: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed 1K, 52% free 2615K/5379K, external 18159K/19434K, paused 55ms
11-28 21:18:19.251: I/dalvikvm-heap(328): Clamp target GC heap from 25.801MB to 24.000MB
11-28 21:18:19.251: D/dalvikvm(328): GC_FOR_MALLOC freed 0K, 52% free 2615K/5379K, external 19152K/19434K, paused 33ms
11-28 21:18:21.551: D/dalvikvm(328): GC_EXTERNAL_ALLOC freed 1K, 52% free 2616K/5379K, external 18975K/19434K, paused 46ms
11-28 21:18:21.581: E/dalvikvm-heap(328): 1627200-byte external allocation too large for this process.
11-28 21:18:21.621: I/dalvikvm-heap(328): Clamp target GC heap from 25.629MB to 24.000MB
11-28 21:18:21.621: E/GraphicsJNI(328): VM won't let us allocate 1627200 bytes
11-28 21:18:21.631: D/dalvikvm(328): GC_FOR_MALLOC freed 0K, 52% free 2616K/5379K, external 18975K/19434K, paused 34ms
11-28 21:18:21.641: D/AndroidRuntime(328): Shutting down VM
11-28 21:18:21.641: W/dalvikvm(328): threadid=1: thread exiting with uncaught exception (group=0x40015560)
11-28 21:18:21.732: E/AndroidRuntime(328): FATAL EXCEPTION: main
11-28 21:18:21.732: E/AndroidRuntime(328): android.view.InflateException: Binary XML file line #7: Error inflating class <unknown>
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.view.LayoutInflater.createView(LayoutInflater.java:518)
11-28 21:18:21.732: E/AndroidRuntime(328):  at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:568)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.view.LayoutInflater.rInflate(LayoutInflater.java:623)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.view.LayoutInflater.inflate(LayoutInflater.java:408)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
11-28 21:18:21.732: E/AndroidRuntime(328):  at com.businesbike.dfp.MyPagerAdapter.instantiateItem(MyPagerAdapter.java:43)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.support.v4.view.ViewPager.addNewItem(ViewPager.java:692)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.support.v4.view.ViewPager.populate(ViewPager.java:849)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.support.v4.view.ViewPager.populate(ViewPager.java:772)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.support.v4.view.ViewPager.completeScroll(ViewPager.java:1539)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.support.v4.view.ViewPager.computeScroll(ViewPager.java:1422)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.view.ViewGroup.drawChild(ViewGroup.java:1562)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.view.View.draw(View.java:6883)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.widget.FrameLayout.draw(FrameLayout.java:357)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.view.ViewGroup.drawChild(ViewGroup.java:1646)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.view.View.draw(View.java:6883)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.widget.FrameLayout.draw(FrameLayout.java:357)
11-28 21:18:21.732: E/AndroidRuntime(328):  at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1862)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.view.ViewRoot.draw(ViewRoot.java:1522)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.view.ViewRoot.performTraversals(ViewRoot.java:1258)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.view.ViewRoot.handleMessage(ViewRoot.java:1859)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.os.Handler.dispatchMessage(Handler.java:99)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.os.Looper.loop(Looper.java:123)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.app.ActivityThread.main(ActivityThread.java:3683)
11-28 21:18:21.732: E/AndroidRuntime(328):  at java.lang.reflect.Method.invokeNative(Native Method)
11-28 21:18:21.732: E/AndroidRuntime(328):  at java.lang.reflect.Method.invoke(Method.java:507)
11-28 21:18:21.732: E/AndroidRuntime(328):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
11-28 21:18:21.732: E/AndroidRuntime(328):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
11-28 21:18:21.732: E/AndroidRuntime(328):  at dalvik.system.NativeStart.main(Native Method)
11-28 21:18:21.732: E/AndroidRuntime(328): Caused by: java.lang.reflect.InvocationTargetException
11-28 21:18:21.732: E/AndroidRuntime(328):  at java.lang.reflect.Constructor.constructNative(Native Method)
11-28 21:18:21.732: E/AndroidRuntime(328):  at java.lang.reflect.Constructor.newInstance(Constructor.java:415)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.view.LayoutInflater.createView(LayoutInflater.java:505)
11-28 21:18:21.732: E/AndroidRuntime(328):  ... 36 more
11-28 21:18:21.732: E/AndroidRuntime(328): Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.graphics.Bitmap.nativeCreate(Native Method)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.graphics.Bitmap.createBitmap(Bitmap.java:477)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.graphics.Bitmap.createBitmap(Bitmap.java:444)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:349)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:498)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:473)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:336)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.content.res.Resources.loadDrawable(Resources.java:1709)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.content.res.TypedArray.getDrawable(TypedArray.java:601)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.widget.ImageView.<init>(ImageView.java:118)
11-28 21:18:21.732: E/AndroidRuntime(328):  at android.widget.ImageView.<init>(ImageView.java:108)
11-28 21:18:21.732: E/AndroidRuntime(328):  ... 39 more

誰かがこの投稿に出くわした場合、これが修正されたと思われるものです。コードを以下の回答のコードに変更し、パノラマ画像をより小さなビットに切り分けて、各画像が 300kb 未満になるようにしました。

4

4 に答える 4

4

十分に文書化された質問であり、解決したように見えますが、ここに役立つ可能性のある情報が少しあります。

logcat から、Gingerbread で開発中 (または少なくともテスト中) であることを検出しました (Honeycomb 以降では、出力に「外部」部分が含まれていないためです。これは、ビットマップに何が起こっているかを強調するという理由だけで重要です。Gingerbread での場合、ビットマップデータはヒープの外側のネイティブ メモリに配置されます。次に、そのデータへのポインタが他の参照情報とともにヒープ内に配置されます。ビットマップへのすべての参照を削除すると、参照情報が解放されます (ある時点で、System.gc()ただし、ビットマップデータ、デバイスが小惑星に衝突されない限り、解放されることはありません。recycle()そのビットマップのメソッド。その呼び出しは、実際にはネイティブ メモリを解放することに注意してください。そのため、ビットマップが再び必要になった場合は、ビットマップをゼロから再作成する必要がありますViewPager(ほとんどの場合、instantiateItem. Honeycomb 以降では、ビットマップデータをスタック, これは少し煩わしくない.dataはまだそのビットマップの場合にのみリリースされますrecycle()(したがって、何が起こっているのかを判断するために使用して、もう少し深く掘り下げる必要があります。DDMSたとえば、私は現在 JB で同じ問題と戦っています. 、および ICS では、4.0.3 は 4.0.4 とは異なる動作をしますが、余談になります)。

おそらくやり過ぎですが、私の解決策は、ビットマップを追跡するクラスを実装し、それらをリサイクルしたことを確認することでした-あなたの場合、これはdestroyItem()ViewPager.

これが、物事を追跡するために使用する(やや歩行者の)クラスです、fwiw。

public class BitmapManager {

private final String TAG = "DEBUG -- " + ClassUtils.getShortClassName(this.getClass());
Context mContext = null;

private class BitmapVectorEntry {
    public Bitmap bm = null;
    public String name = null;
}

Vector<BitmapVectorEntry> mBitmapVector = new Vector<BitmapVectorEntry>();

public BitmapManager( Context aContext ) {
    mContext = aContext;
}

public void setContext( Context aContext ) {
    mContext = aContext;
}

public void registerBitmap( String name, Bitmap b) {

    if(mBitmapVector == null) {
        mBitmapVector = new Vector<BitmapVectorEntry>();
    }
    if(b == null) {
        Log.e(TAG, "Bitmap is NULL!!  ");
        return;
    }
    // Log.d(TAG, "        ~~~~~~ Registering ["+name+"]  ["+b+"]");
    BitmapVectorEntry be = new BitmapVectorEntry();
    be.bm = b;
    be.name = name;
    mBitmapVector.add(be);
}

public void registerBitmapForBackgroundDrawable( String name, View v ) {
    if(v != null) {
        Drawable d = v.getBackground();
        if(d != null) {
            if(d instanceof BitmapDrawable) {
                Bitmap bm = ((BitmapDrawable) d).getBitmap();
                if(bm != null) {
                    // Log.w(TAG, "     ~~~~  Registering Background Bitmap [" + bm + "]");
                    registerBitmap(name, bm);
                }  else  {
                    Log.w(TAG, " ~~~~ Background does not have a bitmap in the BitmapDrawable (Probably, but not necessarily, and error)");
                }
            }  else  {
                Log.w(TAG, " ~~~~ Background does not have a BitmapDrawable (Might not be an error)");
            }
        }  else  {
            Log.w(TAG, " ~~~~~ Background is null, no drawable (Might not be an error)");
        }
    } else  {
        Log.e(TAG, "  ~~~~~ View is null, is there no background for this view?");
    }
}

// We cannot recycle certain bitmaps, like the background for the page which houses
    // the ViewPager, since the pager reuses it, so we just delete it from vector
public void clear(Bitmap bm) {
    removeBitmap(bm, false);
}

// In most cases, when we are done with a bitmap, we want to recycle it.  This is a
    // synchronous call that frees external heap (in 2.3.x) or internal heap (3.x < ).
    // And when I say 'synchronous' I mean 'slow' and 'should not be run on the UI Thread,
    // So be sure to throw this on an async thread
public void recycleBitmap(Bitmap bm) {
    removeBitmap(bm, true);
}

private void removeBitmap(Bitmap bm, boolean andRecycleToo) {

    if(bm == null) {
        Log.e(TAG, "(RECYCLE BITMAP)  !!!! Bitmap is NULL!!, cannot recycle");
        return;
    }
    if(mBitmapVector == null) {
        Log.e(TAG, "(RECYCLE BITMAP)  !!!! Bitmap Vector is NULL!!");
        return;
    }

    boolean foundIt = false;
    Bitmap targetBm = null;
    int i = (mBitmapVector.size() - 1);
    try {
        for(; i >= 0; i--)  {
            BitmapVectorEntry b = mBitmapVector.get(i);
            targetBm = b.bm;
            if(targetBm.equals(bm)) {
                foundIt = true;
                if(andRecycleToo) {
                    if(!targetBm.isRecycled()) {
                        targetBm.recycle();
                    }
                }
                mBitmapVector.removeElementAt(i);
                // Log.e(TAG, "       Recycling ["+targetBm.name+"]  ["+targetBm.bm+"]");
                break;
            }
        }
    }  catch(Exception e) {

        Log.e(TAG, "Exception during recycling bitmap position ["+i+"] ["+bm+"] ["+e+"]");

    }  finally {

        mBitmapVector.trimToSize();
        if(andRecycleToo) {
            if(!foundIt && targetBm != null) {
                if(!targetBm.isRecycled())  {
                    targetBm.recycle();
                } 
                Log.e(TAG, "(RECYCLE BITMAP)   ========================= !!! RECYCLING Bitmap ["+targetBm+"], was unregistered, recycled is ["+targetBm.isRecycled()+"]");
            }  else  {
                // Log.i(TAG, "(RECYCLE BITMAP)   ========================= !!! RECYCLING Bitmap ["+targBe.name+"] ["+targBe.bm+"], was registered");
            }
        }

    }

}

public void flush() {
    if(mBitmapVector == null) {
        // Log.e(TAG, "!!!! Bitmap Vector is NULL!!");
        return;
    }
    for(int i = 0; i < mBitmapVector.size(); i++) {
        BitmapVectorEntry bme = mBitmapVector.get(i);
        if(!bme.bm.isRecycled()) {
            // Log.e(TAG, "Flushing Bitmap ["+bme.name+"] ["+bme.bm+"]");
            bme.bm.recycle();
        }
    }
    mBitmapVector.clear();
    mBitmapVector.trimToSize();

}

public void dumpBitmaps() {
    if(mBitmapVector == null) {
        // Log.e(TAG, "!!!! Bitmap Vector is NULL!!");
        return;
    }
    boolean foundOne = false;
    for(int i = 0; i < mBitmapVector.size(); i++) {
        Bitmap bm0 = mBitmapVector.get(i).bm;
        if(!bm0.isRecycled()) {
            foundOne = true;
            break;
        }
    }
    if(mBitmapVector.size() > 0 && foundOne) {
        Log.e(TAG, " ========= Dumping Bitmap Vector === (Found a leaker) ===== ");
        Log.e(TAG, "            "+mBitmapVector.size()+" entries");
        for(BitmapVectorEntry b : mBitmapVector) {
            if(!b.bm.isRecycled()) {
                Log.e(TAG, "       ["+b.name+"]  ["+b.bm+"]  Recycled ["+b.bm.isRecycled()+"]");
            }
        }
        Log.e(TAG, " ========= End of Bitmap Dump    ======== ");
    }
}
}

キービットはdumpBitmaps()呼び出しです(少なくとも上記の問題については)。すべてのビットマップを入念に登録すると、dumpBitmaps()呼び出しによってモップアップが必要なものがすべて公開されます。リークがどこにあるかを気にせず、単にそれをなくしたい場合は、flush()すべてのビットマップを削除する を呼び出すことができます。

registerBitmap()ビットマップを作成する場所に配置する必要があります。インフレータが予測できないことをするというひどい運に見舞われたので、次のようなものを好みます。

    public Drawable getPreformattedFile() {
    // Log.d(TAG, "Loading in Drawable ["+preformattedFileName()+"]");
    if( preformattedFileName() == null) {
        Log.e(TAG, "Formatted Filename is null");
        return(null);
    }

    Drawable ret = null;
    try {

        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inScaled = false;
        opts.inPurgeable = true;

        Bitmap bm = BitmapFactory.decodeFile(preformattedFileName(), opts);
        if(bm == null) {
            return(null);
        }
        mBitmapManager.registerBitmap(mItem.name(), bm);
        ret = new BitmapDrawable(mContext.getResources(), bm);

        // Log.i(TAG, "         ~~~~~~~~~~~~~~~~~ JUST CHECKING ["+bm+"]  ["+((BitmapDrawable) ret).getBitmap()+"]");

    } catch( OutOfMemoryError e ) {
        // Log.e(TAG, " ============== Before gc ==== OOME  Thread ["+Thread.currentThread().getName()+"]  getPreformattedFile.Before GC Heap Available [[[ "+(Debug.getNativeHeapFreeSize()/1024)+"k ]]]");
        System.gc();
        // Log.e(TAG, " ============== After gc  ==== OOME  Thread ["+Thread.currentThread().getName()+"]  getPreformattedFile.Before GC Heap Available [[[ "+(Debug.getNativeHeapFreeSize()/1024)+"k ]]]");
        e.printStackTrace();
    } catch( Exception e) {
        Log.e(TAG, "Trouble reading PNG file ["+e+"]");
    }
    return(ret);
}

私は非同期で物事を行うことについて数回言及しましたが、あなたはあなたがAndroidに慣れていないと言っていました。完全を期すために、私は AsyncTask の使用も嫌いであることを言及する必要があります。これは、マルチスレッドにかなり厳しい制限があり、画像には多くのマルチスレッドが必要になる傾向があるためです。そのため、代わりに を使用して次のExecutorようなことを行います (これは、実際の作業を行うために上記の方法を使用したことに注意してください)。

public Drawable getPreformattedFileAsync() {
    if(mItem == null) {
        Log.e(TAG, " -- ITEM is NULL!!");
        return(mErrorDrawable);
    }
    if(mFetchFileTask == null) {
        Log.e(TAG, " -- Task is Null!!, Need to start an executor");
        return(mErrorDrawable);
    }
    Runnable job = new Runnable() {
         public void run() {
             Thread.currentThread().setName("ImagePipeline");
             Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
             Thread.currentThread().yield();
             if(mItemDelegate != null) {
                 Drawable retDrawable = getPreformattedFile();
                 if(showAllDebugInformation) {
                     Log.w(TAG, "   ^^^^ Getting preformatted file size ["+retDrawable.getIntrinsicWidth()+"] x ["+retDrawable.getIntrinsicHeight()+"]");
                 }
                 if(retDrawable != null) {
                     Bitmap bm = ((BitmapDrawable) retDrawable).getBitmap();
                     // Log.w(TAG, "       Size of Bitmap is ["+(bm.getRowBytes()*bm.getHeight())+"]");
                     mItemDelegate.onDrawableRequest(mItem, retDrawable);
                     if(mBitmapManager != null) {
                         if(mBusyDrawable != null) {
                             mBitmapManager.recycleBitmap(((BitmapDrawable) mBusyDrawable).getBitmap());
                         }
                         if(mErrorDrawable != null) {
                             mBitmapManager.recycleBitmap(((BitmapDrawable) mErrorDrawable).getBitmap());
                         }
                     }
                 }  else  {
                     mItemDelegate.onDrawableRequest(mItem, mErrorDrawable);
                 }
             }
             // Log.i(TAG, "  RUNNABLE - Set the background");
         }
     };
     mImagePipelineTask.execute(job);
     return(mBusyDrawable);
}

もちろん、これには Executor が必要です。

    private ExecutorService mImagePipelineTask = null;

次のように作成できます。

    mImagePipelineTask = Executors.newSingleThreadExecutor();

(または、冒険好きなら、マルチスレッド エグゼキュータを使用できます。一般的な考え方は同じです)。

おそらく、これは明確にするのに役立ちます。

于 2012-12-14T09:17:05.203 に答える
3

だから使う

1

@Override
public Object instantiateItem(ViewGroup collection, int position)
@Override
public void destroyItem(ViewGroup collection, int position, Object view)

それ以外の

 public Object instantiateItem(View collection, int position)
 public void destroyItem(View collection, int position, Object view)

2 6つの画像サイズでテストされ、それぞれ400kのサイズで正常に動作します

@Override
public Object instantiateItem(ViewGroup collection, int position)
{
    LayoutInflater inflater = (LayoutInflater) collection.getContext()
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);



    int resId = 0;
    switch (position) {
    case 0:
        resId = R.layout.farleft;
        break;
    case 1:
        resId = R.layout.left;
        break;
    case 2:
        resId = R.layout.middle;
        break;
    case 3:
        resId = R.layout.right;
        break;
    case 4:
        resId = R.layout.farright;
        break;
    case 5:
        resId = R.layout.farfarright;
        break;
    }

View view = (View) inflater.inflate(resId, null);


 //get Image view from layout   
//ImageView imageView = (ImageView) view.findViewById(resId);

//imageView.setImageResource(resId);

    collection.addView(view, 0);

    return view;
}

@Override
public void destroyItem(ViewGroup collection, int position, Object view)
{
    collection.removeView((View) view);
}

3 便利なリンクPageAdapter

幸運を

于 2012-11-28T11:42:52.843 に答える
2
pager.setOffscreenPageLimit(MAX_PAGE);  //pager is the ViewPager instance

これMAX_PAGEは、Visibility の外に残すことができるページ数です。これらに追加されたものは破棄され、ユーザーがスワイプして近くの位置に戻ったときにのみ再作成されます。

于 2012-11-28T07:01:52.727 に答える