You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:19:19