在Glass GDK应用程序中获取相机时出现间歇性错误.该应用程序是一个简单的应用程序:
响应语音触发("测试相机")
启动活动以拍摄快照
返回调用Activity以显示快照.
问题是该应用程序可以正常工作,但它不时会一次又一次地获取相机.我已经将多个try/catch块中的相机调用完成处理(如果它无法获取相机,应用程序就会退出),但我想知道为什么它首先发生.
除了以下内容,我不会担心这个问题:
我注意到这些错误经常发生在我用"拍照"语音提示拍摄照片后启动应用程序(好像"拍照"应用程序没有释放相机.)
我投入了很多次尝试/捕获以防止每次不良的相机通话,但是......在我这样做之前,(即当我的代码不那么专注于释放相机时),设备会变得非常温暖,以至于我不得不把它关掉再打开以确保我没有损坏它.
我在日志中看到的唯一奇怪的事情是以下消息.我不知道"未知消息类型8192"可能是什么
11-29 19:38:16.344: E/Camera(4551): Received CAMERA_MSG_RELEASE 11-29 19:38:16.493: D/Camera-JNI(4551): android_hardware_Camera_release - context->decStrong(thiz) 11-29 19:38:16.524: E/Camera(4551): Unknown message type 8192
因为我不知道是什么导致了这个,所以我将发布整个项目,看看是否有一些xml文件或其他可能造成这种情况的模糊不清的地方.
这是清单:
这是语音触发器:
以下是字符串:
TestCamera Settings Hello world! test the camera Done Tap for options
以下是主要活动的布局:
以下是相机活动的布局:
以下是主要活动的代码:
package com.example.testcamera; import java.io.File; import com.google.android.glass.touchpad.Gesture; import com.google.android.glass.touchpad.GestureDetector; import android.os.Bundle; import android.os.Handler; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Point; import android.speech.tts.TextToSpeech; import android.util.Log; import android.view.Display; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; public class MainActivity extends Activity { // App responds to voice trigger "test the camera", takes a picture with CameraActivity and then returns. private static final String TAG = MainActivity.class.getSimpleName(); private static final int TAKE_PHOTO_CODE = 1; private static final int PROGRESS_TIMEOUT = 30000; // in ms --> 10s private static final String IMAGE_FILE_NAME = "/sdcard/ImageTest.jpg"; private boolean picTaken = false; // flag to indicate if we just returned from the picture taking intent private String theImageFile = ""; // this holds the name of the image that was returned by the camera private TextView text1; private TextView text2; private ProgressBar myProgressBar; protected boolean mbActive; private String inputQueryString; private String queryCategory; final Handler myHandler = new Handler(); // handles looking for the returned image file private int numberOfImageFileAttempts = 0; private String responseBody = ""; private TextToSpeech mSpeech; private boolean readyForMenu = false; private boolean gotImageMatch = false; private GestureDetector mGestureDetector; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.v(TAG,"creating activity"); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); setContentView(R.layout.activity_main); text1 = (TextView) findViewById(R.id.text1); text2 = (TextView) findViewById(R.id.text2); text1.setText(""); text2.setText(""); myProgressBar = (ProgressBar) findViewById(R.id.my_progressBar); LinearLayout llResult = (LinearLayout) findViewById(R.id.resultLinearLayout); TextView tvResult = (TextView) findViewById(R.id.tap_instruction); llResult.setVisibility(View.INVISIBLE); tvResult.setVisibility(View.INVISIBLE); myProgressBar.setVisibility(View.INVISIBLE); // Even though the text-to-speech engine is only used in response to a menu action, we // initialize it when the application starts so that we avoid delays that could occur // if we waited until it was needed to start it up mSpeech = new TextToSpeech(this, new TextToSpeech.OnInitListener() { @Override public void onInit(int status) { // Do nothing. } }); mGestureDetector = createGestureDetector(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override protected void onResume() { super.onResume(); if (!picTaken) { Intent intent = new Intent(this, CameraActivity.class); intent.putExtra("imageFileName",IMAGE_FILE_NAME); startActivityForResult(intent,1); } else { // do nothing } } /* * Send generic motion events to the gesture detector */ @Override public boolean onGenericMotionEvent(MotionEvent event) { if (mGestureDetector != null) { return mGestureDetector.onMotionEvent(event); } return false; } private GestureDetector createGestureDetector(Context context) { GestureDetector gestureDetector = new GestureDetector(context); //Create a base listener for generic gestures gestureDetector.setBaseListener( new GestureDetector.BaseListener() { @Override public boolean onGesture(Gesture gesture) { if (gesture == Gesture.TAP) { // do something on tap Log.v(TAG,"tap"); //if (readyForMenu) { openOptionsMenu(); //} return true; } else if (gesture == Gesture.TWO_TAP) { // do something on two finger tap return true; } else if (gesture == Gesture.SWIPE_RIGHT) { // do something on right (forward) swipe return true; } else if (gesture == Gesture.SWIPE_LEFT) { // do something on left (backwards) swipe return true; } return false; } }); gestureDetector.setFingerListener(new GestureDetector.FingerListener() { @Override public void onFingerCountChanged(int previousCount, int currentCount) { // do something on finger count changes } }); gestureDetector.setScrollListener(new GestureDetector.ScrollListener() { @Override public boolean onScroll(float displacement, float delta, float velocity) { // do something on scrolling return false; } }); return gestureDetector; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.stop: finish(); return true; default: return super.onOptionsItemSelected(item); } } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); picTaken = true; switch(requestCode) { case (1) : { if (resultCode == Activity.RESULT_OK) { // TODO Extract the data returned from the child Activity. Log.v(TAG,"onActivityResult"); File f = new File(IMAGE_FILE_NAME); if (f.exists()) { Log.v(TAG,"image file from camera was found"); Bitmap b = BitmapFactory.decodeFile(IMAGE_FILE_NAME); Log.v(TAG,"bmp height=" + b.getHeight()); ImageView image = (ImageView) findViewById(R.id.bgPhoto); image.setImageBitmap(b); text1 = (TextView) findViewById(R.id.text1); text2 = (TextView) findViewById(R.id.text2); text1.setText("Got a picture."); text2.setText("\nSaved successfully to " + IMAGE_FILE_NAME); LinearLayout llResult = (LinearLayout) findViewById(R.id.resultLinearLayout); llResult.setVisibility(View.VISIBLE); TextView line1 = (TextView) findViewById(R.id.titleOfWork); TextView line2 = (TextView) findViewById(R.id.Singer); TextView tap = (TextView) findViewById(R.id.tap_instruction); line1.setText(""); line2.setText(""); tap.setVisibility(View.VISIBLE); } } else { Log.v(TAG,"onActivityResult returned bad result code"); finish(); } break; } } } @Override protected void onDestroy() { //Close the Text to Speech Library if(mSpeech != null) { mSpeech.stop(); mSpeech.shutdown(); mSpeech = null; Log.d(TAG, "TTS Destroyed"); } super.onDestroy(); } }
以下是相机活动的代码:
package com.example.testcamera; import java.io.BufferedOutputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.List; import android.app.Activity; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Bitmap.CompressFormat; import android.hardware.Camera; import android.hardware.Camera.Parameters; import android.os.Bundle; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.widget.ImageView; public class CameraActivity extends Activity implements SurfaceHolder.Callback { private static final String TAG = CameraActivity.class.getSimpleName(); public static final int BUFFER_SIZE = 1024 * 8; String imageFileName = ""; //a variable to store a reference to the Image View at the main.xml file. private ImageView iv_image; //a variable to store a reference to the Surface View at the main.xml file private SurfaceView sv; //a bitmap to display the captured image private Bitmap bmp; //Camera variables //a surface holder private SurfaceHolder sHolder; //a variable to control the camera private Camera mCamera; //the camera parameters private Parameters parameters; @Override public void onCreate(Bundle savedInstanceState) { Log.v(TAG,"onCreate"); super.onCreate(savedInstanceState); setContentView(R.layout.activity_camera); //get the Image View at the main.xml file iv_image = (ImageView) findViewById(R.id.imageView); sv = (SurfaceView) findViewById(R.id.surfaceView); //Get a surface sHolder = sv.getHolder(); sHolder.addCallback(this); Bundle extras = getIntent().getExtras(); // get the image file name from the caller to save the 640x360 image imageFileName = extras.getString("imageFileName"); } public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { Log.v(TAG,"surfaceChanged"); //get camera parameters try { parameters = mCamera.getParameters(); Log.v(TAG,"got parms"); //set camera parameters parameters.setPreviewSize(640,360); parameters.setPictureSize(1280,720); //Camera.Parameters params = mCamera.getParameters(); parameters.setPreviewFpsRange(30000, 30000); Log.v(TAG,"parms were set"); mCamera.setParameters(parameters); mCamera.startPreview(); Log.v(TAG,"preview started"); //sets what code should be executed after the picture is taken Camera.PictureCallback mCall = new Camera.PictureCallback() { public void onPictureTaken(byte[] data, Camera camera) { Log.v(TAG,"pictureTaken"); Log.v(TAG,"data bytes=" + data.length); //decode the data obtained by the camera into a Bitmap Bitmap bmp = decodeSampledBitmapFromData(data,640,360); Log.v(TAG,"bmp height=" + bmp.getHeight()); FileOutputStream outStream = null; try{ FileOutputStream fos = new FileOutputStream(imageFileName); final BufferedOutputStream bos = new BufferedOutputStream(fos, BUFFER_SIZE); bmp.compress(CompressFormat.JPEG, 100, bos); bos.flush(); bos.close(); fos.close(); } catch (FileNotFoundException e){ Log.v(TAG, e.getMessage()); } catch (IOException e){ Log.v(TAG, e.getMessage()); } Intent resultIntent = new Intent(); // TODO Add extras or a data URI to this intent as appropriate. resultIntent.putExtra("testString","here is my test"); setResult(Activity.RESULT_OK, resultIntent); finish(); } }; Log.v(TAG,"set callback"); mCamera.takePicture(null, null, mCall); } catch (Exception e) { try { mCamera.release(); Log.e(TAG,"released the camera"); } catch (Exception ee) { // do nothing Log.e(TAG,"error releasing camera"); Log.e(TAG,"Exception encountered relerasing camera, exiting:" + ee.getLocalizedMessage()); } Log.e(TAG,"Exception encountered, exiting:" + e.getLocalizedMessage()); mCamera = null; Intent resultIntent = new Intent(); setResult(Activity.RESULT_CANCELED, resultIntent); finish(); } } public static Bitmap decodeSampledBitmapFromData(byte[] data, int reqWidth, int reqHeight) { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeByteArray(data, 0, data.length,options); options.inSampleSize = 2; // saved image will be one half the width and height of the original (image captured is double the resolution of the screen size) // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; return BitmapFactory.decodeByteArray(data, 0, data.length,options); } public void surfaceCreated(SurfaceHolder holder) { Log.v(TAG,"surfaceCreated"); // The Surface has been created, acquire the camera and tell it where // to draw the preview. try { mCamera = Camera.open(); Log.v(TAG,"acquired the camera"); mCamera.setPreviewDisplay(holder); Log.v(TAG,"set surface holder for preview"); } catch (Exception e) { try { mCamera.release(); Log.v(TAG,"released the camera"); } catch (Exception ee) { // do nothing Log.e(TAG,"Exception encountered releasing camera, exiting:" + ee.getLocalizedMessage()); } Log.e(TAG,"Exception encountered, exiting:" + e.getLocalizedMessage()); mCamera = null; Intent resultIntent = new Intent(); setResult(Activity.RESULT_CANCELED, resultIntent); finish(); } } public void surfaceDestroyed(SurfaceHolder holder) { Log.v(TAG,"surfaceDestroyed"); if (mCamera != null) { mCamera.stopPreview(); //release the camera mCamera.release(); //unbind the camera from this object mCamera = null; } } @Override public void onPause() { Log.v(TAG,"onPause"); super.onPause(); if (mCamera != null) { mCamera.stopPreview(); //release the camera mCamera.release(); //unbind the camera from this object mCamera = null; } } @Override public void onDestroy() { Log.v(TAG,"onDestroy"); super.onDestroy(); if (mCamera != null) { mCamera.stopPreview(); //release the camera mCamera.release(); //unbind the camera from this object mCamera = null; } } }
我打赌这是一件简单的事情,我看不到......