我有一个活动加载并显示一个稍大的位图。首先是危险的业务,但我们使用下面的标准方法使用BitmapFactory加载它:
private static Bitmap decodeSampledBitmapFromFile(String filepath, int reqWidth,int orientation) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filepath,options);
if(orientation==0){
options.inSampleSize = calculateInSampleSizeWidth(options, reqWidth);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap d = BitmapFactory.decodeFile(filepath,options);
return Bitmap.createScaledBitmap(d, reqWidth, d.getHeight()*reqWidth/d.getWidth(), true);
}
else{
options.inSampleSize = calculateInSampleSizeHeight(options,reqWidth);
options.inJustDecodeBounds = false;
Bitmap d = BitmapFactory.decodeFile(filepath,options);
return Bitmap.createScaledBitmap(d, d.getWidth()*reqWidth/d.getHeight(), reqWidth, true);
}
}
private static int calculateInSampleSizeWidth( BitmapFactory.Options options, int reqWidth) {
int inSampleSize = 1;
if (options.outWidth > reqWidth) {
final int halfWidth = options.outWidth / 2;
while ( (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
将此Bitmap加载到ImageView中是在如下所示的AsyncTask中完成的:
private static class LoadBitmapTask extends AsyncTask<String, Void, Bitmap>{
private ViewSampleActivity _activity;
public LoadBitmapTask(ViewSampleActivity activity){
this._activity = activity;
}
public void detach(){
this._activity = null;
}
@Override
protected Bitmap doInBackground(String... params) {
try{
String filename = params[0];
Display display = _activity.getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int orientation = getCameraPhotoOrientation(_activity,Uri.fromFile(new File(filename)),filename);
Bitmap d = null;
d = decodeSampledBitmapFromFile(filename, (int)(((double)size.x)*0.85),orientation);
d = rotateBitmapAppropriately(_activity,Uri.fromFile(new File(filename)),filename,d);
return d;
}
catch(Exception e){
return null;
}
}
@Override
protected void onPostExecute(Bitmap result){
try{
_activity.sampleImageView.setImageBitmap(result);
_activity.sampleImageView.setVisibility(View.VISIBLE);
_activity.sampleImageView.getLayoutParams().height = result.getHeight();
_activity.sampleImageView.getLayoutParams().width = result.getWidth();
_activity.viewSampleLayout.getLayoutParams().height = LayoutParams.WRAP_CONTENT;
_activity.hasPicture = true;
}
catch(Exception e){
e.printStackTrace();
}
}
}
为了避免内存泄漏,我重载了活动的onStop方法,以便从AsyncTask中分离活动。
@Override
public void onStop(){
if(this.loadBitmapTask!=null){
loadBitmapTask.detach();
}
super.onStop();
}
现在,我看到的奇怪行为是活动在第一次运行时加载得很好。方向更改后,活动将正确重新加载。但是,在五次左右的方向更改后,应用程序将因内存不足错误而崩溃。 Bitmap似乎是明显的罪魁祸首。我没有保存任何ui元素或位图或任何东西的静态副本,所以我想知道这些内存不足错误是否是由于内存泄漏造成的。
有问题的活动是活动层次结构的最后一个。层次结构的根,即主活动,有一个带有WeakReference的android Handler对象,还有一个管理蓝牙网络线程的持久片段。层次结构中的第二个活动是一个简单的ListActivity。
相关活动的父活动是否会对此活动的Java垃圾收集产生影响?
答案 0 :(得分:1)
Bitmap d
方法中decodeSampledBitmapFromFile()
会被垃圾收集吗?我并非100%清楚这些概念,但似乎从d
创建缩放副本而不回收d
本身是可疑的。
我还建议尝试重新连接到AsyncTask而不是让它死掉(并产生更多?!)。如果您正在使用FragmentActivity,则可以使用非配置实例。在活动中存储对任务的引用,并将其另存为非配置实例。然后尝试重新附加onCreate您的活动:
private LoadBitmapTask mTask;
@Override
public Object onRetainCustomNonConfigurationInstance() {
if(mTask != null){
mTask.detach();
}
return mTask;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
mTask = (LoadBitmapTask) getLastCustomNonConfigurationInstance();
if (mTask != null) {
mTask.attach(this);
}
}
通过这种方式,您可以在中断的地方接听&#34;使用AsyncTask而不必产生更多。