Skyla  Feeney

Skyla Feeney

1591410060

The Tale of RxDart - Brian Egan

We’ll start in the early days of Flutter, in the time before any state management packages were published, StreamBuilder was nowhere to be found, and Gitter was still a viable chat solution. In this Wild West, how could folks architect their apps?

#flutter

What is GEEK

Buddha Community

The Tale of RxDart - Brian Egan
Skyla  Feeney

Skyla Feeney

1591410060

The Tale of RxDart - Brian Egan

We’ll start in the early days of Flutter, in the time before any state management packages were published, StreamBuilder was nowhere to be found, and Gitter was still a viable chat solution. In this Wild West, how could folks architect their apps?

#flutter

Rxdart Streaming Shared Preferences

rx_shared_preferences 

  • Shared preference with rxdart Stream observation.
  • Reactive shared preferences for Flutter.
  • Reactive stream wrapper around SharedPreferences.
  • This package provides reactive shared preferences interaction with very little code. It is designed specifically to be used with Flutter and Dart.

Note

Since version 1.3.4, this package is an extension of rx_storage package.

More detail about returned Stream

It's a single-subscription Stream (ie. it can only be listened once).

Stream will emit the value (nullable) or a TypeError as its first event when it is listen to.

It will automatically emit value when value associated with key was changed successfully (emit null when value associated with key was removed or set to null).

When value read from Storage has a type other than expected type:

  • If value is null, the Stream will emit null (this occurred because null can be cast to any nullable type).
  • Otherwise, the Stream will emit a TypeError.

Can emit two consecutive data events that are equal. You should use Rx operator like distinct (More commonly known as distinctUntilChanged in other Rx implementations) to create an Stream where data events are skipped if they are equal to the previous data event.

Key changed:  |----------K1---K2------K1----K1-----K2---------> time
              |                                                
Value stream: |-----@----@------------@-----@-----------------> time
              |    ^                                      
              |    |
              |  Listen(key=K1)
              |
              |  @: nullable value or TypeError

Getting Started

In your flutter project, add the dependency to your pubspec.yaml

dependencies:
  ...
  rx_shared_preferences: ^2.2.0

Usage

1. Import and instatiance

  • Import rx_shared_preferences.
import 'package:rx_shared_preferences/rx_shared_preferences.dart';
  • Wrap your SharedPreferences in a RxSharedPreferences.
// via constructor.
final rxPrefs = RxSharedPreferences(await SharedPreferences.getInstance());
final rxPrefs = RxSharedPreferences(SharedPreferences.getInstance()); // await is optional
final rxPrefs = RxSharedPreferences.getInstance(); // default singleton instance

// via extension.
final rxPrefs = (await SharedPreferences.getInstance()).rx;

NOTE: When using RxSharedPreferences.getInstance() and extension (await SharedPreferences.getInstance()).rx, to config the logger, you can use RxSharedPreferencesConfigs.logger setter.

2. Add a logger (optional)

You can add logger optional parameter to RxSharedPreferences constructor. The logger will log messages about operations (such as read, write) and stream events. This package provides two RxSharedPreferencesLoggers:

  • RxSharedPreferencesDefaultLogger.
  • RxSharedPreferencesEmptyLogger.
final rxPrefs = RxSharedPreferences(
  SharedPreferences.getInstance(),
  kReleaseMode ? null : RxSharedPreferencesDefaultLogger(),
  // disable logging when running in release mode.
);

NOTE: To disable logging when running in release mode, you can pass null or const RxSharedPreferencesEmptyLogger() to RxSharedPreferences constructor or use RxSharedPreferencesConfigs.logger setter.

NOTE: To prevent printing ↓ Disposed successfully → DisposeBag#....

import 'package:disposebag/disposebag.dart' show DisposeBagConfigs;
void main() {
  DisposeBagConfigs.logger = null;
}

3. Select stream and observe

  • Then, just listen Stream, transform Stream through operators such as (map, flatMap, etc...).
  • If you need listen to this Stream many times, you can use broadcast operators such as share, shareValue, publish, publishValue, etc...
// Listen
rxPrefs.getStringListStream('KEY_LIST').listen(print); // [*]

// Broadcast stream
rxPrefs.getStringListStream('KEY_LIST').share();
rxPrefs.getStringListStream('KEY_LIST').shareValue();
rxPrefs.getStringListStream('KEY_LIST').asBroadcastStream();

// Transform stream
rxPrefs.getIntStream('KEY_INT')
  .map((i) => /* Do something cool */)
  .where((i) => /* Filtering */)
  ...

// must **use same rxPrefs** instance when set value and select stream
await rxPrefs.setStringList('KEY_LIST', ['Cool']); // [*] will print ['Cool']

In the previous example we re-used the RxSharedPreferences object rxPrefs for all writing operations. All writing operations must go through this object in order to correctly notify subscribers.

In Flutter, you:

Can create global RxSharedPreferences instance.

Can use default singleton instance RxSharedPreferences.getInstance()

Can use InheritedWidget/Provider to provide a RxSharedPreferences instance (create it in main function) for all widgets (recommended). See example/main.

// An example for wrong usage.
rxPrefs1.getStringListStream('KEY_LIST').listen(print); // [*]

rxPrefs2.setStringList('KEY_LIST', ['Cool']); // [*] will not print anything
  • Streams APIs (via extension methods).
  Stream<Object?>              getObjectStream(String key, [Decoder<Object?>? decoder]);
  Stream<bool?>                getBoolStream(String key);
  Stream<double?>              getDoubleStream(String key);
  Stream<int?>                 getIntStream(String key);
  Stream<String?>              getStringStream(String key);
  Stream<List<String>?>        getStringListStream(String key);
  Stream<Set<String>>          getKeysStream();
  
  Future<void>                 executeUpdateBool(String key, Transformer<bool?> transformer);
  Future<void>                 executeUpdateDouble(String key, Transformer<double?> transformer);
  Future<void>                 executeUpdateInt(String key, Transformer<int?> transformer);
  Future<void>                 executeUpdateString(String key, Transformer<String?> transformer);
  Future<void>                 executeUpdateStringList(String key, Transformer<List<String>?> transformer);
  • All methods from RxStorage (RxSharedPreferences implements RxStorage).
  Future<void>                 executeUpdate<T extends Object>(String key, Decoder<T?> decoder, Transformer<T?> transformer, Encoder<T?> encoder);
  Stream<T?>                   observe<T extends Object>(String key, Decoder<T?> decoder);
  Stream<Map<String, Object?>> observeAll();
  Future<void>                 dispose();

4. Get and set methods like to SharedPreferences

  • RxSharedPreferences is like to SharedPreferences, it provides read, write functions (via extension methods).
  Future<Object?>              getObject(String key, [Decoder<Object?>? decoder]);
  Future<bool?>                getBool(String key);
  Future<double?>              getDouble(String key);
  Future<int?>                 getInt(String key);
  Future<Set<String>>          getKeys();
  Future<String?>              getString(String key);
  Future<List<String>?>        getStringList(String key);

  Future<Map<String, Object?>> reload();
  Future<void>                 setBool(String key, bool? value);
  Future<void>                 setDouble(String key, double? value);
  Future<void>                 setInt(String key, int? value);
  Future<void>                 setString(String key, String? value);
  Future<void>                 setStringList(String key, List<String>? value);
  • All methods from Storage (RxSharedPreferences implements Storage).
  Future<bool>                 containsKey(String key);
  Future<T?>                   read<T extends Object>(String key, Decoder<T?> decoder);
  Future<Map<String, Object?>> readAll();
  Future<void>                 clear();
  Future<void>                 remove(String key);
  Future<void>                 write<T extends Object>(String key, T? value, Encoder<T?> encoder);

5. Dispose

You can dispose RxSharedPreferences when is no longer needed. Just call rxPrefs.dispose(). Usually you call this method on dispose of a State

Example demo

| | | Use this package as a library

Depend on it

Run this command:

With Dart:

 $ dart pub add rx_shared_preferences

With Flutter:

 $ flutter pub add rx_shared_preferences

This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get):

dependencies:
  rx_shared_preferences: ^2.2.0

Alternatively, your editor might support dart pub get or flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:rx_shared_preferences/rx_shared_preferences.dart';

example/lib/main.dart

import 'package:example/home.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_provider/flutter_provider.dart';
import 'package:rx_shared_preferences/rx_shared_preferences.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();

  /// Singleton instance for app
  final rxPrefs = RxSharedPreferences(
    SharedPreferences.getInstance(),
    kReleaseMode ? null : const RxSharedPreferencesDefaultLogger(),
  );

  runApp(
    Provider.value(
      rxPrefs,
      child: const MyApp(),
    ),
  );
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'RxSharedPreferences example',
      theme: ThemeData.dark(),
      home: const MyHomePage(),
    );
  }
} 

Download Details:

Author: hoc081098

Source Code: https://github.com/hoc081098/rx_shared_preferences

#flutter #rxdart 

Some Extension Methods and Classes Built on top of RxDart

rxdart_ext .Some extension methods and classes built on top of RxDart - RxDart extension.

RxDart compatibility

rxdartrxdart_ext
0.26.0<=0.0.1
>=0.27.0 <=0.27.1>=0.1.0 <=0.1.1
>=0.27.2>=0.1.2

API

1. Single

A Stream which emits single event, either data or error, and then close with a done-event.

Success case: ------------(*)|------
                         data done

Failure case: ------------(x)|------
                        error done

NOTE: Single extends Stream, so all operators and transformers for Stream are available for Single as well.

Single is suitable for one-shot operations (likes Future but lazy - executes when listening), eg. making API request, reading local storage, ...

import 'package:http/http.dart' as http;

Single<User> fetchUser(String id) {
  return Single.fromCallable(() => http.get(Uri.parse('$baseUrl/users/$id')))
      .flatMapSingle((res) => res.statusCode == HttpStatus.ok
          ? Single.value(res.body)
          : Single.error(Exception('Cannot fetch user with id=$id')))
      .map((body) => User.fromJson(jsonEncode(body)));
}

Create Single

Factory constructors.

Static methods provided by RxSingles class

Convert others to Single via extensions.

Operators for Single (returns a Single instead of Stream)

2. Operators for Stream

3. StateStream

A Stream that provides synchronous access to the last emitted item, and two consecutive values are not equal. The equality between previous data event and current data event is determined by StateStream.equals. This Stream always has no error.

Example

Useful for Flutter BLoC pattern - StreamBuilder, expose broadcast state stream to UI, can synchronous access to the last emitted item, and distinct until changed

  • [x] Distinct: distinct until changed.
  • [x] Value: can synchronous access to the last emitted item.
  • [x] NotReplay: not replay the latest value.
  • [x] Connectable: broadcast stream - can be listened to multiple time.
                                Stream (dart:core)
                                   ^
                                   |
                                   |
            |--------------------------------------------|
            |                                            |
            |                                            |
        ValueStream (rxdart)                             |
            ^                                            |
            |                                            |
            |                                            |
    NotReplayValueStream (rxdart_ext)                    |
            ^                                    ConnectableStream (rxdart)
            |                                            ^
            |                                            |
       StateStream (rxdart_ext)                          |
            ^                                            |
            |                                            |
            |------------                     -----------|
                        |                     |
                        |                     |
                     StateConnectableStream (rxdart_ext)
class UiState { ... }

final Stream<UiState> state$ = ...;

final StateConnectableStream<UiState> state$ = state$.publishState(UiState.initial());
final connection = state$.connect();

StreamBuilder<UiState>(
  initialData: state$.value,
  stream: state$,
  builder: (context, snapshot) {
    final UiState state = snapshot.requireData;
    
    return ...;
  },
);

4. NotReplayValueStream

A Stream that provides synchronous access to the last emitted item, but not replay the latest value.

Tim Cook dancing to the sound of a permissive license.

Use this package as a library

Depend on it

Run this command:

With Dart:

 $ dart pub add rxdart_ext

With Flutter:

 $ flutter pub add rxdart_ext

This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get):

dependencies:
  rxdart_ext: ^0.1.2

Alternatively, your editor might support dart pub get or flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:rxdart_ext/rxdart_ext.dart';

example/lib/rxdart_ext_example.dart

import 'package:rxdart_ext/rxdart_ext.dart';

void main() {
  Stream.fromIterable([1, 2, 3, 4]).debug().collect();

  final state$ = StateSubject(1);
  state$.debug(identifier: '<<State>>').collect();
  print(state$.value);

  RxSingles.zip2(
    Single.value(1).delay(const Duration(milliseconds: 100)),
    Single.fromCallable(
        () => Future.delayed(const Duration(milliseconds: 200), () => 2)),
    (int p0, int p1) => p0 + p1,
  ).doOnData(state$.add).listen((_) => print(state$.value));
} 

Download Details:

Author: hoc081098

Source Code: https://github.com/hoc081098/rxdart_ext

#dart #rxdart 

Kabanda  Nat

Kabanda Nat

1624363200

There and Back Again: A Browser's Tale, Part 1

Most often a browser’s journey begins with a  Uniform Resource Locator , or, as it’s more commonly referred to as, a URL. Put simply a URL is an address. Put a little less simply a URL is a specific type of  Uniform Resource Identifier  (URI) which is a sequence of character that identifies a resource, and, for our purposes, a website. Diving a bit deeper you’ll find that the URL structure is surprisingly robust as it contains:

  • Protocol: the (network) method of access to the resource.
  • Domain: the address where the resources can be accessed, these are often used in place of an IP address because they’re easier to remember.
  • Path: a more precise location for accessing specific resources.
  • Query string: where parameters and values are stored.
  • Fragment: an internal page reference, commonly referred to as an anchor.

#web dev #a browser's tale

Introduction to D-Tale Library

D-Tale is python library to visualize pandas data structure. D-Tale is interactive graphical user interface tool based on the Flask and React based tool. D-Tale is the one of the easiest ways of visualizing and analyzing pandas data structure.

Installation of D-tale library:

Pip install dtale

#conda environment

Conda install dtale

Importing dtale library. Using seaborn library to load dataset. Here, I am using Iris dataset.

#pandas-dataframe #visualization #eda #visualization-tool #python #introduction to d-tale library