2012-06-28 4 views
1

У меня есть приложение для Android, которое рушится на некоторых телефонах, а не на других. Он имеет около 5 тыс. Загрузок и до сих пор получил около 50 отчетов о сбоях. Однако, исходя из количества оценок/комментариев, которые я получаю от пользователей, говорящих о том, что это силовая катастрофа, я думаю, что процент затронутых пользователей на самом деле намного выше.Android с сохранением фотографий на SD-карте

Поскольку проблема не влияет на мой телефон, я не смог воспроизвести ошибку и отладить ее, как я бы хотел.

Приложение делает снимок с камеры, накладывает растровое изображение на него и сохраняет полученное изображение на SD-карту.

Ниже приведен мой код для метода PictureCallback onPictureTaken.

private Camera.PictureCallback mPicture = new Camera.PictureCallback() { 

    public void onPictureTaken(byte[] data, Camera camera) { 

     captureBtn.setVisibility(ImageButton.INVISIBLE); 

     File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE); 
     if (pictureFile == null){ 
      return; 
     } 

     BitmapFactory.Options options = new BitmapFactory.Options(); 
     Bitmap mutableBitmap = null; 
     Bitmap finalBitmap = null; 
     byte[] byteArray = null; 
     try { 
      mutableBitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options).copy(Bitmap.Config.RGB_565, true); 
      Matrix matrix = new Matrix(); 
      int width = mutableBitmap.getWidth(); 
      int height = mutableBitmap.getHeight(); 
      int newWidth = overlayView.getDrawable().getBounds().width(); 
      int newHeight = overlayView.getDrawable().getBounds().height(); 
      float scaleWidth = ((float) newWidth)/width; 
      float scaleHeight = ((float) newHeight)/height; 
      matrix.postScale(scaleWidth, scaleHeight); 
      matrix.postRotate(90); 

      Bitmap resizedBitmap = Bitmap.createBitmap(mutableBitmap, 0, 0, mutableBitmap.getWidth(), mutableBitmap.getHeight(), matrix, true); 
      finalBitmap = resizedBitmap.copy(Bitmap.Config.RGB_565, true); 
      Canvas canvas = new Canvas(finalBitmap); 

      Bitmap overlayBitmap = null; 
      if (mWeaponType == wep1) { 
       overlayBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.wep1); 
      } else if (mWeaponType == wep2) { 
       overlayBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.wep2); 
      } 

      if (overlayBitmap != null) { 

       matrix = new Matrix(); 
       matrix.postRotate(90); 
       Bitmap resizedOverlay = Bitmap.createBitmap(overlayBitmap, 0, 0, overlayBitmap.getWidth(), overlayBitmap.getHeight(), matrix, true); 
       canvas.drawBitmap(resizedOverlay, 0, 0, new Paint()); 
       canvas.scale(50, 0); 
       canvas.save(); 
       //finalBitmap is the image with the overlay on it 

       // rotate image to save in landscape mode 
       matrix = new Matrix(); 
       matrix.postRotate(270); 
       finalBitmap = Bitmap.createBitmap(finalBitmap, 0, 0, finalBitmap.getWidth(), finalBitmap.getHeight(), matrix, 
         true); 

       // convert final bitmap to byte array 
       ByteArrayOutputStream stream = new ByteArrayOutputStream(); 
       finalBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); 
       byteArray = stream.toByteArray(); 
      } 
     } 

     catch(OutOfMemoryError e) { 
      //fail 
     } 

     try { 
       FileOutputStream fos = new FileOutputStream(pictureFile); 
       fos.write(byteArray); 
       fos.close(); 

       // Notify system that SD card has been updated 
       sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory()))); 
       Log.i(TAG, "Picture saved, intent broadcast that SD has been updated"); 
     } catch (FileNotFoundException e) { 
      Log.d(TAG, "File not found: " + e.getMessage()); 
     } catch (IOException e) { 
      Log.d(TAG, "Error accessing file: " + e.getMessage()); 
     } catch (NullPointerException e) { 

     } 

     finally { 
      mCamera.startPreview(); 
      captureBtn.setVisibility(ImageButton.VISIBLE); 
     } 
    } 
}; 

Я получаю NullPointerException следующим образом:

java.lang.NullPointerException 
at java.io.FileOutputStream.write(FileOutputStream.java:256) 
at com.mypackage.MyActivity.onPictureTaken(MyActivity.java:215) 

который является

fos.write(byteArray); 

линия.

getOutputMediaFile метод перечисленных выше выглядит следующим образом:

/** Create a File for saving an image or video */ 
private static File getOutputMediaFile(int type){ 
    // To be safe, you should check that the SDCard is mounted 
    // using Environment.getExternalStorageState() before doing this. 

    File mediaStorageDir = Environment.getExternalStoragePublicDirectory(
       Environment.DIRECTORY_PICTURES); 

    // Create the storage directory if it does not exist 
    if (! mediaStorageDir.exists()){ 
     if (! mediaStorageDir.mkdirs()){ 
      Log.d("HalfLife2 Booth", "failed to create directory"); 
      return null; 
     } 
    } 

    // Create a media file name 
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); 
    File mediaFile; 
    if (type == MEDIA_TYPE_IMAGE){ 
     mediaFile = new File(mediaStorageDir.getPath() + File.separator + 
     "IMG_"+ timeStamp + ".jpg"); 
    } else if(type == MEDIA_TYPE_VIDEO) { 
     mediaFile = new File(mediaStorageDir.getPath() + File.separator + 
     "VID_"+ timeStamp + ".mp4"); 
    } else { 
     return null; 
    } 

    return mediaFile; 
} 

Я думаю, что проблема может быть где-то здесь, в попытке получить выходной файл мультимедиа. Я пытался обновить приложение, чтобы использовать:

File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
       Environment.DIRECTORY_PICTURES), "MyApp"); 

вместо этого, и один пользователь сообщил о проблеме, чтобы быть фиксированной, но некоторые из них сообщили, что она сохраняется.

Любые идеи, кто-нибудь? Я нахожу это сложным для отладки/исправления, когда я не могу воспроизвести или приблизиться к нему.

+0

макияж конечно, у вас есть в манифесте –

+0

Я думаю, что проблема возникла бы на всех телефонах, если бы разрешение не было установлено. –

+0

Правильно, разрешение установлено правильно. – breadbin

ответ

2

Убедитесь, что вы масштабируете свои изображения в необработанном формате. Я обнаружил, что необработанные изображения ОГРОМНЫ на некоторых моделях телефонов. Я рекомендую масштабировать изображение, если оно очень велико, потому что вы запустите свою виртуальную машину из памяти.

Пример:

 imageRef = sd_card_path+"/"+ImageName; 
       BitmapFactory.Options resample = new BitmapFactory.Options(); 
       resample.inJustDecodeBounds = true; 
       BitmapFactory.decodeFile(imageRef, resample); 
       int width = resample.outWidth; 
       int height = resample.outHeight; 
       if(width*height > utility.IMAGE_SIZE_MIN){ 
        int imageSizef = (int)(width*height/utility.IMAGE_SIZE_MIN); 
        String imageSize = imageSizef+""; 
        resample.inSampleSize = Integer.parseInt(imageSize); 
        resample.inJustDecodeBounds = false; 
        image.setImageBitmap(BitmapFactory.decodeFile(imageRef , resample));      
       }else{ 
        image.setImageBitmap(BitmapFactory.decodeFile(imageRef)); 
       } 
+0

Хорошо, спасибо за ваше предложение! Как я могу добиться этого? – breadbin

+0

Я понимаю, что пример использует файл, так что вот строка прямо из потока камеры: Bitmap bitmap = BitmapFactory.decodeByteArray (изображение, 0, image.length, resample); –

+0

Спасибо Android Addict, могу ли я спросить вас, что такое ваш объект «utility», и откуда взялось значение для вашего «IMAGE_SIZE_MIN»? – breadbin

1

Учитывая Exception проследить, что позволяет предположить, что вы поражая OutOfMemorryError и как таковой ByteArray, никогда не получать заселена, так что вы передаете нуль в fos.write метод

+0

Это правильно, есть более полное объяснение проблемы в принятом ответе. Спасибо за помощь. – breadbin

Смежные вопросы