Using deferred libraries with variables

Viewed 79

Sorry in advance I am a beginner and my English is approximate.

I don't know if what I'm doing is correct or not so sorry (again) if this sounds stupid to you. I try to recover the contents of certain files only when I need them. I think it's good for optimizing my dart/flutter app and reducing loading times.

So So I have a list of files coded like this :

  • N101aze.dart which contains a Map called N101aze
  • N101qsd.dart which contains a List called N101qsd
  • N101wxc.dart which contains a List called N101wxc
  • ...

In the same way I have :

  • N102aze.dart which contains a Map called N102aze
  • N102qsd.dart which contains a List called N102qsd
  • N102wxc.dart which contains a List called N102wxc
  • ...

etc...

Each time I have another file called and coded like that :

N101.dart

export "path[...]/N101aze.dart";
export "path[...]/N101qsd.dart";
export "path[...]/N101wxc.dart";
...

Now in a file I want to make a Deferred loading like that :

import "path[...]/N101.dart" deferred as N101; //I know lowercase is better

I load the library when I want by using

greet() async {
  await N101.loadLibrary();
}

and later I can call my maps and lists by using

N101.N101aze
N101.N101qsd

It's working perfectly when I use the names listed above.

Now, what I really want is to use a key (called kkey here) to call the library I want when I call onPressed on ElevatedButton :

import 'package:flutter/material.dart';
import 'package:my_app/Models/SetColor.dart';

import "path[...]/N101.dart" deferred as N101; //I know lowercase is better
import "path[...]/N102.dart" deferred as N102;
import "path[...]/N103.dart" deferred as N103;
...

class CustomButton extends StatefulWidget {
  const CustomButton({
    required this.kkey,
  }) : super(key: key);
  final String kkey;

  @override
  State<CustomButton> createState() => _CustomButtonState();
}

class _CustomButtonState extends State<CustomButton> {

  Future<void> greet(thekey) async {
    await thekey.loadLibrary();
  }

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      child: Text(
        widget.kkey
      ),
      onPressed: () async {
        await greet(widget.kkey); //it's not working beacause kkey type is String
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => LoadingParts(
              part1: // here I want N101.N101aze when kkey="N101" so I want something like kkey.kkeyaze 
              part2: // here I want N101.N101qsd when kkey="N101" so I want something like kkey.kkeyqsd

...

Note :

  • I "simplified" the code to keep only the essentials
  • part1 is a Map and part2 is a List

For the greet function, I think I understand it doesn't work because N101, N102, N103... have no type and my kkey is the type of String but I don't know what is possible to do...

To invoke my maps and my lists, I have no idea what to do... Especially when I want to concatenate kkey with aze (for example).

I know I can use Switch Case Statement which looks at all characters from kkey to return, for example "N101.loadlibrary()" and "N101.N101.aze" but the number of "Switch" and "Case" is too big to be worth it and the number of possibilities may increase as the application grows.

I hope you will understand my problem and I hope it's not too stupid, I'm learning^^.

Thank you for your attention! Bye!

1 Answers

Unfortunately, there is no way to do it dynamically this way i.e. getting a declaration by name. Although Dart is a static language that supports reflection, flutter does not by default. In Flutter the mirrors package is disabled in favour of static optimization. There is also reflectable but it has limitations where it's not possible to reflect a module for example.

So, the way to fix it is to use static code too to load the deferred libs like the following.

On each NXXX.dart file, where XXX is 101, 102, 103 etc., declare the same map. For example, in N101.dart it's going to be like this:

// Create a map with all structures needed
final nmap = {
  'aze': N101aze,
  'qsd': N101qsd,
  'wxc': N101wxc,
};

And then the usage is going to be like this:

class CustomButton extends StatefulWidget {
  const CustomButton({
    Key? key,
    required this.kkey,
  }) : super(key: key);
  final String kkey;

  @override
  State<CustomButton> createState() => _CustomButtonState();
}

class _CustomButtonState extends State<CustomButton> {
  Future<Map<String, Object>> greet(String thekey) async {
    // Load the deferred module and return the structures
    switch (thekey) {
      case 'N101':
        await N101.loadLibrary();
        return N101.nmap;
      case 'N102':
        await N102.loadLibrary();
        return N102.nmap;
      case 'N103':
        await N103.loadLibrary();
        return N103.nmap;
      default:
        assert(false);
        throw Exception('$thekey not mapped');
    }
  }

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      child: Text(widget.kkey),
      onPressed: () async {
        // Get the common `nmap` from `greet` by `kkey`
        final nmap = await greet(widget.kkey);
        if (mounted) {
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => LoadingParts(
                // Use the `nmap` by name
                part1: nmap['aze']! as Map,
                part2: nmap['qsd']! as List,
                part3: nmap['wxc']! as List,
              ),
            ),
          );
        }
      },
    );
  }
}
Related