how to call variable declared in async function into the widget in flutter?

Viewed 484

Here I'm trying to access the camera from the app using the camera package and I'm a beginner in a flutter. Hope you'll help me in this

I've created an async method and declared the variable in it now I want to call the declared in inside by widget and tried calling it but it says "Undefined name 'firstCamera'". I've referred to https://flutter.dev/docs/cookbook/plugins/picture-using-camera. But I've used code in another page

Thanks in advance.

this is my code

import 'package:flutter/material.dart';
import 'dart:io';
import 'dart:async';
import 'package:camera/camera.dart';

class PrivacyPolicyPage extends StatefulWidget {

  @override
  _PrivacyPolicyPageState createState() => _PrivacyPolicyPageState();
}

class _PrivacyPolicyPageState extends State<PrivacyPolicyPage> {


  Future<void> camera() async {

    final cameras = await availableCameras();
    firstCamera = cameras.first;
  }
  CameraDescription? firstCamera;

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: TakePictureScreen(camera:firstCamera,),
    );
  }
}

class TakePictureScreen extends StatefulWidget {


  const TakePictureScreen({Key? key,required this.camera}) : super(key: key);
  final CameraDescription camera;

  @override
  _TakePictureScreenState createState() => _TakePictureScreenState();
}

class _TakePictureScreenState extends State<TakePictureScreen> {
  late CameraController _controller;
  late Future<void> _initializeControllerFuture;

  @override
  void initState() {
    super.initState();
    // To display the current output from the Camera,
    // create a CameraController.
    _controller = CameraController(
      // Get a specific camera from the list of available cameras.
      widget.camera,
      // Define the resolution to use.
      ResolutionPreset.medium,
    );

    // Next, initialize the controller. This returns a Future.
    _initializeControllerFuture = _controller.initialize();
    @override
    void dispose() {
      // Dispose of the controller when the widget is disposed.
      _controller.dispose();
      super.dispose();
    }

  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: FutureBuilder<void>(
        future: _initializeControllerFuture,
        builder: (context,snapshot){
          if(snapshot.connectionState == ConnectionState.done){
            //If the Future is complete, display the preview.
            return CameraPreview(_controller);

          }
          else{
          //Other wise,display a loading indicator
            return const Center(child:CircularProgressIndicator());
          }
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          try{
            await _initializeControllerFuture;
            final image = await _controller.takePicture();
            await Navigator.of(context).push(
              MaterialPageRoute(
                builder:(context) => DisplayPictureScreen(
                  imagePath:image.path,
                )
              )
            );
          } catch(e){
            //If an error occurs, log the error to the console.
            print(e);
          }

        },
        child: const Icon(Icons.camera),
      ),
    );
  }
}

class DisplayPictureScreen extends StatelessWidget {
  final String imagePath;
  const DisplayPictureScreen({Key? key, required this.imagePath}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title:const Text("Display the Picture")),
      body:Image.file(File(imagePath)),
    );
  }
}
2 Answers

You have to define the variable outside the method. Your _PrivacyPolicyPageState class should look like this:

class _PrivacyPolicyPageState extends State<PrivacyPolicyPage> {

  // Define outside
  CameraDescription firstCamera;

  Future<void> camera() async {
    // Obtain a list of the available cameras on the device.
    final cameras = await availableCameras();

    // Get a specific camera from the list of available cameras.
    // Assigne a value to firstCamera variable
    firstCamera = cameras.first;

  }
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: TakePictureScreen(camera:firstCamera,),
    );
  }
}

According the doc, You need to put that code in the main.dart before the runApp():

// Ensure that plugin services are initialized so that 
// `availableCameras()`
// can be called before `runApp()`
WidgetsFlutterBinding.ensureInitialized();

// Obtain a list of the available cameras on the device.
final cameras = await availableCameras();

// Get a specific camera from the list of available cameras.
final firstCamera = cameras.first;

runApp(
  PrivacyPolicyPage(camera: camera),
);

And after that you will be able to put firstCamera in widgets as parameter and it will be available there

class PrivacyPolicyPage extends StatelessWidget {
    PrivacyPolicyPage(required this.camera);
    final CameraDescription camera;

    @override
    Widget build(BuildContext context) {
    return SafeArea(
        child: TakePictureScreen(camera:camera),
    );
  }
}

class TakePictureScreen extends StatefulWidget {
    const TakePictureScreen({Key? key,required this.camera}) : 
        super(key: key);
    final CameraDescription camera;

    @override
    _TakePictureScreenState createState() => _TakePictureScreenState();
}

And you will be able to use it in _TakePictureScreenState like widget.camera

Also, you can create an InheritedWidget, and then you will be able to use camera in the deeper widgets

Related