CoreJava(第六章)03-默认方法冲突、接口与回调和Comparator接口

本文深入探讨Java中接口冲突的解决策略,包括如何处理默认方法冲突和超类方法优先原则。同时,介绍了接口在回调机制中的应用,通过具体实例展示了如何使用Timer类和ActionListener接口实现定时操作。此外,还讲解了Comparator接口的使用,演示了如何按字符串长度进行排序。

1.解决默认方法冲突

场景一:

如果先在一个接口中将一个方法定义为默认方法,然后在另外一个接口中定义了同样的方法,会出现什么情况?

我们以接口:WoMan和Man;测试:Jane。

Man

public interface Man {
	
	default public void sleep() {
		System.out.println("男人都需要睡觉");
	}

}

WoMan

public interface WoMan {
	
	default public void sleep() {
		System.out.println("女人都需要睡觉");
	}

}

Jane

在这里插入图片描述

总结:

01-接口冲突

我们使用Jane实现两个接口(不同名,方法相同),Java编译器会报告一个错误,让我们自己来选择两个冲突方法中的一个。

场景二:

如果先在一个接口中将一个方法定义为默认方法,然后在超类(父类)中定义了同样的方法,会出现什么情况?

超类(父类)Person;接口Man;测试Jane

Person

public class Person {

	public  void sleep() {
		System.out.println("人都需要睡觉");
	}
}

Man

public interface Man {
	
	default public void sleep() {
		System.out.println("男人都需要睡觉");
	}

}

Jane

在这里插入图片描述

总结:

02-超类(父类)优先

通过控制台打印出来的是"人都需要睡觉",可以看出这段程序优先访问超类(父类)中的方法,由此可以证明:超类和接口都有相同的方法,则程序会优先访问超类中的方法。

2.接口与回调

01-回调概念

我们在执行程序后,程序会发生什么动作(程序会做哪些事情)。

02-举例说明

我们都知道 java.swing 包中有一个 Timer 类, 可以使用它在到达给定的时间间隔时发出通告 。

假如我们的程序中有一个时钟,我们通过请求来达到每秒钟获得一个通告,以便能够更新时钟的表盘(可以理解为秒针)。

这句话大意就是说:(当到达时间间隔时,需要做哪些操作)。

思路:

1)我们需要告诉定时器要做什么?定时器需要调用哪个方法,所以需要实现ActionListener这个接口。

2)我们需要构造一个对象,并将它传递给Timer构造器。

3)启动定时器。

代码:
package com.eleven.intefacee;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;

public class TimerTest {

	public static void main(String[] args) {
		ActionListener listener = new TimePrinter();
		Timer t = new Timer(10000, listener);	// 每隔10秒打印一次
		t.start();
		JOptionPane.showMessageDialog(null, "退出程序?");
		System.exit(0);
	}
}
/**
 * 当到达指定的时间间隔时,定时器就会调用actionPerformed方法
 * @author sywangu
 *
 */
class TimePrinter implements ActionListener{

	@Override
	public void actionPerformed(ActionEvent event) {
		System.out.println(new Date());
		Toolkit.getDefaultToolkit().beep();
	}
	
}

在这里插入图片描述

3.Comparator接口

01-按照长度比较字符串

package com.eleven.intefacee;

import java.util.Arrays;
import java.util.Comparator;

public class LengthComparator implements Comparator<String> {

	/**
	 * 按照长度比较字符串
	 */
	public int compare(String first, String second) {
		return first.length() - second.length();
	}

	public static void main(String[] args) {
		String[] friends = { "Peter", "Paul", "Mary" };
		
		System.out.println("排序前打印:");
		for (int i = 0; i < friends.length; i++) {
			System.out.print(friends[i] + " ");
		}
		
		System.out.println("\n排序后打印:");
		Arrays.sort(friends, new LengthComparator());
		for (int i = 0; i < friends.length; i++) {
			System.out.print(friends[i] + " ");
		}
	}

}

在这里插入图片描述

package com.android.example.cameraappxjava; import android.Manifest; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.ImageFormat; import android.graphics.SurfaceTexture; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraManager; import android.hardware.camera2.CaptureFailure; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.params.StreamConfigurationMap; import android.media.Image; import android.media.ImageReader; import android.net.Uri; import android.opengl.GLSurfaceView; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.SystemClock; import android.provider.MediaStore; import android.util.Log; import android.util.Size; import android.view.Surface; import android.widget.Button; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import com.android.example.cameraappxjava.util.CameraGLRenderer; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * 调用自定义渲染器的Demo:模拟YUV预览渲染 */ public class MainActivity2 extends AppCompatActivity { private static final String TAG = "camera2api"; private static final int REQUEST_CAMERA_PERMISSION = 100; // 1. 删除 TextureView 相关变量 // private TextureView textureView; // private boolean isTextureAvailable = false; // 2. 新增 GLSurfaceView + 自定义渲染器 private GLSurfaceView glSurfaceView; private CameraGLRenderer cameraGLRenderer; // 之前定义的自定义YUV渲染器 // 3. 新增:预览用 ImageReader(接收 Camera2 输出的 YUV 帧,给渲染器用) private ImageReader previewImageReader; // 4. 保留原有拍照用 ImageReader(JPEG格式,不修改) private ImageReader captureImageReader; // 5. 保留其他原有变量(相机设备、会话、按钮等) private Button captureButton; private CameraDevice cameraDevice; private CameraCaptureSession cameraCaptureSession; private CaptureRequest.Builder captureRequestBuilder; private String cameraId; private Handler backgroundHandler; private boolean isSessionClosed; private HandlerThread backgroundThread; private CameraManager manager; private volatile boolean isCapturing = false; private StreamConfigurationMap map; private long lastClickTime = 0; private static final long MIN_CLICK_INTERVAL = 1000; private File file; private ContentResolver resolver; private ContentValues values; private Uri imageUri; // ---------------------- 第三步:修改 onCreate(初始化 GLSurfaceView 渲染器) ---------------------- @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.d(TAG, "onCreate ——————————————————————"); // 1. 初始化 GLSurfaceView(替换原 TextureView) glSurfaceView = findViewById(R.id.glsurfaceView); // 2. 初始化拍照按钮(保留原有逻辑) captureButton = findViewById(R.id.btnCapture); // 3. 配置 GLSurfaceView + 自定义渲染器(核心) initGLRenderer(); // 4. 初始化相机参数(保留原有逻辑,但后续需补充预览ImageReader) initCamera(); // 5. 保留拍照按钮监听(原有逻辑不变) captureButton.setOnClickListener(v -> { long currentTime = SystemClock.elapsedRealtime(); if (currentTime - lastClickTime > MIN_CLICK_INTERVAL) { lastClickTime = currentTime; takePicture(); } else { Log.d(TAG, "点击过快,已忽略"); } }); } // ---------------------- 新增:初始化 GLSurfaceView 自定义渲染器 ---------------------- private void initGLRenderer() { // 1. 设置 OpenGL 版本(必须是 2.0,匹配渲染器着色器) glSurfaceView.setEGLContextClientVersion(2); // 2. 创建自定义渲染器实例 cameraGLRenderer = new CameraGLRenderer(); // 3. 绑定渲染器到 GLSurfaceView glSurfaceView.setRenderer(cameraGLRenderer); // 4. 按需渲染(有新帧才重绘,节省性能) glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); } // ---------------------- 第四步:修改 initCamera(新增预览用 ImageReader) ---------------------- private void initCamera() { Log.d(TAG, "initCamera: 初始化相机配置"); try { // 1. 保留原有逻辑:初始化 CameraManager、相机ID、配置Map manager = (CameraManager) getSystemService(CAMERA_SERVICE); cameraId = manager.getCameraIdList()[0]; CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); if (map == null) { Log.e(TAG, "错误: StreamConfigurationMap为空!!"); return; } // 2. 新增:初始化预览用 ImageReader(YUV_420_888 格式,给渲染器传数据) // 2.1 获取相机支持的 YUV 预览尺寸(用原有的尺寸选择逻辑) Size[] yuvSizes = map.getOutputSizes(ImageFormat.YUV_420_888); Size previewSize = chooseOptimalSize(yuvSizes, glSurfaceView.getWidth(), glSurfaceView.getHeight()); // 2.2 创建 ImageReader(尺寸=预览尺寸,格式=YUV_420_888,缓冲区=2) previewImageReader = ImageReader.newInstance( previewSize.getWidth(), previewSize.getHeight(), ImageFormat.YUV_420_888, 2 ); // 2.3 设置 ImageReader 回调(关键:获取 YUV 帧,传给渲染器) previewImageReader.setOnImageAvailableListener(reader -> { try (Image image = reader.acquireLatestImage()) { if (image == null || cameraGLRenderer == null) return; // 2.5 把 YUV 数据传给渲染器,触发重绘 cameraGLRenderer.setYUVData(image); glSurfaceView.requestRender(); // 触发渲染器 onDrawFrame } catch (Exception e) { Log.e(TAG, "预览帧处理失败: " + e.getMessage()); } }, backgroundHandler); // 在相机后台线程执行 // 3. 保留原有逻辑:初始化拍照用 ImageReader(JPEG格式) Size[] jpegSizes = map.getOutputSizes(ImageFormat.JPEG); Size captureSize = chooseOptimalSize(jpegSizes,glSurfaceView.getWidth(),glSurfaceView.getHeight()); if (captureImageReader == null || captureImageReader.getWidth() != captureSize.getWidth()) { if (captureImageReader != null) captureImageReader.close(); captureImageReader = ImageReader.newInstance( captureSize.getWidth(), captureSize.getHeight(), ImageFormat.JPEG, 2 ); } // 4. 保留原有逻辑:图片保存参数 resolver = getContentResolver(); values = new ContentValues(); values.put(MediaStore.Images.Media.DISPLAY_NAME, "pic_" + System.currentTimeMillis() + ".jpg"); values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg"); values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES); } catch (CameraAccessException e) { Log.e(TAG, "相机访问异常: " + e.getMessage()); } catch (NullPointerException e) { Log.e(TAG, "NPE: " + e.getMessage()); } } // ---------------------- 新增:提取 Image Plane 数据的工具方法 ---------------------- private byte[] extractPlaneData(Image.Plane plane) { ByteBuffer buffer = plane.getBuffer(); byte[] data = new byte[buffer.remaining()]; buffer.get(data); return data; } // ---------------------- 第五步:修改 openCamera(删除 TextureView 检查) ---------------------- private void openCamera() { // 1. 删除原 TextureView 相关检查(替换为 ImageReader 检查) if (previewImageReader == null || backgroundHandler == null) { Log.w(TAG, "预览ImageReader未就绪,延迟打开相机,1000ms后重试"); backgroundHandler.postDelayed(this::openCamera, 1000); return; } Log.d(TAG, "openCamera: 尝试打开相机"); try { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { Log.i(TAG, "1.打开相机: " + cameraId); manager.openCamera(cameraId, stateCallback, backgroundHandler); } else { Log.w(TAG, "相机权限未授予"); } } catch (CameraAccessException e) { Log.e(TAG, "打开相机失败: " + e.getMessage()); } catch (SecurityException e) { Log.e(TAG, "安全异常: " + e.getMessage()); } } // ---------------------- 第六步:修改 createCameraPreviewSession(替换预览 Surface) ---------------------- private void createCameraPreviewSession() { if (cameraDevice == null || previewImageReader == null) { Log.e(TAG, "创建预览会话失败: 相机或预览ImageReader不可用"); return; } try { // 1. 新增:获取预览 ImageReader 的 Surface(Camera2 输出目标) Surface previewSurface = previewImageReader.getSurface(); // 2. 保留:获取拍照 ImageReader 的 Surface Surface captureSurface = captureImageReader.getSurface(); // 3. 配置双输出 Surface(预览 + 拍照,替换原 TextureView 的 Surface) List<Surface> outputSurfaces = new ArrayList<>(2); outputSurfaces.add(previewSurface); // 预览:ImageReader 的 Surface(给渲染器) outputSurfaces.add(captureSurface); // 拍照:原有 ImageReader 的 Surface // 4. 保留原有逻辑:创建会话 + 配置预览请求 cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { Log.i(TAG, "2.2 预览会话配置成功"); cameraCaptureSession = session; try { // 配置预览请求(目标是预览 Surface) captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); captureRequestBuilder.addTarget(previewSurface); // 替换为 ImageReader 的 Surface // 保留原有自动对焦/闪光灯配置 captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); Log.i(TAG, "3.开始下发预览请求"); cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, backgroundHandler); } catch (CameraAccessException e) { Log.e(TAG, "设置预览请求失败: " + e.getMessage()); } } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { Log.e(TAG, "预览会话配置失败"); Toast.makeText(MainActivity2.this, "配置失败", Toast.LENGTH_SHORT).show(); } }, backgroundHandler); } catch (CameraAccessException e) { Log.e(TAG, "创建预览会话异常: " + e.getMessage()); } } // ---------------------- 第七步:修改生命周期方法(添加 GLSurfaceView 管理) ---------------------- @Override protected void onResume() { Log.d(TAG, "onResume —————————————————————— "); super.onResume(); // 1. 保留原有权限检查 if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { Log.i(TAG, "没有相机权限——>开始请求相机权限"); ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION); return; } // 2. 保留原有后台线程启动 startBackgroundThread(); // 3. 新增:恢复 GLSurfaceView(必须调用,否则渲染暂停) glSurfaceView.onResume(); // 4. 打开相机(替换原 TextureView 检查) openCamera(); } @Override protected void onPause() { super.onPause(); Log.d(TAG, "onPause ——————————————————————"); // 1. 新增:暂停 GLSurfaceView(必须调用,保存 OpenGL 上下文) glSurfaceView.onPause(); // 2. 保留原有预览暂停逻辑 if (!isCapturing && cameraCaptureSession != null) { try { cameraCaptureSession.stopRepeating(); Log.d(TAG, "onPause: 暂停预览重复请求(核心资源未释放)"); } catch (CameraAccessException e) { Log.e(TAG, "onPause: 停止预览失败", e); } } // 3. 保留原有拍照中延迟处理逻辑 if (isCapturing) { Log.w(TAG, "onPause: 拍照中,暂不处理预览暂停"); new Handler().postDelayed(() -> { if (!isCapturing && cameraCaptureSession != null) { try { cameraCaptureSession.stopRepeating(); Log.d(TAG, "onPause: 拍照完成后,暂停预览"); } catch (CameraAccessException e) { Log.e(TAG, "onPause: 延迟停止预览失败", e); } } }, 1000); } } @Override protected void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy: Activity 彻底销毁,释放所有资源"); // 1. 新增:释放预览 ImageReader 渲染器资源 if (previewImageReader != null) { previewImageReader.close(); } if (cameraGLRenderer != null) { cameraGLRenderer.release(); } // 2. 保留原有资源释放逻辑(相机、拍照ImageReader、线程等) if (cameraCaptureSession != null) { cameraCaptureSession.close(); cameraCaptureSession = null; } if (cameraDevice != null) { cameraDevice.close(); cameraDevice = null; } if (captureImageReader != null) { captureImageReader.close(); captureImageReader = null; } stopBackgroundThread(); // 3. 置空新增的引用 glSurfaceView = null; cameraGLRenderer = null; previewImageReader = null; // 4. 保留原有置空逻辑 captureButton = null; manager = null; resolver = null; values = null; imageUri = null; backgroundHandler = null; backgroundThread = null; Log.d(TAG, "onDestroy: 所有资源释放完成"); } private boolean checkTakePicture() { if (cameraDevice == null) { Log.w(TAG, "拍照失败: 相机未初始化"); return false; } // 1. 检查会话有效性 if (cameraCaptureSession == null) { Log.e(TAG, "拍照错误: CameraCaptureSession为空"); return false; } // 2. 检查后台Handler if (backgroundHandler == null) { Log.e(TAG, "拍照错误: backgroundHandler未初始化"); startBackgroundThread(); // 初始化方法见下方 return false; } if (isSessionClosed) { Log.e(TAG, "当前会话已关闭"); } return true; } // ---------------------- 第八步:修改 takePicture(替换拍照用 ImageReader) ---------------------- private void takePicture() { Log.i(TAG, "4.开始拍照流程——————————"); try { // 1. 保留原有检查逻辑 boolean checkFlag = checkTakePicture(); if (!checkFlag) { Log.i(TAG, "拍照流程————检查未通过!退出拍照!"); return; } // 2. 替换:拍照请求目标为 captureImageReader(原有 JPEG 格式) CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); captureBuilder.addTarget(captureImageReader.getSurface()); // 用拍照专用 ImageReader // 3. 保留原有拍照参数配置 captureBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO); int rotation = getWindowManager().getDefaultDisplay().getRotation(); captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, rotation); // 4. 保留原有拍照 ImageReader 回调(保存 JPEG 图片) captureImageReader.setOnImageAvailableListener(reader -> { Log.d(TAG, "拍照图像数据可用"); try (Image image = reader.acquireLatestImage()) { if (image != null) { // 保留原有文件创建保存逻辑 file = new File( Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "pic_" + System.currentTimeMillis() + ".jpg" ); // 提取 JPEG 数据(原有逻辑) Image.Plane[] planes = image.getPlanes(); ByteBuffer buffer = planes[0].getBuffer(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes); // 保存图片(原有逻辑) saveImage(bytes, file); // 保留原有广播提示 Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); mediaScanIntent.setData(Uri.fromFile(file)); sendBroadcast(mediaScanIntent); runOnUiThread(() -> Toast.makeText(MainActivity2.this, "保存至: " + file, Toast.LENGTH_SHORT).show() ); } } catch (Exception e) { Log.e(TAG, "保存拍照图像错误: " + e.getMessage()); } finally { isCapturing = false; // 恢复预览(重新下发预览请求) if (cameraCaptureSession != null && captureRequestBuilder != null) { try { cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, backgroundHandler); } catch (CameraAccessException e) { Log.e(TAG, "恢复预览失败: " + e.getMessage()); } } } }, backgroundHandler); // 5. 保留原有拍照执行逻辑 Log.d(TAG, "停止预览"); cameraCaptureSession.stopRepeating(); Log.d(TAG, "4.下发拍照"); isCapturing = true; cameraCaptureSession.capture(captureBuilder.build(), new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) { super.onCaptureFailed(session, request, failure); Log.e(TAG, "拍照失败: " + failure.getReason()); isCapturing = false; } }, backgroundHandler); } catch (CameraAccessException | IllegalStateException | SecurityException e) { Log.e(TAG, "拍照过程异常: " + e.getClass().getSimpleName(), e); isCapturing = false; } } // ---------------------- 保留原有未修改的方法 ---------------------- // (包括:chooseOptimalSize、CompareSizesByArea、stateCallback、saveImage、onRequestPermissionsResult、startBackgroundThread、stopBackgroundThread、closeCamera、checkTakePicture) static class CompareSizesByArea implements Comparator<Size> { @Override public int compare(Size lhs, Size rhs) { return Long.signum((long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight()); } } private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(@NonNull CameraDevice camera) { Log.i(TAG, "相机已打开"); cameraDevice = camera; Log.i(TAG, "2.1 开始配置预览流"); createCameraPreviewSession(); } @Override public void onDisconnected(@NonNull CameraDevice camera) { Log.w(TAG, "相机断开连接"); cameraDevice.close(); } @Override public void onError(@NonNull CameraDevice camera, int error) { Log.e(TAG, "相机错误: " + error); cameraDevice.close(); cameraDevice = null; } }; private void saveImage(byte[] bytes, File file) { Log.d(TAG, "保存图像: " + file.getAbsolutePath()); imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); if (imageUri != null) { try (FileOutputStream output = new FileOutputStream(file)) { output.write(bytes); Log.i(TAG, "图像保存成功, 大小: " + bytes.length + " bytes"); } catch (IOException e) { Log.e(TAG, "保存文件失败: " + e.getMessage()); } } } //触发时机:用户点击授权后调用 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); Log.d(TAG, "权限请求结果: " + requestCode); if (requestCode == REQUEST_CAMERA_PERMISSION) { if (grantResults[0] == PackageManager.PERMISSION_DENIED) { Log.w(TAG, "用户拒绝相机权限"); Toast.makeText(this, "需要相机权限", Toast.LENGTH_SHORT).show(); finish(); } else { Log.i(TAG, "用户授予相机权限"); startBackgroundThread(); openCamera(); } } } private void stopBackgroundThread() { if (backgroundThread != null) { Log.d(TAG, "停止后台线程"); backgroundThread.quitSafely(); try { backgroundThread.join(); backgroundThread = null; backgroundHandler = null; } catch (InterruptedException e) { Log.e(TAG, "停止线程失败: " + e.getMessage()); } } } private void startBackgroundThread() { if (backgroundThread == null) { backgroundThread = new HandlerThread("CameraBackground"); backgroundThread.start(); backgroundHandler = new Handler(backgroundThread.getLooper()); Log.d(TAG, "后台线程启动"); } } private void closeCamera() { Log.d(TAG, "关闭相机资源"); if (isCapturing) { Log.w(TAG, "正在拍照中,等待完成或取消..."); // 可以尝试等待一段时间或取消请求 try { cameraCaptureSession.abortCaptures(); // 取消所有进行中的捕获 } catch (CameraAccessException e) { throw new RuntimeException(e); } } if (cameraCaptureSession != null) { cameraCaptureSession.close(); cameraCaptureSession = null; } isSessionClosed = true; } private Size chooseOptimalSize(Size[] choices, int width, int height) { List<Size> bigEnough = new ArrayList<>(); for (Size option : choices) { float ratio = (float) option.getWidth() / option.getHeight(); float viewRatio = (float) width / height; if (Math.abs(ratio - viewRatio) <= 0.1 && option.getWidth() <= width && option.getHeight() <= height) { bigEnough.add(option); } } if (!bigEnough.isEmpty()) { return Collections.max(bigEnough, new CompareSizesByArea()); } Log.w(TAG, "未找到完美匹配尺寸,使用默认"); return choices[0]; } }我发现并没有调用CameraGLRenderer中的onDrawFrame方法,这是为什么
最新发布
09-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值