You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

点击返回键后二维码扫描页面摄像头黑屏问题求助

二维码扫描后返回原Activity摄像头黑屏的问题分析与解决

问题描述

我开发了一款使用摄像头扫描二维码的应用,进入二维码读取页面后一切正常。扫描二维码后,信息会被传至另一个Activity,但点击返回键后,摄像头画面黑屏,无法再获取图像。我曾尝试在黑屏状态下扫描,确认并非仅显示问题;但退出该Activity再重新进入,摄像头可恢复正常。Logcat未报错,仅在Firebase中记录了事件。请问这是硬件问题、代码问题,还是需要重启Activity的正常现象?

相关Java代码如下:

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;
import com.google.zxing.Result;
import me.dm7.barcodescanner.zxing.ZXingScannerView;

public class CodQR extends AppCompatActivity implements ZXingScannerView.ResultHandler {
    private static final int ID_UL_MEU_PENTRU_PERMISIA_DE_CAMERA = 1000;
    private ZXingScannerView zXingScannerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_cod_qr);
    }

    public void scan() {
        zXingScannerView = new ZXingScannerView(getApplicationContext());
        setContentView(zXingScannerView);
        zXingScannerView.setResultHandler(this);
        zXingScannerView.startCamera();
    }

    @Override
    public void handleResult(Result result) {
        Toast.makeText(getApplicationContext(), result.getText(), Toast.LENGTH_SHORT).show();
        String MyText = result.getText().toString();
        Intent intent = new Intent(CodQR.this, Qr_Results.class);
        intent.putExtra(Intent.EXTRA_TEXT, MyText);
        startActivity(intent);
        zXingScannerView.resumeCameraPreview(this);
    }

    //Permissions
    public void CheckPermissionsCamera(View view) {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(this, "Insufficient permissions.", Toast.LENGTH_LONG).show();
            ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.CAMERA }, ID_UL_MEU_PENTRU_PERMISIA_DE_CAMERA );
        } else {
            scan();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case ID_UL_MEU_PENTRU_PERMISIA_DE_CAMERA: {
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(this, "Permission granted", Toast.LENGTH_SHORT).show();
                } else {
                    // daca grantResults e gol, a dat cancel
                    Toast.makeText(this, "You didn't accept the permission", Toast.LENGTH_LONG).show();
                }
            }
        }
    }
}

public class Qr_Results extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_qr_results);
        TextView myText = findViewById(R.id.Text_Qr_Results);
        //Get Intent
        Intent intent = getIntent();
        //Get the string value of the intent
        String text = intent.getStringExtra(Intent.EXTRA_TEXT);
        //Set text to TextView
        myText.setText(text);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        if (getSupportActionBar() != null) {
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
            getSupportActionBar().setDisplayShowHomeEnabled(true);
        }
    }

    public boolean onSupportNavigateUp() {
        onBackPressed();
        return true;
    }
}

问题原因分析

这绝对是代码逻辑问题,既不是硬件故障,也不属于需要重启Activity的正常现象。核心问题出在摄像头资源的生命周期管理上:

  • 当你跳转到Qr_Results时,当前的CodQR Activity会进入暂停状态,但你没有在这个阶段释放摄像头资源,导致摄像头被异常占用;
  • 你在handleResult里先调用了startActivity,之后才执行resumeCameraPreview——这时候Activity已经开始切换,预览的上下文早就失效了,这行代码完全起不到作用;
  • Qr_Results返回后,CodQRonResume方法没有被重写来恢复摄像头预览,加上之前的扫描View状态已经异常,自然就黑屏了。

另外,你直接用zXingScannerView替换了原布局,返回后这个自定义View没有被正确重建,也是黑屏的诱因之一。


解决方案

你需要正确管理摄像头的生命周期,在Activity的暂停和恢复阶段对应处理摄像头的释放与重启,同时调整handleResult里的逻辑:

修改后的CodQR Activity代码

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;
import com.google.zxing.Result;
import me.dm7.barcodescanner.zxing.ZXingScannerView;

public class CodQR extends AppCompatActivity implements ZXingScannerView.ResultHandler {
    private static final int ID_UL_MEU_PENTRU_PERMISIA_DE_CAMERA = 1000;
    private ZXingScannerView zXingScannerView;
    private boolean isScanningActive = false; // 标记当前是否处于扫描状态

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_cod_qr);
    }

    public void scan() {
        zXingScannerView = new ZXingScannerView(getApplicationContext());
        setContentView(zXingScannerView);
        zXingScannerView.setResultHandler(this);
        zXingScannerView.startCamera();
        isScanningActive = true;
    }

    @Override
    public void handleResult(Result result) {
        Toast.makeText(getApplicationContext(), result.getText(), Toast.LENGTH_SHORT).show();
        String MyText = result.getText().toString();
        Intent intent = new Intent(CodQR.this, Qr_Results.class);
        intent.putExtra(Intent.EXTRA_TEXT, MyText);
        
        // 先停止摄像头再跳转页面,避免资源占用
        zXingScannerView.stopCamera();
        isScanningActive = false;
        startActivity(intent);
    }

    // 返回时重新启动摄像头预览
    @Override
    protected void onResume() {
        super.onResume();
        if (isScanningActive && zXingScannerView != null) {
            zXingScannerView.setResultHandler(this);
            zXingScannerView.startCamera();
        }
    }

    // 暂停时释放摄像头资源
    @Override
    protected void onPause() {
        super.onPause();
        if (zXingScannerView != null) {
            zXingScannerView.stopCamera();
        }
    }

    //Permissions
    public void CheckPermissionsCamera(View view) {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(this, "Insufficient permissions.", Toast.LENGTH_LONG).show();
            ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.CAMERA }, ID_UL_MEU_PENTRU_PERMISIA_DE_CAMERA );
        } else {
            scan();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case ID_UL_MEU_PENTRU_PERMISIA_DE_CAMERA: {
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(this, "Permission granted", Toast.LENGTH_SHORT).show();
                    scan(); // 权限授予后直接启动扫描
                } else {
                    Toast.makeText(this, "You didn't accept the permission", Toast.LENGTH_LONG).show();
                }
            }
        }
    }

    // 销毁时彻底释放资源
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (zXingScannerView != null) {
            zXingScannerView.stopCamera();
            zXingScannerView = null;
        }
    }
}

关键修改点说明

  • 添加isScanningActive标记,用来跟踪当前是否处于扫描状态;
  • handleResult中,先停止摄像头再跳转页面,避免摄像头资源被异常占用;
  • 重写onResume方法:当从Qr_Results返回时,如果之前处于扫描状态,重新启动摄像头预览;
  • 重写onPauseonDestroy方法:在Activity暂停/销毁时统一释放摄像头资源,避免资源泄漏;
  • 在权限授予成功后直接调用scan(),提升用户体验。

内容的提问来源于stack exchange,提问作者CuriousPaul

火山引擎 最新活动