我一直在尝试使用Service
类并使用Camera API
创建背景视频记录器。当我运行应用程序时,一切似乎都运行正常。但是,当我停止服务时,我的应用程序会抛出ANR。使用DDMS tool
后,按下停止录制按钮后,我发现了有关main
主题的以下信息:
at android.media.MediaRecorder.stop(Native Method)
at com.svtech.thirdeye.thirdeye.Services.VideoRecordingOldApiService.stopRecording(VideoRecordingOldApiService.java:212)
at com.svtech.thirdeye.thirdeye.Services.VideoRecordingOldApiService.onDestroy(VideoRecordingOldApiService.java:250)
at android.app.ActivityThread.handleStopService(ActivityThread.java:2877)
at android.app.ActivityThread.access$2000(ActivityThread.java:162)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1466)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5371)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:833)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
at dalvik.system.NativeStart.main(Native Method)
我的onDestroy()
类的Service
方法代码如下:
@Override
public void onDestroy() {
super.onDestroy();
if (linearLayout != null) {
windowManager.removeView(linearLayout);
linearLayout = null;
}
mMediaRecorder.stop();
if (mMediaRecorder != null) {
mMediaRecorder.reset();
mMediaRecorder.release();
mMediaRecorder = null;
}
if (mCamera != null) {
mCamera.release();
mCamera.lock();
mCamera = null;
}
}
编辑:已整改Service
班级
public class VideoRecordingOldApiService extends Service implements SurfaceHolder.Callback {
private Camera mCamera;
private String outputFile;
private MediaRecorder mMediaRecorder;
private CameraCheck cameraCheck;
private final static String TAG = "VideoRecorderService";
private LinearLayout linearLayout;
private SurfaceView surfaceView;
private SurfaceHolder surfaceHolder;
private WindowManager windowManager;
private Thread thread;
private Handler handler;
public VideoRecordingOldApiService() {
}
@Override
public void onCreate() {
linearLayout = (LinearLayout) LayoutInflater.from(this).inflate(R.layout.surfaceview_layout, null);
linearLayout.setLayoutParams(new LinearLayout.LayoutParams(
getResources().getDimensionPixelSize(R.dimen.textureView_width), getResources().getDimensionPixelSize(R.dimen.textureView_height)));
windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
PixelFormat.OPAQUE
);
layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
windowManager.addView(linearLayout, layoutParams);
surfaceView = (SurfaceView) linearLayout.findViewById(R.id.videoSurfaceView);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
cameraCheck = new CameraCheck();
handler = new Handler();
//Setup Notification
final Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);
notificationIntent.addCategory("android.intent.category.LAUNCHER");
final PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification;
notification = new Notification.Builder(getApplicationContext())
.setSmallIcon(R.drawable.videorecordicon)
.setOngoing(true)
.setPriority(Notification.PRIORITY_DEFAULT)
.setContentTitle(getResources().getString(R.string.video_recorder_notification))
.setContentText(getResources().getString(R.string.notification_video_text) + "...")
.setContentIntent(pendingIntent).build();
startForeground(1, notification);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (initCamera()) {
thread = new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
if (initRecorder()) {
mMediaRecorder.start();
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), R.string.video_recorder_started, Toast.LENGTH_LONG).show();
}
});
} else {
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "Couldn't start MediaRecorder", Toast.LENGTH_LONG).show();
}
});
}
}
});
thread.start();
} else {
Toast.makeText(getApplicationContext(), "Camera not found", Toast.LENGTH_SHORT).show();
}
return START_REDELIVER_INTENT;
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
public String getFileName() {
String fileName = null;
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
fileName = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
+ "/" + "video_record" + System.currentTimeMillis() + ".mp4";
Log.i("Camera Recorder", fileName);
} else {
Toast.makeText(getApplicationContext(), "No External Storage Found", Toast.LENGTH_LONG).show();
}
return fileName;
}
private boolean initCamera() {
try {
mCamera = cameraCheck.getDesiredCamera(this, Camera.CameraInfo.CAMERA_FACING_BACK);
Camera.Parameters parameters = mCamera.getParameters();
parameters.setRecordingHint(true);
Camera.Size previewSize = getOptimalPreviewSize(parameters.getSupportedPreviewSizes(),
surfaceView.getWidth(), surfaceView.getHeight());
parameters.setPreviewSize(previewSize.width, previewSize.height);
mCamera.setDisplayOrientation(90);
} catch (Exception e) {
Log.v(TAG, "Could not initialise the camera");
e.printStackTrace();
return false;
}
return true;
}
private boolean initRecorder() {
mMediaRecorder = new MediaRecorder();
outputFile = getFileName();
CamcorderProfile profile = CamcorderProfile.get(Camera.CameraInfo.CAMERA_FACING_BACK, CamcorderProfile.QUALITY_HIGH);
profile.videoFrameWidth = mCamera.getParameters().getSupportedVideoSizes().get(1).width;
profile.videoFrameHeight = mCamera.getParameters().getSupportedVideoSizes().get(1).height;
profile.fileFormat = MediaRecorder.OutputFormat.MPEG_4;
profile.audioCodec = MediaRecorder.AudioEncoder.AAC;
profile.videoCodec = MediaRecorder.VideoEncoder.H264;
try {
mCamera.unlock();
mMediaRecorder.setCamera(mCamera);
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mMediaRecorder.setProfile(profile);
mMediaRecorder.setOutputFile(outputFile);
//mMediaRecorder.setPreviewDisplay(surfaceHolder.getSurface());
mMediaRecorder.prepare();
Log.v(TAG, "MediaRecorder initialized successfully");
} catch (Exception e) {
Log.v(TAG, "MediaRecorder failed to initialize");
e.printStackTrace();
return false;
}
return true;
}
private void releaseCamera() {
if (mCamera != null) {
mCamera.lock();
mCamera.release();
mCamera = null;
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (!thread.isInterrupted()) {
thread.interrupt();
Toast.makeText(getApplicationContext(), R.string.recording_done, Toast.LENGTH_LONG).show();
}
if (linearLayout != null) {
windowManager.removeView(linearLayout);
linearLayout = null;
}
stopForeground(true);
releaseCamera();
thread = null;
}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) h / w;
if (sizes == null)
return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.Size size : sizes) {
double ratio = (double) size.height / size.width;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
有人可以帮我弄清楚为什么我在Mediarecoder的onStop()
方法上得到ANR? DDMS工具对main
线程???
答案 0 :(得分:3)
public static void wall(Location l){
Player p = null;
for(Player players: Bukkit.getOnlinePlayers()){
if (players.getLocation().equals(l)){
p = players;
}
else{
return;
}
}
的生命周期回调始终在应用的主线程上调用。 Service
在&#34;背景&#34;中运行仅来自用户感知的观点。如果您想要真正的后台操作,则需要使用自己的线程。对Service
的调用是一个阻塞调用,因为它正在与媒体服务器进程通话,告诉它停止操作。这花费的时间太长(其他主要线程操作被阻止等待),系统会为您的应用声明ANR并将其杀死。