Code Monkey home page Code Monkey logo

Comments (3)

jonataslaw avatar jonataslaw commented on May 13, 2024

If you're new, maybe I'm introducing you to unnecessary complexity, but it might be good for you to learn some basics.

Let's say you want to do a search for the API reactively, using Bloc, and you don't want to use any extra packages for that because you want complete control of what you're doing.
At a minimum you need to transform the class Bloc you are going to use into a singleton, so you can access it from anywhere.
The sample code contains a disposable singleton model that replaces the package for example from the provider/get_it. Instead of adding a new dependency, and it will always have the same instance, it will only be placed in memory when you call, and you can give dispose to save memory at any time.
In any other language I prefer DI to use singletons, but in Dart, they are not a problem with tests, and can be disposable, which is a great advantage of using them here.

Example:

import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: Get.key,
      onGenerateRoute: Router.generateRoute,
      navigatorObservers: [GetObserver(MiddleWare.observer)],
      home: First(),
    );
  }
}

class Router {
  static Route<dynamic> generateRoute(RouteSettings settings) {
    switch (settings.name) {
      case '/':
        return GetRoute(
          page: First(),
          settings: settings,
        );
      case '/second':
        return GetRoute(
            settings: settings, page: Second(), transition: Transition.fade);
      case '/third':
        return GetRoute(
            settings: settings,
            page: Third(),
            transition: Transition.cupertino);
      default:
        return GetRoute(
            settings: settings,
            transition: Transition.fade,
            page: Scaffold(
              body:
                  Center(child: Text('No route defined for ${settings.name}')),
            ));
    }
  }
}

class First extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          icon: Icon(Icons.add),
          onPressed: () {
            Get.snackbar("hi", "i am a modern snackbar");
          },
        ),
        title: Text('First Route'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('Open route'),
          onPressed: () {
            Get.toNamed("/second");
          },
        ),
      ),
    );
  }
}

class Second extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          icon: Icon(Icons.add),
          onPressed: () {
            Get.snackbar("hi", "i am a modern snackbar");
          },
        ),
        title: Text('second Route'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('Open route'),
          onPressed: () {
            Get.toNamed("/third");
          },
        ),
      ),
    );
  }
}

class Third extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () => Get.back(),
        child: Icon(Icons.arrow_back),
      ),
      appBar: AppBar(
        title: Text("Third Route"),
      ),
      body: StreamBuilder<List<Job>>(
          stream: JobBloc().jon,
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              List<Job> data = snapshot.data;
              return ListView.builder(
                  itemCount: data.length,
                  itemBuilder: (context, index) {
                    return ListTile(
                      title: Text(data[index].company,
                          style: TextStyle(
                            fontWeight: FontWeight.w500,
                            fontSize: 20,
                          )),
                      subtitle: Text(data[index].description),
                    );
                  });
            } else if (snapshot.hasError) {
              return Text("${snapshot.error}");
            }
            return Center(child: CircularProgressIndicator());
          }),
    );
  }
}

class MiddleWare {
  static observer(Routing routing) {
    if (routing.current == "/third") {
      print(routing.current);
      // Fill your class with data
      JobBloc().fetchData();
    } else if (routing.previous == "/third") {
      JobBloc().dispose();
    }
  }
}

class JobBloc {
  //create private instance
  static JobBloc _instance;
  // create a factory than give always same instance
  factory JobBloc() {
    if (_instance == null) _instance = JobBloc._();
    return _instance;
  }
  JobBloc._();

  //create a Stream
  StreamController<List<Job>> _job = StreamController<List<Job>>.broadcast();

  fetchData() async {
    // fetch data from api
    List<Job> data = await Api.result();
    //add result on stream
    _job.add(data);
  }

  // expose the stream
  get jon => _job.stream;

  dispose() {
    //close the stream
    _job.close();
    //Assign your class to null to reset your instance and have GB clear your class from memory to save resources.
    _instance = null;
  }
}

class Api {
  static Future<List<Job>> result() async {
    //fetch data from internet
    http.Response response =
        await http.get("https://mock-json-service.glitch.me/");
    if (response.statusCode == 200) {
      // Transform the response string into an object
      List jsonResponse = json.decode(response.body);
      //Iterate each object in a list and return it
      return jsonResponse.map((job) => Job.fromJson(job)).toList();
    } else {
      // show one snackbar on error case
      Get.snackbar("Error", "Your API denied this request");
      return [];
    }
  }
}

// create a Model class. I use https://app.quicktype.io/ to autogenerate it
class Job {
  final int id;
  final String position;
  final String company;
  final String description;

  Job({this.id, this.position, this.company, this.description});

  factory Job.fromJson(Map<String, dynamic> json) {
    return Job(
      id: json['id'],
      position: json['position'],
      company: json['company'],
      description: json['description'],
    );
  }
}

Note: We don't need any Stateful widgets.
Every time you leave the screen, your block class will be removed from memory.
If the connection fails, a snackbar will be displayed to alert the user (this is one of the things that is only possible with Get, it would be impossible to call a snackbar of the class API using the default framework).
If you have 10 screens, and you want the data to be updated when the user returns from a screen, this is also possible.
Note2: I am not recommending that you do all your projects like this, it is just an example of possibilities that the Framework gives you, and a way to make your application practically Stateless, which can be advantageous in some projects, but bad in others. If you have a TextEditController, for example, your class must be StatefulWidget, never StatelessWidget.

from getx.

jlubeck avatar jlubeck commented on May 13, 2024

Hey @jonataslaw thank you a lot for this, I got caught up with other projects, but I'm trying this now.
By any chance Is there a place where you hang out to chat about flutter? I wouldn't want to keep making tickets for simple stuff that is outside the scope of the library..

from getx.

jlubeck avatar jlubeck commented on May 13, 2024

This worked like a charm. Thank you for the input Jonny

from getx.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.