我在使用SurfaceView进行相当简单的Android相机预览时遇到了问题。 我不知道为什么,但只要SurfaceView大小/位置落在可见区域之外,预览就会开始闪烁。如果相机看到的物体在移动,则强度会增加。
设备:Nexus 7(第一版),Android 4.4.2 针对API16的应用程序。
一旦闪烁发生,在日志中会显示如下所示的大量信息:
I/hwcomposer( 127): Setting interactive mode: Off
I/hwcomposer( 127): Setting interactive mode: On
I/hwcomposer( 127): Setting interactive mode: Off
I/hwcomposer( 127): Setting interactive mode: On
I/hwcomposer( 127): Setting interactive mode: Off
问题始于Sony Tablet Z,并在Nexus 7上重现。 出于某种原因,我不想在这里讨论如果预览区域落在可见区域之外,我没有完全控制。正如您所看到的,即使是(-100,-100)左/上边距的小预览也会导致问题。
该应用程序非常简单。只有一个类和XML布局文件:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<!--
android:layout_width="1022px"
android:layout_height="1363px"
android:layout_marginLeft="0px"
android:layout_marginTop="0px"
-->
<FrameLayout
android:id="@+id/camera_preview_container"
android:layout_width="500px"
android:layout_height="500px"
android:layout_marginLeft="-100px"
android:layout_marginTop="-100px">
<SurfaceView
android:id="@+id/surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
</FrameLayout>
和活动代码:
package com.example.surfaceviewtest;
import java.io.IOException;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Size;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.view.Menu;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
public class MainActivity extends Activity implements SurfaceHolder.Callback {
private final String TAG = "com.example.surfaceviewtest";
private Camera camera;
private boolean isPreviewing = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((SurfaceView)this.findViewById(R.id.surface_view)).getHolder().addCallback(this);
}
@Override
protected void onResume() {
Log.d(TAG, "onResume");
super.onResume();
camera = Camera.open(0);
Camera.Parameters cameraParameters = camera.getParameters();
Size previewSize = cameraParameters.getPreviewSize();
Log.d(TAG, String.format("Preview size: width %d height %d", previewSize.width, previewSize.height));
Size pictureSize = cameraParameters.getPictureSize();
Log.d(TAG, String.format("Picture size: width %d height %d", pictureSize.width, pictureSize.height));
/*cameraParameters.setPictureSize(320, 240);
cameraParameters.setPreviewSize(176, 144);
camera.setParameters(cameraParameters);*/
}
@Override
protected void onPause() {
Log.d(TAG, "onPause");
super.onPause();
stopPreview();
camera.release();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.d(TAG, "surfaceCreated");
try {
setCameraDisplayOrientation();
setCameraOrientation();
camera.setPreviewDisplay(holder);
startPreview();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Log.d(TAG, String.format ("surfaceChanged: format %d width %d height %d", format, width, height));
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "surfaceDestroyed");
stopPreview();
}
private void startPreview() {
if (isPreviewing)
return;
camera.startPreview();
}
private void stopPreview() {
if (isPreviewing == false)
return;
camera.stopPreview();
isPreviewing = false;
}
public int getDisplayOrientation() {
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(0, info);
int rotation = ((WindowManager) getSystemService(
Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
int degrees = orientationToAngle(rotation);
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
return result;
}
protected void setCameraDisplayOrientation() {
int rotation = getDisplayOrientation();
camera.setDisplayOrientation(rotation);
}
protected static int orientationToAngle(int orientation) {
switch (orientation) {
case Surface.ROTATION_0:
return 0;
case Surface.ROTATION_90:
return 90;
case Surface.ROTATION_180:
return 180;
case Surface.ROTATION_270:
return 270;
}
return 0;
}
protected void setCameraOrientation() {
int orientation = ((WindowManager) getSystemService(
Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
int degrees = orientationToAngle(orientation);
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(0, info);
degrees = (degrees + 45) / 90 * 90;
int rotation = 0;
if (info.facing != CameraInfo.CAMERA_FACING_FRONT) {
rotation = (info.orientation - degrees + 360) % 360;
} else {
rotation = (info.orientation + degrees) % 360;
}
Camera.Parameters parameters = camera.getParameters();
parameters.setRotation(rotation);
camera.setParameters(parameters);
}
}