我正在编写一个应用程序,显示全景图片,最终有几个标记,以显示有关某些点的信息。
由于大图片崩溃了应用程序(我还在应用程序中显示了一个大型地图的另一个活动),我现在正尝试使用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)介于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>
我已尝试设置屏幕截图限制但没有帮助。
我在其他帖子上找到了关于内存管理的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 :(得分:8)
答案有点迟了,但问题实际上很简单,而且我没有看到针对它的其他答案。
事情是,当你手动解码位图时(正如你在那些注释掉的行中那样),你必须 .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;
}
使用此功能 - 除了从层次结构中删除Bitmap
之外,还可以回收View
:
@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;
}
就这么简单,不需要使用单独的位图管理或其他任何东西。
答案 1 :(得分:4)
记录良好的问题,即使你似乎已经解决了,但这里有一些潜在的有用信息。
从你的logcat,我发现你正在开发(或至少测试)Gingerbread(因为Honeycomb以后不包括输出中的“外部”部分。这很重要,因为它突出显示了你的位图发生了什么在Gingerbread中,位图数据被放置在堆外的本机内存中。然后,该数据的指针被放置在堆中,以及一些其他参考信息删除对位图的每个引用都会释放引用信息(在某些时候运行System.gc()
时)。但是,位图数据将永远不会被释放,除非你的设备被小行星击中 - 或者(不那么戏剧性)你在那个位图上调用recycle()
方法。应该注意的是,这个调用确实释放了本机内存,所以你真的需要重新启动 - ViewPager
再次需要时,从头开始创建位图(最有可能在instantiateItem
。Honeycomb及以后将位图数据放在堆栈中,这稍微不那么烦人了。 data
仅在recycle()
位图时才会释放(因此您需要更深入地挖掘,使用DDMS
来确定正在发生的事情 - 例如,我是目前在JB上遇到同样的问题,在ICS中,4.0.3的行为与4.0.4不同,但我离题了。
这可能有些过分,但我的解决方案是实现一个类来跟踪我的位图,并确定我已经回收了它们 - 在你的情况下,当你在ViewPager中destroyItem()
时会发生这种情况。 / p>
这是我用来追踪事物的(有点行人)课程,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);
}
当然,这需要执行者:
private ExecutorService mImagePipelineTask = null;
可以这样创建:
mImagePipelineTask = Executors.newSingleThreadExecutor();
(或者,如果你喜欢冒险,你可以使用多线程执行者,相同的一般想法)。
也许这有助于澄清。
答案 2 :(得分: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
古德勒克
答案 3 :(得分:2)
pager.setOffscreenPageLimit(MAX_PAGE); //pager is the ViewPager instance
此处MAX_PAGE
是可以保留在可见性之外的页数。除了这些之外,任何其他内容都将被销毁,并且只有在用户滑回附近位置时才会重新创建。