2012-11-27 70 views
15

मैं एक ऐप लिख रहा हूं जो एक पैनोरामा चित्र प्रदर्शित करता है जिसमें अंततः कुछ बिंदुओं के बारे में जानकारी प्रदर्शित करने के लिए कई मार्कर होते हैं।छवियों के साथ एंड्रॉइड व्यूपेजर: मेमोरी लीक/ऐप क्रैश

चूंकि बड़ी छवि ने ऐप को दुर्घटनाग्रस्त कर दिया है (मेरे पास एक बड़ा मानचित्र प्रदर्शित करने वाले ऐप में एक और गतिविधि है), अब मैं पैनोरमा को व्यूपेगर के साथ पृष्ठों के अनुक्रम के रूप में प्रदर्शित करने की कोशिश कर रहा हूं।

मैंने 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> 

मैं वादा करता हूँ मैं अब से एक उपयोगी सदस्य हो जाएगा (या इससे भी ज्यादा तो एक बार जब मैं वास्तव में जानता हूं कि मैं क्या कर रहा हूं)।

संपादित करें: - पहली गतिविधि में, मैं एक छवि प्रदर्शित कर रहा हूं जो 552 केबी है। - छः छवियां जो मैं इस गतिविधि में प्रदर्शित कर रहा हूं (पैनोरमा व्यू) 30 9 और 500 केबी के बीच हैं। - मैंने एक्लिप्स में आवंटन ट्रैकर का उपयोग किया है और मैं देख सकता था कि मेमोरी भर रहा था लेकिन सटीक डेटा मुझे स्पष्ट नहीं था - दुर्घटना 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> 

के लिए कोड मैं बंद स्क्रीन पृष्ठों की सीमा जो मदद नहीं की स्थापित करने की कोशिश की है है।

मुझे this किसी अन्य पोस्ट पर मेमोरी प्रबंधन के बारे में लिंक मिला और मैं आज रात इसे देख लूंगा।

संपादित करें: मैं और मैं नीचे इस सवाल का जवाब से कोड के लिए कोड बदलने के लिए है: यहाँ 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 से कम हो।

+0

आपकी बड़ी छवि का क्या अर्थ है? क्या आप स्टैक ट्रेस पोस्ट कर सकते हैं? क्या यह पहली छवि पर दुर्घटनाग्रस्त है या आप कुछ छवियों को प्रदर्शित करने और क्रैश से सफलता प्राप्त कर रहे हैं? क्या आप "farfarright" लेआउट भी पोस्ट कर सकते हैं – Mikhaili

+0

मैंने ऊपर कुछ और विवरण जोड़े हैं। कोई भी मदद बहुत ही सराहनीय होगी। – Workbarby

+0

स्टैकट्रैक – hardartcore

उत्तर

3

तो का उपयोग

@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

गुडलक

+0

आपके कोड और लिंक के लिए बहुत बहुत धन्यवाद। मैंने आपके लिए अपना कोड बदल दिया है और समस्या अभी भी बनी हुई है। मुझे एहसास नहीं हुआ था कि मैं वास्तव में बहिष्कृत सामग्री का उपयोग कर रहा था। मैं देखूंगा कि बिट्स को अक्षम करके मैं और आगे जाऊंगा। – Workbarby

+0

मेरे कोड "imageview" में बंद अनुभाग खोलने का प्रयास करें – Mikhaili

+0

@Workbarby: आपने इसे उत्तर के रूप में चिह्नित किया है, तो क्या आप कृपया मुझे बता सकते हैं कि सटीक समाधान क्या है? मुझे भी एक ही समस्या का सामना करना पड़ रहा है और मैं समाधान के बारे में खाली हूं। मैंने कई तरीकों की भी कोशिश की लेकिन असफल रहा। मैंने दोनों पिकासो या सार्वभौमिक छवि लोडर के साथ प्रयास किया, लेकिन अभी भी सफल नहीं हुआ। –

2
pager.setOffscreenPageLimit(MAX_PAGE); //pager is the ViewPager instance 

यहाँ MAX_PAGE पृष्ठों कि दृश्यता के बाहर रह सकते हैं की संख्या है। इनमें से कोई भी अतिरिक्त नष्ट हो जाएगा और जब उपयोगकर्ता पास की स्थिति में वापस आ जाता है तो केवल फिर से बनाया जाता है।

4

खैर प्रलेखित सवाल है, और भले ही आप इसका समाधान नहीं गए हैं लगता है, यहाँ को बेहद उपयोगी जानकारी का एक छोटा सा है।

आप लॉगकैट से, मुझे पता है कि आप जिंजरब्रेड पर विकास (या कम से कम परीक्षण) कर रहे हैं (क्योंकि हनीकॉम के बाद आउटपुट में "बाहरी" भाग शामिल नहीं होता है। यह केवल इसलिए महत्वपूर्ण है क्योंकि यह आपके लिए क्या हो रहा है बिटमैप्स। जिंजरब्रेड में, बिटमैप डेटा ढेर के बाहर देशी मेमोरी में रखा गया है। फिर, पॉइंटर उस डेटा को ढेर के भीतर रखा गया है, कुछ अन्य संदर्भ जानकारी के साथ। बिटमैप के प्रत्येक संदर्भ को रिहा कर देगा रेफरेंसियल जानकारी (कुछ बिंदु पर, जब System.gc() रन)। हालांकि, बिटमैप डेटा कभी भी रिलीज़ नहीं होगा, जब तक कि आपका डिवाइस किसी के द्वारा हिट नहीं किया जाता टेरोइड - या (कम नाटकीय) आप उस बिटमैप पर recycle() विधि को कॉल करते हैं। वह कॉल, यह ध्यान दिया जाना चाहिए, वास्तव में मूल स्मृति को छोड़ देता है, इसलिए आपको ViewPager (instantiateItem में सबसे अधिक संभावना होने पर फिर से स्क्रैच से बिटमैप को फिर से बनाने की आवश्यकता है। हनीकॉम और आगे की जगह बिटमैप डेटा स्टैक के भीतर, जो थोड़ा कम परेशान है। data तब भी जारी किया जाता है जब आप recycle() उस बिटमैप (इसलिए आपको DDMS का उपयोग करके थोड़ा गहरा खोदना होगा, उदाहरण के लिए, मैं वर्तमान में जेबी पर और इसी तरह आईसीएस में एक ही समस्या से लड़ने, 4.0.3 4.0.4 से अलग व्यवहार करता है, लेकिन मैं digress)

यह शायद अधिक है, लेकिन मेरा समाधान मेरी बिटमैप को ट्रैक करने के लिए कक्षा को लागू करना था, और सुनिश्चित करें कि मैंने उन्हें पुनर्नवीनीकरण किया था - आपके मामले में, यह जब आप ViewPager में destroyItem() करेंगे तब होगा।

यहां कुछ (कुछ पैदल यात्री) वर्ग है जो मैं चीजों को ट्रैक करने के लिए उपयोग करता हूं, 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() रखना होगा।मैं inflater अप्रत्याशित काम करने के साथ भयानक भाग्य पड़ा है, इसलिए मैं कुछ ऐसा पसंद करते हैं:

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); 
} 

मैं अतुल्यकालिक रूप से काम करने दो बार उल्लेख किया है, और आप उल्लेख किया है कि आप एंड्रॉयड के लिए नए-ish हैं। पूर्णता के लिए, मुझे यह उल्लेख करना चाहिए कि मैं AsyncTask का उपयोग करके भी नापसंद करता हूं, क्योंकि इसमें बहु-थ्रेडिंग पर कुछ बहुत भारी सीमाएं हैं, और छवियों को बहुत से बहु-थ्रेडिंग की आवश्यकता होती है। तो, बजाय मैं एक Executor का उपयोग करें और कुछ इस तरह करते हैं (जो, आप ध्यान देंगे, विधि का इस्तेमाल किया ऊपर वास्तविक काम करने के लिए):

private ExecutorService mImagePipelineTask = null; 
:

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); 
} 

यह, ज़ाहिर है, एक निर्वाहक की आवश्यकता है

कौन इस प्रकार बनाया जा सकता है:

mImagePipelineTask = Executors.newSingleThreadExecutor(); 

(या, यदि आप साहसी हैं, तो आप एक बहु धागा प्रबंधक, एक ही सामान्य विचार उपयोग कर सकते हैं)।

शायद यह स्पष्ट करने में मदद करता है।

+0

इसके लिए धन्यवाद! रीसायकल() की तरफ इशारा किया जा रहा था जो मुझे अपने व्यूपार्जर मेमोरी रिसाव को हल करने के लिए आवश्यक था। – Cephron

6

उत्तर के साथ थोड़ा देर हो चुकी है, लेकिन मुद्दा वास्तव में काफी सरल है, और मुझे इसे लक्षित करने वाले अन्य उत्तरों को नहीं दिख रहा है।

बात, आप.recycle()उन्हें अपने करना पड़ता है जब आप मैन्युअल रूप से बिटमैप्स डिकोड (के रूप में आप उन पर टिप्पणी की लाइनों में करते हैं),। तो, वापस अपने कोड के लिए, अपने अनुकूलक में आप इस पूरक करने के लिए है: इस के साथ

@Override 
public Object instantiateItem(View collection, int position) { 
    // ... 
    View view = inflater.inflate(resId, null); 
    ImageView imageView = (ImageView) view.findViewById(R.id.imageView); 
    imageView.setImageBitmap(BitmapFactory.decodeResource(getResources(), 
      ids[position])); 
    ((ViewPager) collection).addView(view, 0); 
    return view; 
} 

- पदानुक्रम से View को दूर करने के अलावा Bitmap रीसायकल:

@Override 
public void destroyItem(View collection, int position, Object o) { 
    View view = (View)o; 
    ImageView imgView = (ImageView) view.findViewById(R.id.imageView); 
    BitmapDrawable bmpDrawable = (BitmapDrawable) imgView.getDrawable(); 
    if (bmpDrawable != null && bmpDrawable.getBitmap() != null) { 
      // This is the important part 
      bmpDrawable.getBitmap().recycle(); 
    } 
    ((ViewPager) collection).removeView(view); 
    view = null; 
} 

यह रूप में सरल है कि, अलग बिटमैप प्रबंधन या कुछ भी उपयोग करने की आवश्यकता नहीं है।

+0

मुझे java.lang.RuntimeException मिल रहा है: कैनवास: पहले से देखी गई छवि (जिसे अब रीसाइक्लिंग किया गया है) पर लौटने पर रीसाइक्लिंग बिटमैप [email protected] का उपयोग करने का प्रयास कर रहा है। – Yar

+0

@Yar यह अजीब है। बात यह है कि 'नष्ट करने के बाद' इटिम कहा गया है, इसमें शामिल छवि दृश्यों को अब और प्रस्तुत नहीं किया गया है। तो आपके पास तर्क का कुछ अन्य टुकड़ा होना चाहिए जो पेजर एडाप्टर के अलावा उस बिटमैप तक पहुंचने का प्रयास करता है।यदि आप अधिक जानकारी प्रदान करते हैं (कम से कम लाइन नंबर और प्रासंगिक कोड) –

+0

हैलो, मुझे एक ही त्रुटि मिल रही है, तो मुझे शायद कुछ पता लगाना चाहिए 'java.lang.RuntimeException: कैनवास: छवियों के माध्यम से स्वाइप करते समय पुनर्नवीनीकरण बिटमैप का उपयोग करने का प्रयास पेजर देखें। क्या आप मदद कर सकतें है। – Dory

संबंधित मुद्दे