2

I'm having two troubles with the below code. It just take picture "onclick" using intent of camera android and it display the image on the ImageView.

  1. After two or three pictures without leaving the activity, it crash with an outOfMemory error often when i'm rotating the display.
  2. When I take picture first time, it refresh the imageview but when i do second or third time...it doesn't refresh the picture until I rotate the screen
  3. I would like to save picture on internal storage instead of external, but I don't understand how to do cause I tried several tutorial and it stucks the camera!

    public class HandScryActivity extends Activity {

    private static int TAKE_PICTURE = 1;
    private MtgMatch myMatch;
    private File handFile;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.handscry);  
        // Disable screen saver
        getWindow().addFlags(LayoutParams.FLAG_KEEP_SCREEN_ON);
        // Load match 
        myMatch = MtgMatch.getSingletonMtgMatch();
        handFile = new File(Environment.getExternalStorageDirectory(), "test.jpg");
        if (myMatch.getHandUri() != null) { loadPicture(); }        
    }
    
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        loadPicture();
    }
    
    // Handles onGame clicked buttons
    public void btnHandClick(View v) {
            Button clickedButton = (Button) v;
        // according to clicked button
        switch (clickedButton.getId()) {
            case R.id.btnBackToGame:
                this.finish();
                break;
            case R.id.btnTakePicture:              
                myMatch.setHandUri(Uri.fromFile(handFile));
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);                
                intent.putExtra(MediaStore.EXTRA_OUTPUT, myMatch.getHandUri());
                startActivityForResult(intent, TAKE_PICTURE);
                break;              
            default:
                break;
        }
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {                     
            if (requestCode == TAKE_PICTURE) {
                // Display image
                if (resultCode == RESULT_OK) {
                    loadPicture();
            } else if (resultCode == RESULT_CANCELED) {
                // User cancelled the image capture
            } else {
                // Image capture failed, advise user
            }
        }
    }
    
    // Put the photo inside frame
    private void loadPicture() {
            ImageView img = (ImageView) findViewById(R.id.imgHand);
            img.setImageURI(myMatch.getHandUri());
    }
    
    }
    
Neeraj Singh
  • 610
  • 9
  • 15
Riccardo Neri
  • 790
  • 1
  • 11
  • 24

2 Answers2

3

You have a memory leak. The reason rotating your screen is causing memory exhaustion is because a screen rotate automatically destroys the Activity and rebuilds it. You can prove this by overriding the onPause and onStart methods and placing a debug statement in them, then rotate the screen and you see them get invoked. You need to understand the android Activity Lifecycle.

You have memory leaks because you are keeping references to those images in memory. You need to be tracking the memory usage. When you tilt the screen, the old activity is sticking around in memory, and a new one is created. In order for the garbage collector to collect up your unnecessary objects, you have to make sure there are no references left to them in the code. There are tools to chart the memory usage of your application so you can find out where the memory leak is:

Follow the directions in this page to have MAT tell you where the memory leak is:

Memory Analyzer Tool in android?

Community
  • 1
  • 1
Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
  • I tried with debug and android destroys activity before create the new one onConfigurationChanges. Therefor it should destroy all my instances, isn't it? – Riccardo Neri Apr 15 '12 at 16:49
  • 1
    You are misunderstanding how the java does memory management with garbage collection. Briefly, you need to understand the difference between memory that is "Reachable" and memory that is "Unreachable". And you need to memorize the Object Lifecycle. You are making objects at a high rate of speed and you are not releasing them from memory. This will explain it: http://java.sun.com/docs/books/performance/1st_edition/html/JPAppGC.fm.html – Eric Leschinski Apr 15 '12 at 17:11
  • Thanks for reply, I read everything but I still haven't clear Ideas. Do you mean that I create instances of MtgMatch quicker than the garbage collector can clean? Cause they are going to be un-reachable as soon as destroy method is called but GC doesn't necessarly pick up them soon? – Riccardo Neri Apr 15 '12 at 17:38
  • 1
    When you call the new intent, you are passing in a reference to myMatch, you need to take that piece out so that it is impossible for the new activity to access components of the old activity. The garbage collector WANTS to destroy them, but it can't, because you are telling it to keep the old activities around just in case you need them. And it is exhausting the very limited memory on the smartphone. Take out the 'intent.putExtra' line, and the garbage collector will clean up older activities. – Eric Leschinski Apr 15 '12 at 19:41
  • But how can I pass a destination to camera intent where save picture, so? I suppose that if, instead passing myMatch.getUri, I pass to it a simple URI the situation will be the same. Why after taking the picture the intent is not gone away and references of it marked to be collected? Basically..how can I adjust my code? – Riccardo Neri Apr 16 '12 at 07:37
  • Finally I get started with heap monitor and I saw that when firing the activity of picture, Suddenly the usage of CPU rise to 99.35% ! It doesn't matter how many times I rotate the screen, it's just between 99.2 and 99.6%. I suppose that if, GC is little bit slower one time, it crashes. So I suppose it's not a memory leak, just low memory of software. An ImageView fitted with image is taking 50% approx of memory. How can I reduce that size? – Riccardo Neri Apr 16 '12 at 08:55
0

To fix the high Memory usage that you are experiencing, it might be worthwhile to you, to take the file that the camera is returning, load it to a bitmap, and using bitmap factory options, set the option to use a sample size. (this scales down the image, but most likely you don't need a 2560x1900 image shown on a 640x480 screen) Check out this tutorial: http://tutorials-android.blogspot.co.il/2011/11/outofmemory-exception-when-decoding.html

TChadwick
  • 868
  • 10
  • 19
  • This is old but that link was useful but gives out wrong data. The parameter in the example for downscaling was 5, if you read the documentation for the API, it says it moves it to the closest lower power of 2 so it is used as 4, and instead of 1/5 or 20% size, the image is 4 times smaller or 1/4 in dimension or 1/16 in size (width * height). – SWoo Sep 17 '14 at 17:16