How to pass data down the widget tree?

Issue

I have read and understood a similar question posted here, but am having trouble applying it to my use case. I am new to Flutter and am creating an app that streams audio from a given URL using Ryan Heise’s audio_service plugin. Using this plugin I instantiate an audioHandler immediately upon starting my app:

late AudioHandler audioHandler;

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  final session = await AudioSession.instance;
  await session.configure(const AudioSessionConfiguration.music());
  audioHandler = await AudioService.init(
    builder: () => AudioPlayerHandler(),
    config: const AudioServiceConfig(
      androidNotificationChannelId: 'com.ryanheise.myapp.channel.audio',
      androidNotificationChannelName: 'Channel Name',
      androidNotificationOngoing: true,
    ),
  );
  runApp(const MyApp());
}

With this audioHandler initialized, I would like to use it in child widgets. The example below demonstrates one such child widget:

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        debugShowCheckedModeBanner: false,
        title: "Koradi Radio",
        theme: ThemeData(
          brightness: Brightness.light,
          scaffoldBackgroundColor: Colors.white70,
        ),
        darkTheme: ThemeData(
          brightness: Brightness.dark,
        ),
        themeMode: ThemeMode.system,
        home: const EnglishHome());
  }
}

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

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


class _EnglishHomeState extends State<EnglishHome> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('English Radio'),
        backgroundColor: Colors.transparent,
      ),
      body: ... 
    }
}

Note that MyApp currently just routes to EnglishHome(), but I plan on adding additional languages and instead routing MyApp to a page where a user can select their language. How can I pass audioHandler to all descendent widgets from Main() ? (EnglishHome, EspHome, FrenchHome, etc?) Based upon what I have read, I will either be modifying the Key parameter of child widgets or else their BuildContext?

Solution

You can use provider package and all you need to do is use Provider.value and then use Provider.of(context) in your EnglishHome, FrenchHome etc classes.

late AudioHandler audioHandler;

Future<void> main() async {
  audioHandler = await AudioService.init(...);
  runApp(MyApp(audioHandler));
}

class MyApp extends StatelessWidget {
  final AudioHandler audioHandler;
  const MyApp(this.audioHandler, {Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Provider.value(
      value: audioHandler, // Providing the data above MaterialApp
      child: MaterialApp(
        home: EnglishHome(),
      ),
    );
  }
}

class EnglishHome extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Accessing the data. 
    final audioHandler = Provider.of<AudioHandler>(context);
    return Container();
  }
}

Answered By – CopsOnRoad

Answer Checked By – Robin (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *