camera.takePicture() 使我的应用程序崩溃

Posted

技术标签:

【中文标题】camera.takePicture() 使我的应用程序崩溃【英文标题】:camera.takePicture() is crashing my app 【发布时间】:2013-08-20 02:28:25 【问题描述】:

我有一个应该使用 camera.takePicture 拍照的应用程序。我使用的代码如下:

private Bitmap bitmapPicture;
//inside onCreate
btn.setOnClickListener(new OnClickListener()

    public void onClick(View v)
        camera.takePicture(myShutterCallback, 
                myPictureCallback_RAW, myPictureCallback_JPG);
    
    );


 //inside the activity
 ShutterCallback myShutterCallback = new ShutterCallback()

@Override
public void onShutter() 
    // TODO Auto-generated method stub

;

PictureCallback myPictureCallback_RAW = new PictureCallback()

@Override
public void onPictureTaken(byte[] arg0, Camera arg1) 
    // TODO Auto-generated method stub

;

PictureCallback myPictureCallback_JPG = new PictureCallback()

@Override
public void onPictureTaken(byte[] arg0, Camera arg1) 
    // TODO Auto-generated method stub
    bitmapPicture = BitmapFactory.decodeByteArray(arg0, 0, arg0.length);
;

当我单击快门声音播放的按钮时,surfaceView 上的图像冻结但随后应用程序崩溃。为什么会这样?当我在带有模拟相机的模拟器上运行它时,它可以正常工作,但在设备上却崩溃了。

【问题讨论】:

但 avd 不会崩溃。仅读取设备。 【参考方案1】:

使用这个简单的代码使用设备相机进行捕捉

IMP 注意:将这些权限添加到 mainfest 文件中

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />

主活动

public class MainActivity extends Activity 

private static final int CAMERA_PIC_REQUEST = 1111;//Constant ID for ActivityResult
private ImageView mImage; // To display the thumbnail

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mImage = (ImageView) findViewById(R.id.camera_image);

    // Start an intent for Camera Capture with ResultActivity
    Intent cameraIntent = new Intent(
            android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    startActivityForResult(cameraIntent, CAMERA_PIC_REQUEST);



@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) 
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == CAMERA_PIC_REQUEST) 
        // Get the image in a Bitmap extension to assign it to the ImageView
        if (data.getExtras() == null)
            return;
        Bitmap thumb = (Bitmap) data.getExtras().get("data");
        mImage.setImageBitmap(thumb);

        // Compress the Bitmap image into JPEG to save it on the device
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        thumb.compress(Bitmap.CompressFormat.JPEG, 100, bytes);// 100 is the scale..for less quality decrease the number                                

        // Save the image on the root SDCard
        File file = new File(Environment.getExternalStorageDirectory()
                + File.separator + "imageName.png");

        try 
            // Create the file to save the image
            file.createNewFile();
            FileOutputStream fo = new FileOutputStream(file);
            fo.write(bytes.toByteArray());
            fo.close();
         catch (Exception e) 
        

    




把它放在你的布局 MainActivity.XML 中:

    <ImageView android:id="@+id/camera_image"
    android:layout_ android:layout_ />

【讨论】:

我正在寻找的是一种无需使用手机相机应用程序的意图即可拍照并保存的方法。 除了您的代码以缩略图的质量保存图片 我的代码将图像保存在设备上并将其显示为布局中的缩略图......而且您在问题中也没有明确提及意图问题。我希望这可能会有所帮助【参考方案2】:

我终于解决了这个问题。下面我为任何想知道如何截取布局的屏幕截图、无意从相机拍摄的图片、surfaceView 内容的屏幕截图(某种)并将屏幕截图保存在文件夹中的人提供一些代码:

public class Cam_View extends Activity implements SurfaceHolder.Callback

protected static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 0;
private SurfaceView SurView;
private SurfaceHolder camHolder;
private boolean previewRunning;
final Context context = this;
public static Camera camera = null;
private RelativeLayout CamView;
private Bitmap inputBMP=null,bmp,bmp1;
private ImageView mImage;




@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.camera);

    CamView = (RelativeLayout) findViewById(R.id.camview);//RELATIVELAYOUT OR 
                                                          //ANY LAYOUT OF YOUR XML

    SurView = (SurfaceView)findViewById(R.id.sview);//SURFACEVIEW FOR THE PREVIEW 
                                                    //OF THE CAMERA FEED
    camHolder = SurView.getHolder();                           //NEEDED FOR THE PREVIEW
    camHolder.addCallback(this);                               //NEEDED FOR THE PREVIEW
    camHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//NEEDED FOR THE PREVIEW
    camera_image = (ImageView) findViewById(R.id.camera_image);//NEEDED FOR THE PREVIEW



    Button btn = (Button) findViewById(R.id.button1); //THE BUTTON FOR TAKING PICTURE



    btn.setOnClickListener(new OnClickListener()     //THE BUTTON CODE
    
        public void onClick(View v)
        
                  camera.takePicture(null, null, mPicture);//TAKING THE PICTURE
                                                         //THE mPicture IS CALLED 
                                                         //WHICH IS THE LAST METHOD(SEE BELOW)
            

        );

    


@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,//NEEDED FOR THE PREVIEW
    int height) 
if(previewRunning)
    camera.stopPreview();

Camera.Parameters camParams = camera.getParameters();
Camera.Size size = camParams.getSupportedPreviewSizes().get(0); 
    camParams.setPreviewSize(size.width, size.height);
camera.setParameters(camParams);
try
    camera.setPreviewDisplay(holder);
    camera.startPreview();
    previewRunning=true;
catch(IOException e)
    e.printStackTrace();



public void surfaceCreated(SurfaceHolder holder)                   //NEEDED FOR THE PREVIEW
try
    camera=Camera.open();
catch(Exception e)
    e.printStackTrace();
    Toast.makeText(getApplicationContext(),"Error",Toast.LENGTH_LONG).show();
    finish();



@Override
public void surfaceDestroyed(SurfaceHolder holder)              //NEEDED FOR THE PREVIEW
camera.stopPreview();
camera.release();
camera=null;




public void TakeScreenshot()    //THIS METHOD TAKES A SCREENSHOT AND SAVES IT AS .jpg

Random num = new Random();
int nu=num.nextInt(1000); //PRODUCING A RANDOM NUMBER FOR FILE NAME
CamView.setDrawingCacheEnabled(true); //CamView OR THE NAME OF YOUR LAYOUR
CamView.buildDrawingCache(true);
Bitmap bmp = Bitmap.createBitmap(CamView.getDrawingCache());
CamView.setDrawingCacheEnabled(false); // clear drawing cache
                ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
                bmp.compress(CompressFormat.JPEG, 100, bos); 
                byte[] bitmapdata = bos.toByteArray();
                ByteArrayInputStream fis = new ByteArrayInputStream(bitmapdata);

                String picId=String.valueOf(nu);
                String myfile="Ghost"+picId+".jpeg";

                File dir_image = new  File(Environment.getExternalStorageDirectory()+//<---
                        File.separator+"Ultimate Entity Detector");          //<---

                dir_image.mkdirs();                                                  //<---
                    //^IN THESE 3 LINES YOU SET THE FOLDER PATH/NAME . HERE I CHOOSE TO SAVE
                    //THE FILE IN THE SD CARD IN THE FOLDER "Ultimate Entity Detector"

                try 
                    File tmpFile = new File(dir_image,myfile); 
                    FileOutputStream fos = new FileOutputStream(tmpFile);

                     byte[] buf = new byte[1024];
                        int len;
                        while ((len = fis.read(buf)) > 0) 
                            fos.write(buf, 0, len);
                        
                            fis.close();
                            fos.close();

                            Toast.makeText(getApplicationContext(),
                                    "The file is saved at :SD/Ultimate Entity Detector",Toast.LENGTH_LONG).show();

                            bmp1 = null;
                            camera_image.setImageBitmap(bmp1); //RESETING THE PREVIEW
                            camera.startPreview();             //RESETING THE PREVIEW       
                 catch (FileNotFoundException e) 
                    e.printStackTrace();
                 catch (IOException e) 
                    e.printStackTrace();
                




private PictureCallback mPicture = new PictureCallback()    //THIS METHOD AND THE METHOD BELOW
                             //CONVERT THE CAPTURED IMAGE IN A JPG FILE AND SAVE IT

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

    File dir_image2 = new  File(Environment.getExternalStorageDirectory()+
            File.separator+"Ultimate Entity Detector");
    dir_image2.mkdirs();  //AGAIN CHOOSING FOLDER FOR THE PICTURE(WHICH IS LIKE A SURFACEVIEW 
                            //SCREENSHOT)



    File tmpFile = new File(dir_image2,"TempGhost.jpg"); //MAKING A FILE IN THE PATH                 
                    //dir_image2(SEE RIGHT ABOVE) AND NAMING IT "TempGhost.jpg" OR ANYTHING ELSE
    try //SAVING
        FileOutputStream fos = new FileOutputStream(tmpFile);
        fos.write(data);
        fos.close();
        //grabImage();
     catch (FileNotFoundException e) 
        Toast.makeText(getApplicationContext(),"Error",Toast.LENGTH_LONG).show();
     catch (IOException e) 
        Toast.makeText(getApplicationContext(),"Error",Toast.LENGTH_LONG).show();
    

    String path = (Environment.getExternalStorageDirectory()+  
            File.separator+"Ultimate EntityDetector"+
                                        File.separator+"TempGhost.jpg");//<---

    BitmapFactory.Options options = new BitmapFactory.Options();//<---
    options.inPreferredConfig = Bitmap.Config.ARGB_8888;//<---
    bmp1 = BitmapFactory.decodeFile(path, options);//<---
    //THE LINES ABOVE READ THE FILE WE SAVED BEFORE AND CONVERT IT INTO A BitMap
    camera_image.setImageBitmap(bmp1); //SETTING THE BitMap AS IMAGE IN AN IMAGEVIEW(SOMETHING
                                //LIKE A BACKGROUNG FOR THE LAYOUT)
    TakeScreenshot();//CALLING THIS METHOD TO TAKE A SCREENSHOT


;
 

如果你想拍一张简单的截图(不需要摄像头),你可以单独使用 TakeScreenshot 方法。

如果你想截取一个surfaceView的截图是不可能直接从surfaceview做的,使用mPicture,将你捕获的图片设置为backgroung,然后调用TakeScreenshot来截取你的截图。(如上所示)

如果您想用相机拍照而不用意图调用其他相机应用,请使用上面代码中的带有 mPicture 和 surfaceView 内容的 takePicture。

如果“按原样”使用,前面的代码的作用是截取布局内容(按钮、图像视图等)并将来自相机的图像设置为背景。

下面我还为之前的代码提供了一个基本的布局xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_   
android:id="@+id/camview">

<SurfaceView
    android:id="@+id/sview"
    android:layout_
    android:layout_
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true" />

<ImageView
    android:id="@+id/camera_image"
    android:layout_
    android:layout_
    android:contentDescription="@string/app_name" />



<Button
    android:id="@+id/button1"
    style="?android:attr/buttonStyleSmall"
    android:layout_
    android:layout_
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true" />


</RelativeLayout>

【讨论】:

这给了我 java.lang.NullPointerException【参考方案3】:

只需添加一个回调即可在您的相机实例上开始预览。问题是在相机实例上开始预览后,需要一些时间才能拍照。试试这个:

       camera.startPreview();
        camera.setOneShotPreviewCallback(new Camera.PreviewCallback() 
            @Override
            public void onPreviewFrame(byte[] data, Camera camera) 
                camera.takePicture(null, null, new Camera.PictureCallback() 
                    @Override
                    public void onPictureTaken(byte[] data, Camera camera) 
               // do something you want with your picture and stop preview
                        camera.stopPreview();
                    
                );

【讨论】:

以上是关于camera.takePicture() 使我的应用程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章

Android Camera.takePicture() 有时不返回?

Camera1 源码解析系列—— Camera1 takePicture() 流程解析

Camera1 源码解析系列—— Camera1 takePicture() 流程解析

Android Camera takePicture 正在使用 Previews 小缓冲区

android静音相机快门声音?

拍照并将其放置在画廊中