自定义SurfaceView添加至Fragment后导致应用崩溃问题求助
解决Fragment中添加自定义SurfaceView崩溃的问题
嘿,我来帮你排查这个Fragment里添加自定义SurfaceView就崩溃的问题!从你给出的代码片段来看,有几个常见的坑很可能导致了崩溃,咱们一步步梳理解决:
1. 补全构造函数重载
Fragment中通过布局inflater加载自定义View时,系统会调用带AttributeSet的构造函数,如果你只实现了Context单参构造函数,会直接触发找不到构造方法的崩溃。赶紧补上另外两个构造函数,并把初始化逻辑抽成通用方法:
public class CameraFocusIndacatorSurfaceView extends SurfaceView implements Runnable { private final Paint paint; private final SurfaceHolder mHolder; private final Context context; private boolean isRunning = false; // 控制绘制线程的开关 // 单参构造 public CameraFocusIndacatorSurfaceView(Context context) { super(context); init(); } // 必须补的双参构造(inflater加载时调用) public CameraFocusIndacatorSurfaceView(Context context, AttributeSet attrs) { super(context, attrs); init(); } // 可选补的三参构造(适配主题样式) public CameraFocusIndacatorSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } // 统一初始化逻辑 private void init() { mHolder = getHolder(); context = getContext(); paint = new Paint(); // 初始化画笔属性,比如颜色、抗锯齿等 paint.setColor(Color.GREEN); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(3f); // 关键:添加SurfaceHolder回调,监听Surface的创建/销毁 mHolder.addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { // Surface创建后再启动绘制线程,避免空指针 isRunning = true; new Thread(CameraFocusIndacatorSurfaceView.this).start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // 处理Surface尺寸变化的逻辑(比如调整对焦框位置) } @Override public void surfaceDestroyed(SurfaceHolder holder) { // Surface销毁时停止线程,避免内存泄漏 isRunning = false; } }); } @Override public void run() { while (isRunning) { Canvas canvas = null; try { // 锁定画布,确保线程安全 canvas = mHolder.lockCanvas(); if (canvas != null) { // 在这里实现你的对焦指示器绘制逻辑 drawFocusIndicator(canvas); } } catch (Exception e) { e.printStackTrace(); } finally { // 必须释放画布,否则会导致Surface卡死 if (canvas != null) { mHolder.unlockCanvasAndPost(canvas); } } // 控制绘制帧率,避免过度占用CPU try { Thread.sleep(16); } catch (InterruptedException e) { e.printStackTrace(); } } } // 示例绘制方法 private void drawFocusIndicator(Canvas canvas) { // 清空画布 canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); // 画一个居中的对焦框 int centerX = getWidth() / 2; int centerY = getHeight() / 2; int size = 100; canvas.drawRect(centerX - size, centerY - size, centerX + size, centerY + size, paint); } // 对外提供停止绘制的方法,供Fragment生命周期调用 public void stopDrawing() { isRunning = false; } }
2. 适配Fragment生命周期
Fragment销毁时,一定要主动停止SurfaceView的绘制线程,避免野指针或内存泄漏。比如在你的Fragment中:
public class YourFragment extends Fragment { private CameraFocusIndacatorSurfaceView mFocusSurfaceView; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.your_fragment_layout, container, false); mFocusSurfaceView = view.findViewById(R.id.focus_surface_view); return view; } @Override public void onDestroyView() { super.onDestroyView(); if (mFocusSurfaceView != null) { mFocusSurfaceView.stopDrawing(); } } }
3. 排查相机权限(如果和相机相关)
从你的View名字CameraFocusIndacatorSurfaceView来看,它大概率和相机联动。别忘了在AndroidManifest.xml中声明相机权限:
<uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" />
并且在运行时动态申请权限,确保权限通过后再初始化SurfaceView,否则也会触发权限相关的崩溃。
内容的提问来源于stack exchange,提问作者Marnus Steyn
相关产品推荐
相关产品推荐

