How to use Provider value in Flutter

Provider package in Flutter serves us in many ways. Flutter team recommends it as the best state management architecture. But that is not the end of the story. We can use Provider for many purposes, that also includes passing a global style across the flutter app. However, understanding Provider will remain incomplete if we don’t understand the concept of generics value or the type of Provider.

This section on Provider is intended for beginners, so we assume we need to start from the beginning.

Firstly, we can provide any type of value through Provider.

Take a look at the code below.

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'model/global_theme.dart';
import 'view/home.dart';

void main() {
  runApp(
    /// Providers are above [Root App] instead of inside it, so that tests
    /// can use [Root App] while mocking the providers
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => GlobalTheme()),
        Provider<int>(create: (context) => 1),
        Provider<String>(create: (context) => 'Hello Flutter'),
      ],
      child: const Home(),
    ),
  );
}

Forget about the first line. Take a look at the middle line and let’s try to understand it first.

Provider<int>(create: (context) => 1),

In this case, Provider passes an integer value inside <> brackets. That generic value tells Flutter what type of provider to look for. And we’ve returned a value 1.

The second line tells us another stroy.

Provider<String>(create: (context) => 'Hello Flutter'),

This time Flutter will look for a String or text; so we’ve returned a text: “Hello Flutter”.

Once we’ve passed this generic value we can try to access that value anywhere, in the widget tree. However, that value must be provided there inside the build method.

Why so?

Because context works like a road. Each different Provider takes different road, or context. Inside the build method, all roads, contexts merge and separate the value. As a result we can access different value quite easily.

Flutter works seamlessly with Provider and goes up through the widget tree to find the exact value.

If it doesn’t find that generic value, exception is thrown.

Let’s try to understand more about the generic value or type that Provider understands.

Not that it should be only integer or String. It could be any type, even an Object. That means, we can pass a whole class properties and methods through Provider.

The first line of code tells that story. However, in a different way, although.

 ChangeNotifierProvider(create: (_) => GlobalTheme()),

Here, in the above line we’ve used ChangeNotifierProvider, instead of Provider. There are reasons to do that. We’ve discussed that already.

However, the most important reason is, if we want to change the state, or call a class method through Provider, the ChangeNotifierProvider is the best choice.

Now, we can try to grab those values. First of all, consider the above line.

We have passed a custom class GlobalTheme. That defines the global theme of the app. Certainly, we can define different ThemeData object to make every page of our app look different.

But at present, it’s enough to get the idea.

import 'package:flutter/material.dart';

class GlobalTheme with ChangeNotifier {
  final globalTheme = ThemeData(
    primarySwatch: Colors.deepOrange,
    textTheme: const TextTheme(
      bodyText1: TextStyle(
        fontSize: 22,
      ),
      bodyText2: TextStyle(
        color: Colors.blue,
        fontSize: 18,
        fontWeight: FontWeight.bold,
      ),
      caption: TextStyle(
        fontSize: 16,
        fontWeight: FontWeight.bold,
        fontStyle: FontStyle.italic,
      ),
      headline1: TextStyle(
        color: Colors.deepPurple,
        fontSize: 50,
        fontFamily: 'Allison',
      ),
      headline2: TextStyle(
        color: Colors.deepOrange,
        fontSize: 30,
        fontWeight: FontWeight.bold,
      ),
    ),
    appBarTheme: const AppBarTheme(
      backgroundColor: Colors.amber,
      // This will control the "back" icon
      iconTheme: IconThemeData(color: Colors.red),
      // This will control action icon buttons that locates on the right
      actionsIconTheme: IconThemeData(color: Colors.blue),
      centerTitle: false,
      elevation: 15,
      titleTextStyle: TextStyle(
        color: Colors.deepPurple,
        fontWeight: FontWeight.bold,
        fontFamily: 'Allison',
        fontSize: 40,
      ),
    ),
  );
}

Next, we can have these values in our home page. To understand the whole widget tree, you can read the full code snippets in this GitHub repository.

import 'package:build_blog_with_flutter/model/global_theme.dart';
import 'package:flutter/material.dart';

import 'package:provider/provider.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(
          'Testing Global Theme with Provider',
          style: Theme.of(context).appBarTheme.titleTextStyle,
        ),
      ),
      body: const HomeBody(),
    );
  }
}

/// pushing to main now
class HomeBody extends StatelessWidget {
  const HomeBody({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final int globalInt = Provider.of<int>(context);
    final String globalString = Provider.of<String>(context);
    final ThemeData globalTheme = Provider.of<GlobalTheme>(context).globalTheme;
    return Center(
      child: Column(
        children: [
          Container(
            margin: const EdgeInsets.all(5),
            padding: const EdgeInsets.all(5),
            child: Text(
              '$globalInt',
              //style: Theme.of(context).textTheme.bodyText1,
              style: globalTheme.textTheme.bodyText1,
            ),
          ),
          Container(
            margin: const EdgeInsets.all(5),
            padding: const EdgeInsets.all(5),
            child: Text(
              globalString,
              //style: Theme.of(context).textTheme.bodyText2,
              style: globalTheme.textTheme.bodyText2,
            ),
          ),
          Container(
            margin: const EdgeInsets.all(5),
            padding: const EdgeInsets.all(5),
            child: Text(
              'Headline 1 theme style again provided by provider',
              //style: Theme.of(context).textTheme.headline2,
              style: globalTheme.textTheme.headline1,
            ),
          ),
        ],
      ),
    );
  }
}

As a result, we see the following screenshot where we get the provided integer, String value; and, along with that we can also apply our custom theme to our app.

Flutter provider example
Flutter provider example

In the above code, we can avoid using the custom theme. Actually we had provided the global custom theme through the following lines:

ChangeNotifierProvider(create: (_) => GlobalTheme()),
...
final ThemeData globalTheme = Provider.of<GlobalTheme>(context).globalTheme;

If we don’t do that, no longer the provided custom theme works. And in that case, the rest provided value appears on the screen with the default ThemeData that take another context or road.

As a result, the look of the app gets changed.

Flutter app without provider backed theme
Flutter app without provider backed theme

Anyway, the headline was wrong. It should have been read like, “Headline 1 theme style provided by default theme.” 🙂

We hope, it now makes sense, how Provider works and we get provided value anywhere in the widget tree.

What Next?

Books at Leanpub

Books in Apress

My books at Amazon

GitHub repository

Technical blog

Twitter

Comments

6 responses to “How to use Provider value in Flutter”

  1. […] our last section on the usage of Provider package, we’ve seen what we can do with Provider. To tell you frankly, we can do many things in […]

  2. […] our last section we’ve built a simple blog app with the help of Provider package that only displays a few clickable posts on home page. Consequently, we can click any post and read […]

  3. […] In our last two sections, consecutively we’ve built two simple Flutter applications. Both flutter applications are a simple Blog that we’ve built with the help of Provider package.  […]

  4. […] our last section on the usage of Provider package, we’ve seen what we can do with Provider. To tell you frankly, we can do many things in Flutter […]

  5. […] Through Listenable object the Custom Painter object maintains a list of listeners. […]

  6. […] And finally, we are going to store persistent data in our local SQLite database, using provider package. […]

Leave a Reply