1

私は初心者の Android 開発者で、練習プロジェクトとして、写真を撮って外部ストレージに保存し、ImageView に表示できるアクティビティを作成しようとしています。ほとんどすべてが機能しているようですが、メモリリークが発生しているようです。

画面の向きが変わると、アクティビティが破棄されてから再作成されると思います。画像を表示し続けるために、画像へのパスを onSaveInstanceState のバンドルに文字列として保存し、onResotreInstanceState で画像をリセットしています。5mp の写真を撮ると、画面を 1 回回転させることができますが、2 回目の回転でアプリがクラッシュし、LogCat がメモリ不足エラーを報告します。解像度の低い画像を使用すると、より多くの回転が得られますが、アプリは最終的にクラッシュし、同じエラーが発生します.

私はAndroidのメモリリークについて調べてきましたが、ビューへの参照を持つことができ、vmがメモリを解放するのを防ぐことができる静的Drawablesを使用しないようにすべてが言っているようです。私が知る限り、参照を保持し続けるようなことはしていません。私のエラーを見つけるのを手伝ってくれる人がいれば、本当に感謝しています。コードは次のとおりです。

public class CameraTestsActivity extends Activity {

private Uri fileUri;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
}

public void takePicture(View view){
    Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

    fileUri = getOutputImageFileUri();
    intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);

    startActivityForResult(intent, 0);
}

private static Uri getOutputImageFileUri() {
    return Uri.fromFile(getOutputImageFile());
}

private static File getOutputImageFile(){
    Log.d("CameraTestsActivity", "Storage state: " + Environment.getExternalStorageState());
    if (Environment.getExternalStorageState().equals("mounted")){
        File mediaStorageDirs = new File (Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures" + "/CameraTestsActivity");
        if (! mediaStorageDirs.exists()){
            if (! mediaStorageDirs.mkdirs()){
                Log.d("CameraTestsActivity", "Failed to create directories");
                mediaStorageDirs = null;
                return null;
            }
        }

        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        File imageFile = new File(mediaStorageDirs.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
        mediaStorageDirs = null;
        return imageFile;


    }
    Log.d("CameraTestsActivity", "Storage state bad");
    return null;
}



@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == RESULT_OK){
        if (requestCode == 0){
            setImage();
        }
    }
    else{
        super.onActivityResult(requestCode, resultCode, data);
    }
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    fileUri = Uri.parse(savedInstanceState.getString("uri"));
    setImage();
    super.onRestoreInstanceState(savedInstanceState);
}

@Override
protected void onSaveInstanceState(Bundle outState) {
    outState.putString("uri", fileUri.toString());
    super.onSaveInstanceState(outState);
}

private void setImage(){
    ImageView image = (ImageView)findViewById(R.id.imageView1);
    File file = new File(fileUri.toString().substring(7));
    if (!file.exists())
        Log.d("CameraTestsActivity", "File " + fileUri.toString().substring(7) + "does not exist");
    image.setImageURI(fileUri);
}

}
4

2 に答える 2

1

ビットマップを表示するときは、そのサイズがヒープ サイズまたは VM バジェットを超えないように注意する必要があります。メモリ リークはありませんが、方向を変更すると、以前にロードされたビットマップを消去するのに時間がかかる場合があり、メモリ オーバーフロー エラーが発生します。このエラーを回避するには、ビットマップを効率的に表示する方法をお読みください。

于 2012-05-21T05:24:14.703 に答える
0

アプリのメモリを分析して、リークがどこにあるかを見つけてください。ここにいくつかのリンクがあります: link1link2

以前のアクティビティのビットマップを ImageView から削除し、アクティビティの onStop() が呼び出されたときに Bitmap.recycle() を呼び出すことで、以前のアクティビティのビットマップを手動で解放することもできます。

于 2012-05-21T05:28:12.113 に答える