我似乎有内存泄漏,我不知道如何修复。我已经阅读了 android.com 上的所有 ImageSwitcher 教程和示例,但这些似乎都处理了已经在 drawables 文件夹中的 drawables。我的代码允许用户用他们的相机拍摄一张或两张照片,将图像存储到 SD,并使用图像切换器“翻转”图像。
public class CardViewImageActivity extends Activity implements ViewFactory {
private CardDBAdapter mDbHelper;
private String _cardImgGuidFront;
private String _cardImgGuidBack;
private Boolean frontShowing = false;
private Boolean hasFront = false;
private Boolean hasBack = false;
private Uri uriFront;
private Uri uriBack;
private int cardId;
private ImageSwitcher iSwitcher;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.card_view_image);
iSwitcher = (ImageSwitcher)findViewById(R.id.imageSwitcher);
iSwitcher.setFactory(this);
iSwitcher.setOnClickListener(SwitcherOnClick);
this.cardId = Integer.parseInt(getIntent().getExtras().getString(
"cardId")); //$NON-NLS-1$
getCardImageGuids(this.cardId);
if(_cardImgGuidFront != null)
{
hasFront = true;
uriFront = Uri.parse(Environment.getExternalStorageDirectory().toString() + "/" + _cardImgGuidFront + ".jpg");
}
if(_cardImgGuidBack != null)
{
hasBack = true;
uriBack = Uri.parse(Environment.getExternalStorageDirectory().toString() + "/" + _cardImgGuidBack + ".jpg");
}
if(hasFront && hasBack)
Toast.makeText(this, R.string.card_view_touch, Toast.LENGTH_SHORT).show();
if(hasFront)
{
iSwitcher.setImageURI(uriFront);
frontShowing = true;
}
else if(hasBack)
{
iSwitcher.setImageURI(uriBack);
frontShowing = false;
}
else
{
Toast.makeText(this, R.string.card_no_image, Toast.LENGTH_SHORT).show();
}
}
@Override
public void onDestroy()
{
iSwitcher.setImageURI(null);
super.onDestroy();
}
public View makeView() {
ImageView iView = new ImageView(this);
iView.setScaleType(ImageView.ScaleType.FIT_CENTER);
iView.setLayoutParams(new ImageSwitcher.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
return iView;
}
protected OnClickListener SwitcherOnClick = new OnClickListener()
{
@Override
public void onClick(View v)
{
if(frontShowing && hasBack)
{
iSwitcher.destroyDrawingCache();
iSwitcher.setImageURI(uriBack);
frontShowing = false;
}
else if(!frontShowing && hasFront)
{
iSwitcher.destroyDrawingCache();
iSwitcher.setImageURI(uriFront);
frontShowing = true;
}
else
{
}
}
};
private void getCardImageGuids(int cardId)
{
try
{
this.mDbHelper = new CardDBAdapter(this);
this.mDbHelper.open();
Cursor c = this.mDbHelper.fetchCard(this.cardId);
_cardImgGuidFront = c.getString(c
.getColumnIndex(CardDBAdapter.CARD_IMG_GUID_FRONT));
_cardImgGuidBack = c.getString(c
.getColumnIndex(CardDBAdapter.CARD_IMG_GUID_BACK));
}
catch(SQLiteException ex)
{
Toast.makeText(CardViewImageActivity.this, ex.toString(), Toast.LENGTH_LONG).show();
}
finally
{
this.mDbHelper.close();
this.mDbHelper = null;
}
}
}
上面的代码有时似乎工作得很好。但是,我偶尔会收到 OutOfMemory 错误。现在,根据我通过调试的理解,当 .setFactory(this) 被调用时,makeView() 似乎被调用了两次,这似乎很好,因为 ImageSwitcher 的目的是在两个图像之间切换。我想知道除了 SetImageUri() 是否有更好的方法来切换图像。我看不到任何可能泄漏的地方或可能导致问题的原因。我看不到任何地方甚至可以使用 convertView。有没有办法缓存来自 Uri 的图像?每次调用 .setImageUri() 时是否都会重新加载图像?有没有办法转储该内存(或重用)?这就是吞噬我记忆的东西吗?
不要听起来不尊重或粗鲁,但我真的更喜欢帮助,而不需要有人参考避免内存泄漏文章或指向 imageswitcher 的 javadocs 的链接?避免内存泄漏文章显示了一些“您不应该这样做”,但从未显示您“应该”做什么。我已经有指向 javadocs 的链接。我正在寻找能够真正解释我做错了什么并用代码为我指明更好方向的人(我学习最好的代码而不是模糊的抽象学术理论),而不是仅仅从谷歌搜索中反刍前 3 个链接. :)
感谢您的任何帮助!:)
编辑:10Feb2012 所以我尝试加载 Drawables 并立即收到内存不足错误,这比偶尔使用 .setImageUri() 出现错误更糟糕。以下包含模组:
private Drawable front;
private Drawable back;
@Override
public void onCreate(Bundle savedInstanceState) {
...
Resources res = getResources();
...
if(_cardImgGuidFront != null)
{
hasFront = true;
String frontPath = Environment.getExternalStorageDirectory().toString() + "/" + _cardImgGuidFront + ".jpg";
front = new BitmapDrawable(res, frontPath);
}
if(_cardImgGuidBack != null)
{
hasBack = true;
String backPath = Environment.getExternalStorageDirectory().toString() + "/" + _cardImgGuidBack + ".jpg";
back = new BitmapDrawable(res, backPath);
}
查看 SoftReference,使用需要使用另一个可绘制对象创建 SoftReference。我看不出使用 SoftReference 有什么帮助,因为我现在在初始加载时崩溃了。