Initializing camera for list of available cameras in Future

Viewed 186

I am using this code that I got directly from pub.dev regarding initializing the camera and creating a list of available cameras

the list is created in a Future main() function but it is not being automatically called when I navigate to the CameraApp page. Has anyone run into this issue? How do I initialize the camera and create the list of available cameras when it navigates to the page with this code? Please help, thank you.

/// CameraApp is the Main Application.
class CameraApp extends StatelessWidget {
  /// Default Constructor
  const CameraApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: CameraExampleHome(),
    );
  }
}

List<CameraDescription> _cameras = <CameraDescription>[];

Future<void> main() async {
  // Fetch the available cameras before initializing the app.
  try {
    WidgetsFlutterBinding.ensureInitialized();
    _cameras = await availableCameras();
  } on CameraException catch (e) {
    _logError(e.code, e.description);
  }
  runApp(const CameraApp());
}

And this is the code where I call the CameraApp function from inside a button:

ElevatedButton(
              onPressed: () 
              {Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (context) => CameraApp()));},
              child: const Text('Camera'),
              style: ElevatedButton.styleFrom(
                  minimumSize: const Size(160.0, 35.0)),

            ),
4 Answers

There are few things to consider here.. The implementation you did was right but you named the cameras as a private variable which will be accessed in a single dart file by adding an _ like _cameras. Removing that will make it globally available in all classes just by importing main.dart

Here is the full code

main.dart

import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:trial/CameraExampleHome.dart';

List<CameraDescription> cameras = <CameraDescription>[];
void main() async {
  try {
    WidgetsFlutterBinding.ensureInitialized();
    cameras = await availableCameras();
    print(cameras);
  } on CameraException catch (e) {
    print(e.toString());
  }
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: CameraApp());
  }
}

class CameraApp extends StatelessWidget {
  /// Default Constructor
  const CameraApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: CameraExampleHome(),
    );
  }
}

cameraExampleHome.dart

import 'package:flutter/material.dart';

import 'main.dart';

class CameraExampleHome extends StatefulWidget {
  const CameraExampleHome({Key? key}) : super(key: key);

  @override
  State<CameraExampleHome> createState() => _CameraExampleHomeState();
}

class _CameraExampleHomeState extends State<CameraExampleHome> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text("Available Cameras $cameras"),
//output: Available Cameras [CameraDescription(0, CameraLensDirection.back, 90), CameraDescription(1, CameraLensDirection.front, 270), CameraDescription(2, CameraLensDirection.front, 270)]
      ),
    );
  }
}

You can create a kind of singleton to manage camera operations.

class CameraManager {
  // Declare your camera list here
  List<CameraDescription> _cameras = <CameraDescription>[];

  // Constructor
  CameraManager._privateConstructor() {}

  // initialise instance
  static final CameraManager instance =
      CameraManager._privateConstructor();

  // Add a getter to access camera list
  bool get cameras => _cameras;

  // Init method
  init() async {
    try {
      _cameras = await availableCameras();
    } on CameraException catch (e) {
      _logError(e.code, e.description);
    }
  }

  // other needed methods to manage camera
  ...
}

And then in you main function

Future<void> main() async {
  // Fetch the available cameras before initializing the app.
  try {
    WidgetsFlutterBinding.ensureInitialized();
    await CameraManager.instance.init();
  }
  runApp(const CameraApp());
}

Then on other part of your application, you can import the singleton and access methods and properties with CameraManager.instance.*, for example CameraManager.instance.cameras access _cameras through the getter.

You could create a library file for Global Variables.

Create a file called "globals.dart" in your lib folder.

Declare the following line at the top.

library your_project_name.globals;

Then set your variable in it

List<CameraDescription> cameras = <CameraDescription>[];

Usage in main

import 'globals.dart' as globals;

main() {
  ...
  globals.cameras = await availableCameras();
  ...
}

Then simply use the variable anywhere in your project.

import 'globals.dart' as globals;

globals.cameras...

Declare list of CameraDescription global instance as below:

  List<CameraDescription> cameras = <CameraDescription>[];

Now you can access the camera instance by importing main.dart , _ always make the instance variable private which will not be accessible outside the file

Related