【问题标题】:Android service doesn't rebind to camera when respawned重生时Android服务不会重新绑定到相机
【发布时间】:2022-07-30 21:57:36
【问题描述】:

我运行了一个分析前台帧的服务。从我启动服务的那一刻起,它工作正常,直到它被杀死。从那一刻起,当它重生时,我看不到与以前相同的消息(说 X App 正在使用你的相机),尽管我看到了前台通知。

我该如何解决这个问题,以便在它重生时不会停止分析帧?

启动服务

public class WelcomeActivity extends AppCompatActivity {

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

        Button btnStart = findViewById(R.id.btnStart);
        btnStart.setOnClickListener(v -> {
                Intent serviceIntent = new Intent(this, StartService.class);
                Utils.requestCameraPermission(getApplicationContext(), this);
                this.startService(serviceIntent);
        });

启动服务

public class StartService extends LifecycleService {
    private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
    private FrameAnalyzer frameAnalyzer;

    @Override
    public void onCreate() {
        super.onCreate();
        frameAnalyzer = new FrameAnalyzer(...);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        Intent notificationIntent = new Intent(this, WelcomeActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,
                0, notificationIntent, 0);

        Notification notification = new NotificationCompat.Builder(this, ServiceApp.CHANNEL_ID)
                .setContentTitle(getString(R.string.service_title))
                .setContentText(getString(R.string.service_text))
                .setSmallIcon(R.drawable.test_icon)
                .setContentIntent(pendingIntent)
                .build();

        startForeground(1, notification);
        // Add listener for Camera Provider
        cameraProviderFuture = ProcessCameraProvider.getInstance(this);
        cameraProviderFuture.addListener(() -> {
            try {
                ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
                CameraBinder binder = new CameraBinder(cameraProvider, getApplicationContext(), frameAnalyzer);
                binder.setUp(this);
            } catch (ExecutionException | InterruptedException e) {
                // No errors need to be handled for this Future.
                // This should never be reached.
            }
        }, ContextCompat.getMainExecutor(this));

        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public IBinder onBind(@NonNull Intent intent) {
        super.onBind(intent);
        return null;
    }
}

相机绑定

public class CameraBinder implements ImageAnalysis.Analyzer {
    private final ProcessCameraProvider cameraProvider;
    private final Context context;
    private final ImageAnalyzer imageAnalyzer;

    public CameraBinder(ProcessCameraProvider cameraProvider,
                        Context context, ImageAnalyzer imageAnalyzer) {
        this.cameraProvider = cameraProvider;
        this.context = context;
        this.imageAnalyzer = imageAnalyzer;
    }

    public void setUp(final LifecycleOwner lifecycleOwner) {
        // Must unbind the use-cases before rebinding them
        cameraProvider.unbindAll();
        // Choose the camera by requiring a lens facing
        final int lens = CameraSelector.LENS_FACING_FRONT;
        CameraSelector cameraSelector = new CameraSelector.Builder()
                .requireLensFacing(lens)
                .build();
        // Image Analysis use case
        // Use cases
        ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
                .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_YUV_420_888)
                .build();
        // Get orientation
        // Source: https://stackoverflow.com/a/59894580/4544940
        OrientationEventListener orientationEventListener = new OrientationEventListener(context) {
            @Override
            public void onOrientationChanged(int orientation) {
                int rotation;

                // Monitors orientation values to determine the target rotation value
                if (orientation >= 45 && orientation < 135) {
                    rotation = Surface.ROTATION_270;
                } else if (orientation >= 135 && orientation < 225) {
                    rotation = Surface.ROTATION_180;
                } else if (orientation >= 225 && orientation < 315) {
                    rotation = Surface.ROTATION_90;
                } else {
                    rotation = Surface.ROTATION_0;
                }

                // Updates target rotation value to {@link ImageAnalysis}
                imageAnalysis.setTargetRotation(rotation);
            }
        };
        orientationEventListener.enable();
        imageAnalysis.setAnalyzer(Runnable::run, this);
        // Attach use cases to the camera with the same lifecycle owner
        Camera camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, imageAnalysis);
    }

    @Override
    public void analyze(@NonNull ImageProxy image) {
        if (image.getImageInfo().getTimestamp() % 10 == 0) {
            this.imageAnalyzer.run(image);
        }
        image.close();
    }
}

版本

dependencies {
    def camerax_version = "1.0.2"
    implementation "androidx.camera:camera-core:${camerax_version}"
    implementation "androidx.camera:camera-camera2:${camerax_version}"
    implementation "androidx.camera:camera-lifecycle:${camerax_version}"
    implementation "androidx.camera:camera-view:1.0.0-alpha30"
    implementation "androidx.camera:camera-extensions:1.0.0-alpha30"
    implementation 'androidx.lifecycle:lifecycle-service:2.3.0'
}

【问题讨论】:

  • 您是否看到从 addListener Runnable 记录的任何异常? ListenableFuture 会捕获并记录它们,因此您可能错过了它们。

标签: android-service android-lifecycle android-camera2 android-camerax foreground-service


【解决方案1】:

如果您的应用面向 Android 11(API 级别 30)或更高版本并在前台服务中访问摄像头或麦克风,请将摄像头或麦克风前台服务类型分别声明为组件的属性。 Source.

将此属性添加到AndroidManifest.xml 中的我的服务组件工作:

<manifest>
    ...
    <service ... android:foregroundServiceType="camera" />
</manifest>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-21
    相关资源
    最近更新 更多