点击返回键后二维码扫描页面摄像头黑屏问题求助
二维码扫描后返回原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时,当前的CodQRActivity会进入暂停状态,但你没有在这个阶段释放摄像头资源,导致摄像头被异常占用; - 你在
handleResult里先调用了startActivity,之后才执行resumeCameraPreview——这时候Activity已经开始切换,预览的上下文早就失效了,这行代码完全起不到作用; - 从
Qr_Results返回后,CodQR的onResume方法没有被重写来恢复摄像头预览,加上之前的扫描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返回时,如果之前处于扫描状态,重新启动摄像头预览; - 重写
onPause和onDestroy方法:在Activity暂停/销毁时统一释放摄像头资源,避免资源泄漏; - 在权限授予成功后直接调用
scan(),提升用户体验。
内容的提问来源于stack exchange,提问作者CuriousPaul




