如何处理 ViewPager 片段中的图像回收?
How to handle image recycling in ViewPager fragments?
我有一个使用 ViewPager 的图像查看器。每个片段上都有一个大图像。这在一段时间内工作正常,但在足够多的图像之后,应用程序内存不足。
为了解决这个问题,我尝试回收位图,但这会导致另一个问题:如果我向后滑动,回收的位图会导致 RuntimeException
:
java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@268f7cd3
片段代码如下所示:
Bitmap m_image = null;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View root = inflater.inflate(R.layout.fragment_image, container, false);
final ImageView img = (ImageView)root.findViewById(R.id.ivImage);
img.setVisibility(View.GONE);
Picasso.with(getContext())
.load(getArguments().getString("url"))
.into(new Target()
{
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from)
{
m_image = bitmap;
img.setImageBitmap(m_image);
img.setVisibility(View.VISIBLE);
}
@Override
public void onBitmapFailed(Drawable errorDrawable)
{
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable)
{
}
});
return root;
}
@Override
public void onDestroyView()
{
if(m_image != null)
{
m_image.recycle();
m_image = null;
}
super.onDestroyView();
}
保存 ViewPager 的 Activity 看起来像这样:
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image);
final DataHandler dataHandler = getApp().getDataHandler();
PagerAdapter adapter = new FragmentStatePagerAdapter(getSupportFragmentManager())
{
@Override
public Fragment getItem(int position)
{
Entry e = dataHandler.get(position);
Fragment f = new ImageFragment();
Bundle args = new Bundle();
args.putString("url", e.getURL());
f.setArguments(args);
return f;
}
@Override
public int getCount()
{
return dataHandler.getCount();
}
});
ViewPager pager = (ViewPager)findViewById(R.id.vpImages);
pager.setAdapter(adapter);
}
使用Picasso 时不需要处理内存。如果您的片段被 GCed,ImageView 将负责回收与其关联的位图。
一些建议:
如果您在项目中添加OkHttp作为依赖项,Picasso 将自动添加网络缓存。缓存图像加载速度更快,数据消耗更少。
为了仅使用您需要的内存,我会调整图像大小以匹配 ImageView 大小。为此,请使用:
Picasso.with(context).fit().centerCrop().into(imageView);
我有一个使用 ViewPager 的图像查看器。每个片段上都有一个大图像。这在一段时间内工作正常,但在足够多的图像之后,应用程序内存不足。
为了解决这个问题,我尝试回收位图,但这会导致另一个问题:如果我向后滑动,回收的位图会导致 RuntimeException
:
java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@268f7cd3
片段代码如下所示:
Bitmap m_image = null;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View root = inflater.inflate(R.layout.fragment_image, container, false);
final ImageView img = (ImageView)root.findViewById(R.id.ivImage);
img.setVisibility(View.GONE);
Picasso.with(getContext())
.load(getArguments().getString("url"))
.into(new Target()
{
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from)
{
m_image = bitmap;
img.setImageBitmap(m_image);
img.setVisibility(View.VISIBLE);
}
@Override
public void onBitmapFailed(Drawable errorDrawable)
{
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable)
{
}
});
return root;
}
@Override
public void onDestroyView()
{
if(m_image != null)
{
m_image.recycle();
m_image = null;
}
super.onDestroyView();
}
保存 ViewPager 的 Activity 看起来像这样:
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image);
final DataHandler dataHandler = getApp().getDataHandler();
PagerAdapter adapter = new FragmentStatePagerAdapter(getSupportFragmentManager())
{
@Override
public Fragment getItem(int position)
{
Entry e = dataHandler.get(position);
Fragment f = new ImageFragment();
Bundle args = new Bundle();
args.putString("url", e.getURL());
f.setArguments(args);
return f;
}
@Override
public int getCount()
{
return dataHandler.getCount();
}
});
ViewPager pager = (ViewPager)findViewById(R.id.vpImages);
pager.setAdapter(adapter);
}
使用Picasso 时不需要处理内存。如果您的片段被 GCed,ImageView 将负责回收与其关联的位图。
一些建议:
如果您在项目中添加OkHttp作为依赖项,Picasso 将自动添加网络缓存。缓存图像加载速度更快,数据消耗更少。
为了仅使用您需要的内存,我会调整图像大小以匹配 ImageView 大小。为此,请使用:
Picasso.with(context).fit().centerCrop().into(imageView);