How to build a bottom navigation bar in Flutter

Mobile applications often have various categories of content to offer. The Google Play Store app, for example, presents its content in categories such as games, apps, movies, and books. In Flutter apps, the BottomNavigationBar widget enables users to see any one category as the app starts and quickly look at the others with just the tap of a finger.

Flutter Logo

In this tutorial, we’ll tell you everything you need to know about BottomNavigationBar in Flutter. We’ll demonstrate how it works, walk through some use cases, and show you how to customize the BottomNavigationBar widget in your Flutter app.

Here’s what we’ll cover:

What is BottomNavigationBar in Flutter?

BottomNavigationBar is a widget that displays a row of small widgets at the bottom of a Flutter app. Usually, it’s used to show around three to five items. Each item must have a label and an icon. BottomNavigationBar allows you to select one item at a time and quickly navigate to a given page.

Now let’s walk through the process of creating a simple BottomNavigationBar step by step. The finished product will look as follows:

Finished Product

Showing BottomNavigationBar

The BottomNavigationBar widget is given to the bottomNavigationBarproperty of Scaffold:

Scaffold(
  appBar: AppBar(
    title: const Text('BottomNavigationBar Demo'),
  ),
  bottomNavigationBar: BottomNavigationBar(
    items: const <BottomNavigationBarItem>[
      BottomNavigationBarItem(
        icon: Icon(Icons.call),
        label: 'Calls',
      ),
      BottomNavigationBarItem(
        icon: Icon(Icons.camera),
        label: 'Camera',
      ),
      BottomNavigationBarItem(
        icon: Icon(Icons.chat),
        label: 'Chats',
      ),
    ],
  ),
);

BottomNavigationBar has a required property called itemsitems accept a widget of a type BottomNavigationBarItemBottomNavigationBarItem is simply used to show the actual item inside BottomNavigationBar.

The above code just displays the BottomNavigationBar with the first item selected as the default. It does not change the selection yet as we click on the other items:

First Item Selected

Showing a selection of items

To show the selection of other items, we’ll use two properties: onTap and currentIndex.

int _selectedIndex = 0; //New
BottomNavigationBar(
  items: const <BottomNavigationBarItem>[
    ...
  currentIndex: _selectedIndex, //New
  onTap: _onItemTapped,         //New
)
//New
void _onItemTapped(int index) {
  setState(() {
    _selectedIndex = index;
  });
}

The _selectedIndex variable holds the value of the currently selected item. _selectedIndex is given to the currentIndex property.

The _onItemTapped() callback is assigned to onTap of BottomNavigationBar, which returns the index when the item is tapped. Simply assigning a currently selected item index to _selectedIndex and doing setState will show the item as selected in BottomNavigationBar.

Selecting Item

Displaying the page of the selected item

As of now, we don’t have any page to show based on the selected item. So let’s go ahead and great it:

//New
static const List<Widget> _pages = <Widget>[
  Icon(
    Icons.call,
    size: 150,
  ),
  Icon(
    Icons.camera,
    size: 150,
  ),
  Icon(
    Icons.chat,
    size: 150,
  ),
];
Scaffold(
  appBar: AppBar(
    title: const Text('BottomNavigationBar Demo'),
  ),
  body: Center(
    child: _pages.elementAt(_selectedIndex), //New
  ),
  bottomNavigationBar: BottomNavigationBar(
    ...
  ),
);

_pages hold a list of widgets. For simplicity, we’re just showing a big icon of the item itself.

Showing one page in the center of the screen from _pages based on the _selectedIndex of the item will do the rest of the magic.

Now we have BottomNavigationBar up and running:

Bottom Navigation Working

The illustration below shows how the code translates into the design:

Code Translated to Design

Customizing the BottomNavigationBar

BottomNavigationBar has a lot of options to customize it per your need. Let’s zoom in on some of the properties you can customize.

Background color

You may want to change the background color of the BottomNavigationBar to match your brand. You do that simply by using the backgroundColor property.


Over 200k developers use LogRocket to create better digital experiences

Learn more →

BottomNavigationBar(
  backgroundColor: Colors.blueAccent,
  items: const <BottomNavigationBarItem>[
    ...
  ],
)

Blue Accent

Elevation

By default, the BottomNavigationBar is set to elevate 8 points from the surface so that it appears on top of pages. You can set this property to any value:

BottomNavigationBar(
  backgroundColor: Colors.white10,
  elevation: 0,
  items: const <BottomNavigationBarItem>[
   ...
  ],
)

Elevation Value

Icon size

You can shrink or magnify the size of all the icons at once using iconSize property:

BottomNavigationBar(
  iconSize: 40,
  items: const <BottomNavigationBarItem>[
    ...
  ],
)

Icon Size Updated

Mouse cursor

When running on the web, you can customize the mouse cursor when it hovers over an item on the BottomNavigationBar:

BottomNavigationBar(
  mouseCursor: SystemMouseCursors.grab,
  items: const <BottomNavigationBarItem>[
    ...
  ],
)

Mouse Hovering Over Icons

Selected item

You can make the selected item appear different from an unselected one using the several selected properties of BottomNavigationBar:

BottomNavigationBar(
  selectedFontSize: 20,
  selectedIconTheme: IconThemeData(color: Colors.amberAccent, size: 40),
  selectedItemColor: Colors.amberAccent,
  selectedLabelStyle: TextStyle(fontWeight: FontWeight.bold),
  items: const <BottomNavigationBarItem>[
    ...
  ],
)

Yellow Highlighted Icons

Unselected items

You may also want to change the look and feels of unselected items. BottomNavigationBar has a few unselected properties that you can use:

BottomNavigationBar(
  unselectedIconTheme: IconThemeData(
    color: Colors.deepOrangeAccent,
  ),
  unselectedItemColor: Colors.deepOrangeAccent,
  items: const <BottomNavigationBarItem>[
    ...
  ],
)

Different Icon Properties

Removing labels

If you want to get rid of the labels entirely, you can use showSelectedLabels and showUnselectedLabels:

BottomNavigationBar(
  iconSize: 40,
  showSelectedLabels: false,
  showUnselectedLabels: false,
  items: const <BottomNavigationBarItem>[
    ...
  ],
)

No Labels

Highlighting the selected item

You can emphasize the selected item by setting the BottomNavigationBar type to BottomNavigationBarType.shifting:

BottomNavigationBar(
  type: BottomNavigationBarType.shifting,
  selectedFontSize: 20,
  selectedIconTheme: IconThemeData(color: Colors.amberAccent),
  selectedItemColor: Colors.amberAccent,
  selectedLabelStyle: TextStyle(fontWeight: FontWeight.bold),
  items: const <BottomNavigationBarItem>[
    ...
  ],
)

Emphasized Select

How to preserve the state of pages

Although the basic version of BottomNavigationBar is working well, we have one problem: whatever action — e.g., searching, filtering, entering text, scrolling through a list, filling out a contact form, etc. — is being performed on the page will be lost upon selecting another item from the BottomNavigationBar:

State of Pages Being Lost

In the demo above, we’re trying to find a contact. When we switch to the camera section before we finish our search and then return to the chat section, the previously entered text is completely gone.

Fear not — the solution is pretty simple. Simply replace the existing widget with IndexedStack. The IndexedStack widget holds a stack of widgets but shows only one at a time. Since all the widgets stay in the stack, the state is preserved.

//Before
Center(
  child: _pages.elementAt(_selectedIndex),
)
//After
IndexedStack(
  index: _selectedIndex,
  children: _pages,
)

The index property is used to show one page from the _pages, which is given to the children property.

Index Property

How to include TabBar with BottomNavigationBar

Sometimes a single page is not enough to cover a wide range of subcategories within a parent category inside BottomNavigationBar. For example, the Google Play Store app has subcategories labeled For you, Top charts, Kids, etc. A scenario like this calls for the Flutter TabBar widget.

For demonstration purposes, let’s try to add TabBar for incoming, outgoing, and missed calls inside the calls section, as shown below:

Incoming, Outgoing, and Missed Calls Sections

The overall structure of BottomNavigationBar remains the same. You may need to create a separate class for the page in which you want to include a TabBar. For that purpose, the CallsPage is created and added to the list of pages.

static const List<Widget> _pages = <Widget>[
  CallsPage(),
  // Camera page
  // Chats page
];

The CallsPage looks like this:

DefaultTabController(
  length: 3,
  child: Scaffold(
    appBar: AppBar(
      flexibleSpace: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          TabBar(
            tabs: [
              Tab(
                text: 'Incoming',
              ),
              Tab(
                text: 'Outgoing',
              ),
              Tab(
                text: 'Missed',
              ),
            ],
          )
        ],
      ),
    ),
    body: TabBarView(
      children: [
        IncomingPage(),
        OutgoingPage(),
        MissedPage(),
      ],
    ),
  ),
);

Here’s the output:

Calls Page Icons

Hiding BottomNavigationBar on scroll

When building a Flutter app, you always want to utilize the screen space as efficiently as possible. When a user is scrolling through a long list of items on one of the pages in your app, you can hide the BottomNavigationBar smoothly. This behavior improves the user experience because you’re showing only content that is required at that moment.

As of now, the BottomNavigationBar stays as it is while scrolling through the list of outgoing calls:

Bottom Navigation Stays

Let’s walk through the process of hiding the BottomNavigationBar step by step.

First, wrap your list view inside the NotificationListener widget. NotificationListener listens to the scroll notification happening on the ListView.

NotificationListener<ScrollNotification>(
  onNotification: _handleScrollNotification,
  child: Scaffold(
    body: Center(
      child: ListView.builder(
        itemCount: items.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text('${items[index]}'),
          );
        },
      ),
    ),
  ),
);

Next, implement the _handleScrollNotification method to determine the scroll direction. Notify the page that hosts the BottomNavigationBar to hide it when the user scrolls down.

bool _handleScrollNotification(ScrollNotification notification) {
  if (notification.depth == 0) {
    if (notification is UserScrollNotification) {
      final UserScrollNotification userScroll = notification;
      switch (userScroll.direction) {
        case ScrollDirection.forward:
          widget.isHideBottomNavBar(true);
          break;
        case ScrollDirection.reverse:
          widget.isHideBottomNavBar(false);
          break;
        case ScrollDirection.idle:
          break;
      }
    }
  }
  return false;
}

Wrap the BottomNavigationBar inside the SizeTransition widget. SizeTransition animates the size of BottomNavigationBar.

AnimationController animationController =
    AnimationController(vsync: this, duration: Duration(milliseconds: 300));
SizeTransition(
  sizeFactor: animationController,
  axisAlignment: -1.0,
  child: BottomNavigationBar(
    items: const <BottomNavigationBarItem>[
      ...
    ],
  ),
)

Start hiding animation on receiving the callback from the page that has the ListView.

CallsPage(
  isHideBottomNavBar: (isHideBottomNavBar) {
    isHideBottomNavBar
        ? animationController.forward()
        : animationController.reverse();
  },
)

Here is the result:

Scrolling Outgoing Calls

That’s it! The full code for this Flutter BottomNavigationBar example can be found on GitHub.

Conclusion

In this tutorial, we showed how to integrate BottomNavigationBar and customize it. We also learned various use cases with examples that you’ll likely encounter while developing a full-fledged Flutter app. I hope the practical examples we examined in this article helped you understand these important concepts.

Mastering Flutter App Architecture with Bloc

When it comes to developing mobile applications, Flutter stands out as one of the most powerful and user-friendly frameworks available. It allows developers to create functional apps with ease. However, building an app, no matter how simple or complex, without a well-structured architecture is akin to constructing a house without a blueprint or plan – it’s bound to lead to chaos and confusion.

In the early stages of app development, you might not fully appreciate the importance of having a robust architecture. Small apps can often get away with disorganized code. However, as your project scales, incorporating proper architectural principles becomes critical. Picture this: a production-level application with numerous screens, animations, methods, classes, and other components. Without a well-defined architecture, it’s easy to lose track of how everything fits together and communicates.

This is where architectural patterns come into play. They provide the structure, organization, and guidelines necessary to maintain clean, readable, testable, and maintainable code. In the world of Flutter, one such architectural pattern that has gained significant popularity is the Bloc architecture.

What is Bloc?

Bloc, which stands for Business Logic Component, is more than just a tool for managing the state of an application. It’s actually an architectural design pattern that empowers developers to create strong, production-ready apps.

In the context of software development, business logic, or domain logic, refers to the part of the program that handles real-world business rules. These rules dictate how data can be created, stored, and modified, essentially defining the core functionality of the application.

Bloc Architecture Graphical Representation

Bloc architecture achieves a clear separation between the user interface (UI) and the business logic. In contrast to building an app without any architectural pattern, where you might find yourself writing logic directly within the UI components, Bloc encourages developers to isolate business logic in separate files. This separation makes it easier to manage, test, and comprehend the inner workings of a complex application.

Key Components of Bloc

The Bloc architecture comprises four primary layers, each with a specific role and responsibility:

1. UI (Presentation Layer):

This layer is where all the components and widgets that the user interacts with are defined. It includes everything that’s visible to the user, from buttons and forms to images and text.

2. Bloc (Business Logic Layer):

The Bloc layer acts as a mediator between the UI and the Data layer. It takes user-triggered events, such as button presses or form submissions, as input. Then, it processes these events, orchestrates the business logic, and responds to the UI with the relevant state changes.

3. Data Layer:

The Data layer is responsible for managing data sources, including databases, APIs, and local storage. It fetches, stores, and updates data according to the requirements of the business logic.

4. Repository Layer:

The Repository layer acts as a bridge between the Bloc and Data layers. It abstracts the data source interactions, providing a consistent and simplified API for the Bloc layer to access data. This abstraction allows you to switch between different data sources without affecting the business logic.

Event and State

In Bloc-based architecture, two crucial terms to understand are Event and State.

1. Event:

An Event represents user actions, such as button clicks or form submissions, triggered in the UI. It encapsulates information about the action and delivers it to the Bloc for handling.

2. State:

The UI updates based on the State it receives from the Bloc. Different states can represent various UI conditions, such as:

  • Loading State (displaying a progress indicator)
  • Loaded State (showing the actual widget with data)
  • Error State (indicating that something went wrong).

Bloc Pattern in Flutter - Event & State

Implementing Bloc:

Let us take an example of a project using the Weather App. Let’s integrate the bloc pattern inside it to illustrate how the bloc works on a project.

Step 1: Setting up your project

flutter create weather_app

Step 2: Installing Bloc

Go to your pubspec.yaml file and add the following dependencies.

flutter_bloc:
bloc:
equatable:

Step 3: Folder structure

The folder structure is like this:

weather_app/

|-- lib/

|   |-- bloc/

|   |   |-- weather_bloc/

|   |   |   |-- weather_bloc.dart

|   |   |   |-- weather_event.dart

|   |   |   |-- weather_state.dart

|   |-- data/

|   |   |-- repository/

|   |   |   |-- weather_repo.dart

|   |   |-- models/

|   |   |   |-- weather.dart

|   |-- presentation/

|   |   |-- constants/

|   |   |   |-- app_string.dart

|   |   |   |-- colors.dart

|   |   |   |-- image_assets.dart

|   |   |   |-- styles.dart

|   |   |-- screens/

|   |   |   |-- search_page.dart

|   |   |   |-- show_weather.dart

|   |   |-- widgets/

|   |   |   |-- column_data_widget.dart

|   |   |   |-- pwh.dart

|-- main.dart

Step 4: Setup Data layer

The data layer consists of the repository which calls an API to fetch the weather data based on city enter.

i) weather_repo.dart

class WeatherRepo {
  Future<WeatherModel> getWeather(String city) async {
   final result = await http.get(Uri.parse(weather_base_url));
   if (result.statusCode != 200) {
     throw Exception();
   }
   final response = json.decode(result.body);
   return WeatherModel.fromJson(response);
 }
}

ii) weather.dart

class WeatherModel {
 final dynamic temp;
 final dynamic icon;

 WeatherModel( {
     this.temp,
     this.icon,
   });

 factory WeatherModel.fromJson(Map<String, dynamic> json) {
   return WeatherModel(
     temp: json["main"]["temp"],
     icon: json["weather"][0]["icon"],
   );
 }
}

Step 5: Generate bloc files

i) weather_bloc.dart

class WeatherBloc extends Bloc<WeatherEvent, WeatherState> {
 final WeatherRepo weatherRepo;
 WeatherBloc({required this.weatherRepo}) : super(WeatherIsNotSearched()) {
   on<FetchWeather>(_onFetchWeather);
 }

 Future<void> _onFetchWeather(
   FetchWeather event,
   Emitter<WeatherState> emit,
 ) async {
   emit(WeatherIsLoading());
   try {
     final weather = await weatherRepo.getWeather(event.city);
     final city = event.city;

     emit(WeatherIsLoaded(weather, city));
   } catch (_) {
     emit(WeatherFailure());
   }
 }
}  

Let’s break down the provided code into points:

  • The WeatherBloc class is extending the Bloc class, and it’s designed to handle events of type WeatherEvent and manage states of type WeatherState.
  • In the constructor, it takes an instance of WeatherRepo as a required parameter. This repository likely handles data retrieval, such as fetching weather information.
  • Upon initialization of the WeatherBloc, it starts with an initial state of WeatherIsNotSearched().
  • The on method is used to listen to a specific event type, in this case, FetchWeather. When a FetchWeather event occurs, it will call the _onFetchWeather method to handle it.
  • Inside _onFetchWeather, the emit method is used to change the state to WeatherIsLoading(). This informs the UI that the app is currently in the process of fetching weather data.
  • It then attempts to fetch weather data from the weatherRepo by calling weatherRepo.getWeather(event.city) where event.city is the city for which the weather data is requested.
  • If the data is successfully retrieved, it sets the weather and city variables with the obtained data and the requested city.
  • It then updates the state to WeatherIsLoaded(weather, city). This indicates that the weather data has been successfully fetched and is ready for display in the UI.
  • If any errors occur during the data fetching process (caught by the catch block), it changes the state to WeatherFailure(). This state signifies that there was an issue while attempting to fetch the weather data.

ii) weather_state.dart

class WeatherState extends Equatable {
 const WeatherState();

 @override
 List<Object> get props => [];
}

class WeatherIsNotSearched extends WeatherState {}

class WeatherIsLoading extends WeatherState {}

class WeatherIsLoaded extends WeatherState {
 final dynamic _weather;
 final dynamic city;

 const WeatherIsLoaded(this._weather, this.city);

 WeatherModel get getWeather => _weather;

 @override
 List<Object> get props => [_weather,city];
}
class WeatherFailure extends WeatherState {}

Let’s break down each part:

  • WeatherState is a class that extends Equatable. It’s the base class for all the different states that the BLoC can have, and it’s used to compare state objects for equality.
  • WeatherIsNotSearched is a subclass of WeatherState. This state represents the initial state of the app, indicating that the user hasn’t searched for weather information yet. It’s used to set the BLoC’s initial state when the app starts.
  • WeatherIsLoading is another subclass of WeatherState. This state is used to indicate that the app is currently in the process of fetching weather data. It’s set when the BLoC is awaiting the response from a data source.
  • WeatherIsLoaded is a more complex subclass of WeatherState. This state represents that weather data has been successfully fetched. It holds two private variables, _weatherandcity`, which store the actual weather data and the city for which it was fetched, respectively.
    • The constructor takes _weather and city as parameters when it’s created.
    • There’s a getWeather method that allows you to access the weather data. It returns _weather.
  • WeatherFailure is yet another subclass of WeatherState. This state is used when there’s an error or failure in fetching weather data. It’s set if an exception occurs during the data retrieval process.

iii) weather_event.dart

class WeatherEvent extends Equatable {
 const WeatherEvent();

 @override
 List<Object> get props => [];
}
class FetchWeather extends WeatherEvent {
 final String city;
 const FetchWeather({required this.city});

  dynamic get getCity => city;

 @override
 List<Object> get props => [city];
}

class ResetWeather extends WeatherEvent {}

Let’s break down each part:

  • WeatherEvent is a base class that extends Equatable. It serves as the parent class for all the different events that can trigger state changes in the BLoC. Equatable is used to compare event objects for equality.
  • FetchWeather is a subclass of WeatherEvent. This event represents the action of requesting weather data for a specific city. It contains a city parameter in its constructor, indicating the city for which the weather data is being requested.
    • The constructor takes the city as a required parameter when creating the event.
    • There’s a getCity method that allows you to access the city parameter.
    • The props list in the FetchWeather class is overridden to include a city in the list, enabling the comparison of two FetchWeather events based on their cities.

Step 6: Adding an event to the bloc

To compute a bloc you have to add an event to the bloc. Such that there is logic included for each event is triggered.

child: ElevatedButton(
         style: buttonStyle,
         onPressed: () {
                if (_formKey.currentState!.validate()) {
                    _formKey.currentState!.save();
                     weatherBloc.add(FetchWeather(city: cityController!.text));
                 }
              },
         child: const Text(
                  AppString.search,
                ),
         );

Step 7: Access bloc data to UI

Having crafted the BLoC and integrated all the necessary features, the next step involves making this BLoC accessible within the widget tree. This is essential for us to access and utilize the weather data, enabling its display on the screen. We also need to establish a connection with the “Get Weather” button.

Prior to this, it’s crucial to grasp the various widgets offered by the BLoC library:

  • BlocProvider: This widget facilitates providing access to the BLoC to the widget tree.
  • BlocBuilder: It’s a widget that listens to the BLoC’s state changes and rebuilds the UI accordingly.
  • BlocListener: This widget enables us to listen to state changes in the BLoC and execute specific actions based on those changes.
  • BlocConsumer: Similar to BlocBuilder, it also observes state changes in the BLoC but provides methods for both building and listening.
  • RepositoryProvider: A widget for providing repositories to the widget tree, allowing BLoCs to access data sources effectively.

i) Bloc Provider

BlocProvider is a widget that supplies a BLoC to its child widgets.

  • It’s used for dependency injection, ensuring the same BLoC instance is available to various widgets.
  • Place BlocProvider where all child widgets need access to the BLoC. In the case of a Flutter app, this often means wrapping it around the MaterialApp.
  • This enables us to access the BLoC using ** BlocProvider.of(context) ** .
  • By default, BlocProvider initializes the BLoC lazily, meaning it’s created when someone tries to use it. To change this, set the lazy parameter to false.
  • If you have multiple BLoCs, nest them inside one another for a hierarchical structure.
class MyApp extends StatelessWidget {
 const MyApp({Key? key}): super(key: key);

 @override
 Widget build(BuildContext context) {
   return BlocProvider(
     create: (context) => WeatherBloc(
       weatherRepo: WeatherRepo(),
     ),
     child: MaterialApp(
       debugShowCheckedModeBanner: false
       home: const WeatherPage(),
     ),
   );
 }
}

ii) Bloc Builder

  • BlocBuilder serves as a widget that facilitates updating the user interface in response to changes in the app’s state.
  • In our scenario, we aim to have the UI react to the user’s action of pressing the “Get Weather” button.
  • BlocBuilder automatically reconstructs the UI each time the state undergoes a change.
  • It’s crucial to position BlocBuilder around the specific widget that you want to refresh when the state changes.
  • While it’s possible to wrap the entire widget tree with BlocBuilder, this isn’t efficient. Imagine the processing resources and time required to rebuild the entire widget structure just to update a single Text widget.
  • Therefore, it’s advisable to enclose BlocBuilder around the widget that needs to be updated when the state changes.
  • In our case, the entire page should be updated because, when the user triggers the “Get Weather” button, we want to display a Circular Progress Indicator in place of the previous content.
  • As a result, we should incorporate BlocBuilder within the body of the widget.
BlocBuilder<WeatherBloc, WeatherState>(
             builder: (context, state) {
             if (state is WeatherIsLoading) {
                 return const Center(
                   child: CircularProgressIndicator());
               } else if (state is WeatherIsLoaded) {
                 return ShowWeather(weather:state.getWeather,city:state.city);
               } else {
                 return const Center(
                   child: Text("City not found"),
                 );
               }
             },
           );

iii) Bloc Listeners

  • BlocListener, as the name suggests, monitors state changes, much like BlocBuilder.
  • However, unlike BlocBuilder, it doesn’t construct the widget itself. Instead, it takes a single function called a “listener” which executes only once for each state change, excluding the initial state.
  • Its purpose is for actions like navigation, displaying a Snackbar, or showing a dialog.
  • It also includes a “bloc” parameter, which is only needed if you want to provide a BLoC that isn’t accessible through BlocProvider in the current context.
  • BlocListener’s “listenWhen” parameter works similarly to BlocBuilder’s “buildWhen.”
  • The primary role of BlocListener is not to build or update widgets, unlike BlocBuilder. It’s solely responsible for observing state changes and performing specific operations. These operations might include actions like navigating to other screens when the state changes or displaying a Snackbar in response to a particular state.
  • For instance, if you want to show a Snackbar when the app is in the “WeatherLoadInProgress” state, you can wrap the relevant content within BlocListener.
BlocListener<WeatherBloc, WeatherState>(listener: ((context, state) {
             if (state is WeatherFailure) {
               ScaffoldMessenger.of(context).showSnackBar(
                 const SnackBar(
                   content: Text("Something went wrong"),
                 ),
               );
             }
           })),

iii) Bloc Consumers

  • Currently, we’re utilizing BlocBuilder to create widgets and BlocListener to display Snack bars.
  • Is there a simpler way to merge these functionalities into a single widget? Absolutely!
  • BlocConsumer offers a solution that blends both BlocListener and BlocBuilder into one.
  • Instead of separately implementing BlocListener and BlocBuilder, we can now achieve this combination.
BlocConsumer<WeatherBloc, WeatherState>(
             listener: ((context, state) {
               if (state is WeatherFailure) {
                 ScaffoldMessenger.of(context).showSnackBar(
                   const SnackBar(
                     content: Text("Something went wrong"),
                   ),
                 );
               }
             }),
             builder: (context, state) {
               if (state is WeatherIsNotSearched) {
                 return weatherNotSearched(weatherBloc);
               } else if (state is WeatherIsLoading) {
                 return const Center(
                   child: CircularProgressIndicator(),
                 );
               } else if (state is WeatherIsLoaded) {
                 return ShowWeather(weather: state.getWeather, city: state.city);
               } else {
                 return const Center(
                   child: Text("City not found"),
                 );
               }
             },
           )

Benefits of using the Bloc architecture

  • Separation of concerns:

Bloc architecture separates the UI layer from the business logic layer. This makes the code more modular, reusable, and testable.

  • State management:

Bloc architecture provides a centralized way to manage the state of the app. This makes it easier to reason about the app’s behavior and ensure that the UI is always in sync with the state.

  • Predictable behaviour:

Bloc architecture makes the app’s behavior more predictable. This is because the UI is only updated when the state changes and the state is only changed in response to events.

  • Performance:

Bloc architecture can improve the performance of the app by reducing the number of unnecessary rebuilds. This is because the UI is only rebuilt when the state changes and the state is only changed in response to events.

  • Testability:

Bloc architecture makes the app more testable. This is because the business logic is isolated in the Bloc layer, which makes it easier to write unit tests.

Drawback:

  • Complexity:

The Bloc architecture can be difficult to learn for developers who are new to Flutter or state management patterns. It requires an understanding of Reactive Programming and can take time to master.

  • Boilerplate Code:

Setting up Bloc may require writing some boilerplate code, which can be seen as a drawback for small projects.

Overall, Bloc architecture is a powerful and flexible design pattern that can be used to build scalable and maintainable Flutter apps. It provides a number of benefits, including separation of concerns, state management, predictable behavior, performance, and testability.

Read more about Bloc Here

Management Skills

10 Important Management Skills

1. People Management Skills:

People management skills
Business meeting and teamwork concept

First of all, focus on your team, which consists of some great people. They have a lot to do. So you have to deal with demotivation and conflicts. Here you have to manage your people with emotional intelligence. Know about your team members on both the personal and professional levels.

You have to adapt your people management skills at their best to give feedback, understand values and understand each person in your team. Otherwise, you cannot connect properly with your team members and its effects on your project indirectly.

You need to exhibit your managerial quality and authority while holding back the ability to play your part as a member of a team.

2. Communication Skills:

Communication skills
Communication is the key of attraction

Effective leaders must have good communication skills including verbal, written, and listening skills. Having good communication skills is crucial for a manager. As a team manager, you are the communication bridge between frontline staff and senior management.

As a manager, deal with a variety of people, from new employees to heads of departments and CEOs, in several ways via social media, emails, online meetings, phone calls, presentations and meetings.

An open and positive attitude goes a long way to creating a healthy and work-friendly environment, ensure that staff feel valued. A positive workplace makes happy and motivated employees.

3. Technical Skills:

Technical Skill Image
Technical Skills

Technical skills are a must require for a manager. You probably be hired for your first work based on your skills in technical fields and you’ll use them properly during your early career.

Suppose you have a marketing degree, based on that you join an AD agency, then you’ll use your knowledge about promotion to prepare ad campaigns. Technical skills are developed through work experience, job training and formal education.

4. Conceptual Skills:

Conceptual skill
Conceptual skills

Conceptual skill is one of the most important management skills. Managers at the top, who decide what’s good for the organization from a wide orientation, rely on conceptual skills– the ability to analyze complex situations.

Senior administrators often called on to “Think outside of the box”- to arrive at unique solutions to knotty and ambiguous problems. They need both strong creative and strong analytical talents.

5. Leadership Skills:

Leadership Skill Image
Leadership Skills

The best managers are basically inspirational and effective leaders. They set the tone for their arenas by demonstrating through their actions- norms for staff activity.

Effective leaders used to lead by example as much as by direction. Motivating team members to increase productivity and action is a crucial element of effective leadership. Great leaders want input from all stakeholders and accept the contributions of other team members. They give credit where credit is due.

You can develop your leadership skills by volunteering to run point on projects. College students can develop their leadership skills by taking a leadership role while working on a group project.

6. Problem Solving:

Problem Solving
Problem Solving

Problem-solving is an essential management skill. A good manager must have the ability to tackle any situation and solve every problem that can come upon a typical workday.

Problem-solving in management involves identifying a certain problem and get the best solution and then finding the best way to manage the problem and get the best result.

When it is clear that a manager has great problem-solving skills, it separates him from the rest of the team and gives subordinates confidence in his managerial skills.

7. Time Management Skills:

Time Management Skill Image
Time Management

Managers face multiple demands or orders during their working time, and it filled their days with a lot of interruptions.

Ironically, some technologies which were supposed to save time, such as e-mail and voice-mail, have actually increased workloads. If you don’t develop your time management skills, then you can’t handle complex situations based on time.

Here are some suggestions:

  • Focus on the most important tasks first.
  • Don’t procrastinate and delegate routine tasks.
  • Prioritize tasks.
  • Fix a specific time for attending phone calls and answering e-mails.
  • Stick to an agenda.
  • Eliminate unnecessary paperwork.

8. Directing and Oversight:

Directing and Oversight Image
Directing

Directing is one of the most important managerial skills. Where you take charge and tell people what to do. You can also make important decisions and give orders to your team members.

Oversight might include anything from reviewing business models and checking for incompetence to making sure a project is on time and within budget. Oversight is basically the maintenance phase of management.

9. Domain Knowledge:

Domain Knowledge Image
Domain Knowledge

A good manager should know the process he is managing, including the type of tasks that team members are performing and how they are working on them. If you don’t have domain knowledge, it means that you and your team don’t even work at maximum capacity or use all of their potential due to a lack of understanding of one another. Without it, you cannot give the right direction to your team members.

10. Diagnostic, Analytical and Decision-Making Skills:

Management Skills: 10 Important Managerial Skills | Types of Management Skills
Decision Making

If you want to be a good manager, then you should have good diagnostic and analytical skills. Diagnostic skill is actually the ability to visualize the best response to a situation.

Analytical skill refers to the ability to identify the key variables in a situation.

The diagnostic skills and analytical skills of a manager help him to identify the best possible approaches to a situation. It also helps a manager to visualize the outcomes of these approaches. These skills are also required to make a decision.

Decision-making skills are required to make a decision in any condition. It is a very useful managerial skill. If you have good decision-making skills, then you can take important decisions immediately.

Sass/Less Comparison

In this document, I am using Sass’s SCSS syntax. You can choose to use the indented syntax in sass, if you prefer it, it has no functional differences from the SCSS syntax.

For Less, I’m using the JavaScript version because this is what they suggest on the website. The ruby version may be different.

Variables

Sass             | Less
-----------------+-----------------
$color: red;     | @color: red;
div {            | div {
  color: $color; |   color: @color;
}                | }

Both languages support scoped variable definition within a selector context. However, they differ in their behavior:

Sass                     | Less
-------------------------+-----------------
$color: black;           | @color: black;
.scoped {                | .scoped {
  $bg: blue;             |   @bg: blue;
  $color: white;         |   @color: white;
  color: $color;         |   color: @color;
  background-color: $bg; |   background-color: @bg;
}                        | }
.unscoped {              | .unscoped {
  color: $color;         |   color: @color;
  // Would be an error   |   // Would be an error
  // background: $bg;    |   // background: @bg;
}                        | }

And their different output:

Sass Output                 | Less Output
----------------------------+----------------------------
.scoped {                   | .scoped {
  color: white;             |   color: white;
  background-color: blue;   |   background-color: blue;
}                           | }
.unscoped { color: white; } | .unscoped { color: black; }

Nested Selectors

Sass and Less have the & selector that allows nested selector to refer to the parent scope.

Sass               | Less
-------------------+-----------------
p {                | p {
  a {              |   a {
    color: red;    |     color: red;
    &:hover {      |     &:hover {
      color: blue; |       color: blue;
    }              |     }
  }                |   }
}                  | }

Mixins

Sass                              | Less
----------------------------------+----------------------------------
@mixin bordered {                 | .bordered {
  border-top: dotted 1px black;   |   border-top: dotted 1px black;
  border-bottom: solid 2px black; |   border-bottom: solid 2px black;
}                                 | }
                                  | 
#menu a {                         | #menu a {
  @include bordered;              |   .bordered;
}                                 | }

Mixins with Arguments / Dynamic Mixins

Sass                              | Less
----------------------------------+----------------------------------
@mixin bordered($width: 2px) {    | .bordered(@width: 2px) {
  border: $width solid black;     |   border: @width solid black;
}                                 | }
                                  | 
#menu a {                         | #menu a {
  @include bordered(4px);         |   .bordered(4px);
}                                 | }

Selector Inheritance

Less does not provide selector inheritance.

Sass                        | Less  | CSS Output
----------------------------+-------+---------------------------
.bordered {                 |  N/A  | .bordered, #menu a {
  border: 1px solid back;   |       |   border: 1px solid back; }
}                           |       |
                            |       |
#menu a {                   |       |
  @extend .bordered;        |       |
}                           |       |

Colors

Both less and sass provide color math. It was a bad idea in Sass, I’m not sure why less chose to copy it. There’s no point in comparing them.

Sass provides a full array of tools for manipulating colors. All color representations (named colors, hex, rgb, rgba, hsl, hsla) are understood as colors and colors can be manipulated.

Sass exposes a long list of color functions not found in CSS:

Accessors:

  • red($color)
  • green($color)
  • blue($color)
  • hue($color)
  • saturation($color)
  • lightness($color)
  • alpha($color)

Mutators:

  • lighten($color, $amount)
  • darken($color, $amount)
  • saturate($color, $amount)
  • desaturate($color, $amount)
  • adjust-hue($color, $amount)
  • opacify($color, $amount)
  • transparentize($color, $amount)
  • mix($color1, $color2[, $amount])
  • grayscale($color)
  • compliment($color)

Note: Less.js provides a number of similar color functions.

Numbers

Both Sass and Less support numbers and basic arithmetic. However, they differ significantly with respect to how they handle units.

Sass supports unit-based arithmetic, just like you learned in school. Complex units are supported in any intermediate form and will only raise an error if you try to print out the value of a complex unit.

Additionally, Sass has conversion tables so that any comparable units can be combined.

Sass will let you define your own units and will happily print out unknown units into your css. Less will not. Sass does this as a form of future proofing against changes in the w3c specification or in case a browser introduces a non-standard unit.

Sass:

1cm * 1em => 1 cm * em
2in * 3in => 6 in * in
(1cm / 1em) * 4em => 4cm
2in + 3cm + 2pc => 3.514in
3in / 2in => 1.5

Less:

1cm * 1em => Error
2in * 3in => 6in
(1cm / 1em) * 4em => Error
2in + 3cm + 2pc => Error
3in / 2in => 1.5in

Conditionals & Control Structures

Less does not provide any conditionals or looping structures. Instead, it provides mixin guards and pattern-matching which can be used to similar effect.

Sass and Less provide boolean types true and false, the andor, and not operators as well as <><=>=== operators. There are minor syntax differences between the two (Sass syntax shown here).

Some sass examples:

@if lightness($color) > 30% {
  background-color: black;
}
@else {
  background-color: white;
}

Looping:

@for $i from 1px to 10px {
  .border-#{i} {
    border: $i solid blue;
  }
}

A similar example in Less, using mixins:

.mixin (@color) when (lightness(@color) > 30%) {
  background-color: black;
}
.mixin (@color) when (lightness(@color) =< 30%) {
  background-color: white;
}

Less supports looping via recursion, but not (yet) selector interpolation as shown in the Sass example, so it is of limited use.

Server Side Imports

Both sass and less will import other sass and less files.

Output formatting

Less has three output formats: normal, compressed & yui-compressed. Sass has four: nested, compact, compressed, expanded.

Sass output compression currently beats the google page speed css plugin output by a few percents.

Comments

Less and Sass both support C-style (/* */) and C++ Style comments (//).

Namespaces

Less provides a feature that Sass does not:

#bundle () {
  .red { background-color: red }
  .green { background-color: green }
}

.foo {
  #bundle > .red;
}

Generates:

.foo {
  background-color: red;
}

The sass team considered this feature and decided that adding it would create fragility and unexpected interconnectedness.

Comparison of JS Frameworks: ReactJS and EmberJS

According to research, Javascript is the most used programming language among developers worldwide. Its popularity can be explained by its simplicity and applicability, especially for the web development. There are a lot of libraries, frameworks, and other useful tools that are constantly updated. They help programmers to develop efficient, user-friendly apps and websites with JavaScript. React.js and Ember.js are among the most popular and most widely used JS frameworks. In this article, you can take a closer look at the reasons behind such popularity. Additionally, you can develop a better understanding of the main differences between Ember.js and React.js and how to choose the most suitable framework for your specific needs.

What You Need To Know About React.js

react-vs-ember

React was initially developed by Facebook in 2013 and is still maintained by the company. It is suitable for developing massive web applications which data is changing frequently. The concept that React.js is based on is allowing reusing components. Developers write small blocks of code that can be combined to create whole applications or used as independent interface elements. One of the most important features of the framework is the ability to use an XML-like syntax extension – JSX. It allows coding faster, safer and easier.

Pros of Using React.js

  • The framework is SEO-friendly which allows increasing the webpage crawl depth. Search engines can index such pages faster and more efficiently.
  • It is suitable for proceeding big amounts of data.
  • Code components can be reused as many times as you need.
  • Virtual DOM can improve the performance of a high-load application and can make it more user-friendly.
  • React.js makes the mobile app development easier because the code written during the website development can be used again to create a mobile app. If you plan to develop not only the website but also the mobile application, it will free you from the need to hire two large development teams.
  • The framework is useful for creating isomorphic code. Using such an application becomes more comfortable because the pages render faster. Due to the fact that the same code can be used for both the client and server bases, there is no need to duplicate the same features. As the result, development time and costs are reduced.

Cons of the React.js Framework

  • In some cases, using this framework requires more coding.
  • The documentation is getting more difficult because of the numerous updates and upgrades.
  • Not all browsers support React.js which means that programmers have to use additional plugins and extensions.

What You Need To Know About Ember.js

ember-javascript

Perhaps, Ember 2.0 is the most strictly organized JS framework. When you are developing projects with Ember, there is usually only one right way to complete the task and it is impossible to make a mistake. Ember is more like a platform which offers long-term support and maintenance for the developed project. The framework provides an advanced control system, tools for switching to new updated versions, and clear manuals and tools for avoiding out-of-date APIs. Without any doubts, Ember has every right to be called a well-weighed framework. However, a closer look at the pros and cons of Ember.js proves that is not suitable for every development project.

Benefits of Ember 2.0

  • Excellent documentation;
  • Convenient and rich default architecture;
  • Data binding (synchronization between the model and the view);
  • High-performance focus;
  • Server-side rendering;
  • URL support;
  • Numerous features within the framework.

Drawbacks of the Ember.js Framework

  • Slow rendering in the beginning;
  • Small community, less frequently updated tutorials;
  • Application development is complex and slow;
  • Few libraries and code examples;
  • No standard set of user interface elements;
  • Deep linking can perform randomly in complex applications.

React.js vs Ember.js: Which Framework to Choose For Your Project?

If you want to experience better web application development, it is required to have enough resources and support documentation for programmers to learn more about a certain framework and its features. This is due to the popularity of a certain framework: the more users it has, the more information can be found on the Internet. Therefore, before choosing Ember or React, programmers have to analyze the main features of both thoughtfully. This is why we prepared a comprehensive Ember.js comparison with React.js.

So, let’s compare React.js and Ember.js and their main characteristics:

Characteristics React.js Ember.js
What is it? A JS library for user interface development and more JS framework which a good fit for massive web applications
Licenses MIT BSD-3-Clause
Websites which use the framework Facebook, Instagram, New York Times, Khan Academy, Airbnb Netflix, Apple Music, LinkedIn, Yahoo!
Dynamic UI Binding State parameters are linked directly with the UI. The framework applies specific templates to update the values.
Reusable Components UI-components do not have to be related. Ember components are based on the widget approach. It is also possible to write application-specific HTML tags with the help of backend structure.
Routing It does not support routing but has numerous modules to handle it. It supports routing but the app becomes more complex.
Opinionation It is considered to be less opinionated and simple at the same time. Considerably high opinionated.
Data binding One-way Two-way

The main difference between React.js and Ember.js lies in the field of applicability. Indeed, React is good for dynamic extensive application with constantly changing data and high traffic. The JavaScript developers use Ember mostly for complex apps which require long and mindful development.

What’s Ember.js is well-known for is the fact that its main advantages can become its biggest disadvantages at the same time. It’s all about the inflexible structure of the apps created with Ember. Although its community is open to the proposals for improving Ember, there is always only one correct sequence of actions prescribed by the architecture of the framework itself for development. Outside-the-box solutions can lead to development difficulties. Definitely, this fact diminishes the advantages of the Ember.js.

React.js and Ember.js: Summary

The framework is the embodiment of certain templates, an integrated set of technologies, and the code that facilitates the application development and further support. Before hiring a dedicated team, first, make a list of full requirements for the future project and comprehensively analyze the frameworks to choose the most suitable one for your specific needs.

When full-stack developers compare Ember.js vs React.js, the vast majority suggest choosing React. The object-oriented approach, the ability to easily modify existing components and reuse code transform React development into a continuous improvement process. Components that were created during a particular project do not have additional dependencies. It means that all previous progress can be easily applied to a new website or even a mobile application.

Without any doubt, React.js development is in demand nowadays. Therefore, it is important to take a closer look at the expertise of the programmers on your team. Entrusting your project to a professional and experienced team is the key to success.

Nhớ Mẹ

Đã đôi lần nhớ lại ngày xưa!
Sớm bình minh lập lờ chưa tỏ,
Nhành hoa dại ru mình trong gió.
Tiếng gà vườn nào gáy, …nhớ ai!

Đã đôi lần nhớ lại ngày xưa!
Bóng dáng quen những trưa hè vắng,
Vẫn miệt mài lom khom dưới nắng.
Tiếng ve sầu sâu lắng, …nhớ ai!

Đã đôi lần nhớ lại ngày xưa!
Những cơn mưa đầu mùa rất vội,
Mái hiên nhà lao xao gió thổi.
Khói bếp chiều lai láng, …nhớ ai!

SG, 16-09-2013
lD, 25-06-2013

(Hơn 4 năm qua, ko đêm nào con ko nhớ)

Reactive Programming – Observables

Mastering observables

Important:A newer version of this software with updated documentation is available. Visit the Couchbase Developer Portal for more information.

The following guide helps you getting up to speed with asynchronous programming and Observables in particular. This guide is not tied to the Java SDK exclusively and aims to give you a general understanding of how to build full stack asynchronous applications.

Motivation

Asynchronous and reactive methodologies allow you to better utilize system resources. Instead of wasting a thread waiting for network (or disk) IO, it can be fully utilized to perform other work instead.

A broad range of technologies exists to facilitate this style of programming, ranging from the very limited and not really usable java.util.concurrent.Future, to full blown libraries and runtimes like Akka (and everything in between). For a database driver, the following requirements must be met:

  • Rich functionality
  • Interoperable and not opinionated
  • Performant
  • Small dependency and runtime footprint

After evaluating the requirements and solutions closely, one library stood out: RxJava. It has a very rich set to compose asynchronous workflows, has no dependencies on its own and is used at high-profile companies like Netflix. The Rx model (more on that a little later) is mature and well-thought and the community is vibrant.

We hope that once you read through the introduction and get more familiar with the concept, you never want to go back. We certainly don’t. That said, we fully support blocking operations as well, so you can still use a traditional blocking-based model if you absolutely want to.

The next section gradually introduces you into the world of Observables, the first step to reactive masterhood. If you want to learn more about the motivation, read on here.

Java 8, Lambdas and Anonymous Classes

Before jumping into the details, one thing warrants clarification: RxJava, and therefore the Java SDK fully supports Java 8. This brings some great improvements, most prominently support for lambdas and method references.

Because the Java SDK has support for Java 6 and 7, most of the examples shown in the documentation use anonymous classes instead of lambdas. You are free and even encouraged to use them if you are able to, but Java 8 on production servers is still a few months/years away at most companies.

That said, we expect the SDK to be around for a long time and want to pave the way for the future right now. To whet your appetite, compare Java 6 code to Java 8 (same code):

// Loads 3 documents in parallel
Observable
    .just("doc1", "doc2", "doc3")
    .flatMap(new Func1<String, Observable<JsonDocument>>() {
        @Override
        public Observable<JsonDocument> call(String id) {
            return bucket.get(id);
        }
    }).subscribe(new Action1<JsonDocument>() {
        @Override
        public void call(JsonDocument document) {
            System.out.println("Got: " + document);
        }
    });
// Loads 3 documents in parallel
Observable
    .just("doc1", "doc2", "doc3")
    .flatMap(bucket::get)
    .subscribe(document -> System.out.println("Got: " + document));

Also, RxJava has support for other languages like Scala, Groovy or Clojure. If you are using one of those languages, please refer to the RxJava documentation on how to use the adapters.

Understanding Observables

You can think of a Observable as the push-based, asynchronous cousin (“dual”) of the pull-based, synchronous Iterable. The contract of a Observable is that zero to N data events can happen, followed by a complete event. In addition, an error event can happen at any time, also completing the Observable.

Table 1. The Duality of Iterable & Observable
Event Iterable (Pull) Observable (Push)
retrieve data T next() onNext(T)
discover error throws Exception onError(Exception)
complete returns onCompleted()

A Observable can also be converted into a BlockingObservable, which then, unsurprisingly, behaves very much like a Iterable.

The key element to take away is that a Observable<T> can emit 0 to N events, which is very different of a Future<T>, which only contains one value. Once you start to work on streams instead of single values, you will very much appreciate this fact.

Also, important to understand is that by definition, a Observable does not imply that the underlying code is executed asynchronously. As a consumer of an Observable, you leave the actual implementation to the supplier, who is able to change it later on without you having to adapt your code. Imagine, you are consuming this API:

public interface FooService {
    Observable<String> load();
}

It could be that when load() is called, the String value is fetched right out of a Map in memory (or even a hard-coded value). In this case, there is no need to move the execution away from the caller thread, because the value will be returned instantaneously. If at a later point the implementation needs to be changed so that the String is loaded through a web service (which introduces latency and other semantics), the API doesn’t need to be changed, because the underlying implementation is free to move it to a Scheduler.

Consuming Observables

The first thing you want to do when working with Observables is to consume them. Consuming a Observable means subscribing to it. Here is an example which subscribes and prints out all the items emitted:

Observable
    .just(1, 2, 3)
    .subscribe(new Subscriber<Integer>() {
        @Override
        public void onCompleted() {
            System.out.println("Completed Observable.");
        }

        @Override
        public void onError(Throwable throwable) {
            System.err.println("Whoops: " + throwable.getMessage());
        }

        @Override
        public void onNext(Integer integer) {
            System.out.println("Got: " + integer);
        }
    });

This prints:

Got: 1
Got: 2
Got: 3
Completed Observable.

You can see that our Observer gets notified of every event and also receives the completed event.

Note:A well-formed Observable will invoke its Subscriber’s onNext method zero or more times, and then will invoke either the onCompleted or onError method exactly once.

You can also test the error case by throwing an artificial exception when the value 2 is emitted:

Observable
    .just(1, 2, 3)
    .doOnNext(new Action1<Integer>() {
        @Override
        public void call(Integer integer) {
            if (integer.equals(2)) {
                throw new RuntimeException("I don't like 2");
            }
        }
    })
    .subscribe(new Subscriber<Integer>() {
        @Override
        public void onCompleted() {
            System.out.println("Completed Observable.");
        }

        @Override
        public void onError(Throwable throwable) {
            System.err.println("Whoops: " + throwable.getMessage());
        }

        @Override
        public void onNext(Integer integer) {
            System.out.println("Got: " + integer);
        }
    });

This prints:

Got: 1
Whoops: I don't like 2

The first value gets through without problems, the second value throws an exception and therefore terminates the observable (and no subsequent values are allowed to be emitted after a error event).

Note:The subscribe method also returns a Subscription which you can use to unsubscribe and therefore do not receive further events.

Even if you don’t unsubscribe explicitly, operations like take do that for you implicitly. The following code only takes the first five values and then unsubscribes:

Observable
    .just("The", "Dave", "Brubeck", "Quartet", "Time", "Out")
    .take(5)
    .subscribe(new Subscriber<String>() {
        @Override
        public void onCompleted() {
            System.out.println("Completed Observable.");
        }

        @Override
        public void onError(Throwable throwable) {
            System.err.println("Whoops: " + throwable.getMessage());
        }

        @Override
        public void onNext(String name) {
            System.out.println("Got: " + name);
        }
    });

This prints:

Got: The
Got: Dave
Got: Brubeck
Got: Quartet
Got: Time
Completed Observable.
Note:If you take a close look at the API, subscribe() can be fed with either an Observer or a Subscriber. Unless you are implementing a custom Observer, always use Subscriber (because otherwise it will be wrapped in one internally anyway and you are saving unnecessary object allocations).

You do not need to implement the full Subscriber every time. If you are only interested in the data events, you can subscribe like this:

Observable
    .just(1, 2, 3)
    .subscribe(new Action1<Integer>() {
        @Override
        public void call(Integer integer) {
            System.out.println("Got: " + integer);
        }
    });

Be aware though that if an error happens, the following exception will be propagated:

Exception in thread "main" rx.exceptions.OnErrorNotImplementedException
	at rx.Observable$36.onError(Observable.java:8412)
	at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:128)
	at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:97)
	at rx.internal.operators.OperatorDoOnEach$1.onError(OperatorDoOnEach.java:67)
	at rx.internal.operators.OperatorDoOnEach$1.onNext(OperatorDoOnEach.java:78)
	at rx.internal.operators.OnSubscribeFromIterable$IterableProducer.request(OnSubscribeFromIterable.java:76)
	...

It is recommended to always implement an error handler right from the beginning, since things can and will go wrong at some point. It can come in handy though if you just want to try things out quickly or for illustrative purposes.

From Async to Sync

As long as your Observable works on the same thread all the time, there is no need for communication between threads since only one is executing. When your Observable flow gets executed on a different thread though, you need to take some extra care to make sure you are not missing values. This is not specific to Observables though, every time you need to deal with parallel threads you need to think about synchronization and communication.

The following code emits a increasing value every second, and this is done on a different thread:

public static void main(String... args) {
    Observable
        .interval(1, TimeUnit.SECONDS)
        .subscribe(new Action1<Long>() {
            @Override
            public void call(Long counter) {
                System.out.println("Got: " + counter);
            }
        });
}

It works perfectly fine, the only problem is though chances are you won’t see anything printed out. This is because your main thread exits before the background thread had a chance to run and emit values.

A common way to deal with such a situation is to add a CountDownLatch, which allows you to synchronize between different threads. One thread counts down the latch, the other one waits until it is counted down:

final CountDownLatch latch = new CountDownLatch(5);
Observable
    .interval(1, TimeUnit.SECONDS)
    .subscribe(new Action1<Long>() {
        @Override
        public void call(Long counter) {
            latch.countDown();
            System.out.println("Got: " + counter);
        }
    });

latch.await();

This prints and then exits:

Got: 0
Got: 1
Got: 2
Got: 3
Got: 4
Note:One common mistake is to use Thread.sleep() instead of a latch to synchronize the execution between threads. This is a bad idea because it not really synchronizes anything, but just keeps one thread alive for a specific amount of time. If the actual calls take less time you are wasting time, and if it takes longer you won’t get the desired effect. If you do this in unit tests, be prepared for a good amount of non-determinism and randomly failing tests. Always use a CountDownLatch.

A technique unique to Observables is to convert it into a BlockingObservable to achieve the same effect. In simple terms, it converts a Observable into a Iterable and making it execute on the caller thread, blocking it until one or more values arrive. This technique is used extensively in the documentation to show concepts, while not having to deal with CountDownLatches all the time. It can also be used if you for some reason are not able to use asynchronous computations.

The conversion itself doesn’t do any blocking in the first place, only subsequent calls will:

// This does not block.
BlockingObservable<Long> observable = Observable
    .interval(1, TimeUnit.SECONDS)
    .toBlocking();

// This blocks and is called for every emitted item.
observable.forEach(new Action1<Long>() {
    @Override
    public void call(Long counter) {
        System.out.println("Got: " + counter);
    }
});

Since this will run forever, you are free to chain any asynchronous computations before. So you ca build an asynchronous workflow and then block at the very end. This resembles the same code as with the CountDownLatch before:

Observable
    .interval(1, TimeUnit.SECONDS)
    .take(5)
    .toBlocking()
    .forEach(new Action1<Long>() {
        @Override
        public void call(Long counter) {
            System.out.println("Got: " + counter);
        }
    });

If you know that only a single value is every returned, you can use the single() method:

int value = Observable
    .just(1)
    .toBlocking()
    .single();

Be aware though that if more items get emitted, you get an exception:

Exception in thread "main" java.lang.IllegalArgumentException: Sequence contains too many elements
	at rx.internal.operators.OperatorSingle$1.onNext(OperatorSingle.java:58)
	at rx.internal.operators.OnSubscribeFromIterable$IterableProducer.request(OnSubscribeFromIterable.java:76)
	at rx.Subscriber.setProducer(Subscriber.java:148)
	at rx.Subscriber.setProducer(Subscriber.java:144)
	....

The same thing happens if no value gets emitted:

Exception in thread "main" java.util.NoSuchElementException: Sequence contains no elements
	at rx.internal.operators.OperatorSingle$1.onCompleted(OperatorSingle.java:82)
	at rx.internal.operators.OnSubscribeFromIterable$IterableProducer.request(OnSubscribeFromIterable.java:79)
	at rx.Subscriber.setProducer(Subscriber.java:148)
	at rx.Subscriber.setProducer(Subscriber.java:144)
	at rx.Subscriber.setProducer(Subscriber.java:144)
	at rx.Subscriber.setProducer(Subscriber.java:144)
	....

As an alternative, you can use singleOrDefault() so that a fallback value gets returned.

You can use this technique with the Java SDK if you are loading a document and it does not exist:

JsonDocument doc = bucket.get("id").toBlocking().singleOrDefault(null);
if (doc == null) {
    System.err.println("Document not found!");
} else {
    System.out.println(doc);
}

If you check out the API documentation of the BlockingObservable, you will discover many more possibilities, including iterators or grabbing the first and/or last valuess.

One last thing that comes in handy with blocking calls: sometimes you want to collect all emitted values into a list. You can combine the blocking calls with the toList() operator to achieve something like this:

List<Integer> list = Observable
    .just(1, 2, 3)
    .toList()
    .toBlocking()
    .single();

// Prints: [1, 2, 3]
System.out.println(list);

Creating Observables

There are many ways to create Observables, and you’ve already seen just() and interval(). There are many more of those convenience methods available on the Observable class, but they all boil down to the create() method. You can simulate the example from before with this:

Observable.create(new Observable.OnSubscribe<Integer>() {
    @Override
    public void call(Subscriber<? super Integer> subscriber) {
        try {
            if (!subscriber.isUnsubscribed()) {
                for (int i = 0; i < 5; i++) {
                    subscriber.onNext(i);
                }
                subscriber.onCompleted();
            }
        } catch (Exception ex) {
            subscriber.onError(ex);
        }
    }
}).subscribe(new Action1<Integer>() {
    @Override
    public void call(Integer integer) {
        System.out.println("Got: " + integer);
    }
});

Every time a Subscriber subscribes, the call() method is executed. You can then call onNext, onComplete and onError as you wish, but keep in mind that both onComplete and onError should only be called once, and afterwards no subsequent onNext is allowed to follow so that the contract is met.

You can see that no blocking call is needed, because the Observable is completely handled on the current thread. In the section on Schedulers, you learn more about that.

Note:This example shows why it is crucial to call subscribe() on the Observable, because only such a call triggers the actual execution of the pipeline. This is a little different with Subjects, which are covered later in this guide. Nevertheless, always call subscribe() on your Observables.

Refer to the RxJava documentation on many more methods that you can use to create Observables. If you are dealing with the Java SDK, in most places this is done for you, but there are situation where it comes in handy.

The Java SDK does not expose bulk methods anymore on the API, because you can do this already with the help of Observables. Compare these two examples, one only loads one document, the other loads a few (you’ll learn about flatMap() in the next section):

// Loads one document and prints it:
bucket
    .get("doc1")
    .subscribe(new Action1<JsonDocument>() {
        @Override
        public void call(JsonDocument document) {
            System.out.println("Got: " + document);
        }
    });
// Loads 3 documents in parallel
Observable
    .just("doc1", "doc2", "doc3")
    .flatMap(new Func1<String, Observable<JsonDocument>>() {
        @Override
        public Observable<JsonDocument> call(String id) {
            return bucket.get(id);
        }
    }).subscribe(new Action1<JsonDocument>() {
        @Override
        public void call(JsonDocument document) {
            System.out.println("Got: " + document);
        }
    });

Transforming Observables

Observables can transform their values in various ways. One of the most basic ones is map(), which converts the incoming value into a different one. You surely like division, so here is the FizzBuzz game:

Observable
    .interval(10, TimeUnit.MILLISECONDS)
    .take(20)
    .map(new Func1<Long, String>() {
        @Override
        public String call(Long input) {
            if (input % 3 == 0) {
                return "Fizz";
            } else if (input % 5 == 0) {
                return "Buzz";
            }
            return Long.toString(input);
        }
    })
    .toBlocking()
    .forEach(new Action1<String>() {
        @Override
        public void call(String s) {
            System.out.println(s);
        }
    });

The map function is used to convert the input number into a string and do some checks to satisfy the FizzBuzz game. As a more practical example, consider loading a document from the Java SDK and only extracting the firstname of a user before passing it on:

bucket
    .get("id")
    .map(new Func1<JsonDocument, String>() {
        @Override
        public String call(JsonDocument document) {
            return document.content().getString("firstname");
        }
    }).subscribe();

A variation of map() is called flatMap(), which allows you to do those transformations with asynchronous calles. Taking the example from above, we want to map from String (the document ID) to a JsonDocument (the loaded document). With a normal map(), call you would either need to block on the Observable or at some point deal with a Observable<Observable<JsonDocument>>.

Thankfully, flatMap() flattens the resulting values for us and return them into the original flow:

// Loads 3 documents in parallel
Observable
    .just("doc1", "doc2", "doc3")
    .flatMap(new Func1<String, Observable<JsonDocument>>() {
        @Override
        public Observable<JsonDocument> call(String id) {
            return bucket.get(id);
        }
    }).subscribe(new Action1<JsonDocument>() {
        @Override
        public void call(JsonDocument document) {
            System.out.println("Got: " + document);
        }
    });

You can see that flatMap() returns an Observable<T> whereas the normal map just returns <T>. You will use flatMap() a lot when dealing with flows like this, so keep it in mind.

Another helpful transformation is scan(). It applies a function to each value emitted by an Observable, sequentially, and emits each successive value. We can use it to aggregate values like this:

Observable
    .just(1, 2, 3, 4, 5)
    .scan(new Func2<Integer, Integer, Integer>() {
        @Override
        public Integer call(Integer sum, Integer value) {
            return sum + value;
        }
    }).subscribe(new Action1<Integer>() {
        @Override
        public void call(Integer integer) {
            System.out.println("Sum: " + integer);
        }
    });

This prints:

Sum: 1
Sum: 3
Sum: 6
Sum: 10
Sum: 15

Finally, groupBy() comes in handy, which emits one Observable by each group, defined by a function. The following example emits two Observables, one for even and one for odd values:

Observable
    .just(1, 2, 3, 4, 5)
    .groupBy(new Func1<Integer, Boolean>() {
        @Override
        public Boolean call(Integer integer) {
            return integer % 2 == 0;
        }
    }).subscribe(new Action1<GroupedObservable<Boolean, Integer>>() {
        @Override
        public void call(GroupedObservable<Boolean, Integer> grouped) {
            grouped.toList().subscribe(new Action1<List<Integer>>() {
                @Override
                public void call(List<Integer> integers) {
                    System.out.println(integers + " (Even: " + grouped.getKey() + ")");
                }
            });
        }
    });

This prints:

[1, 3, 5] (Even: false)
[2, 4] (Even: true)

Combined with the Java SDK, this technique can be used to separate returned Documents based on their content. The following example uses a view to load all documents from the beer-sample bucket, groups them by type and counts the number of occurrences:

bucket
    .query(ViewQuery.from("my_design_doc", "my_view"))
    .flatMap(ViewResult::rows)
    .flatMap(ViewRow::document)
    .groupBy(document -> document.content().getString("type"))
    .subscribe(observable ->
        observable.count().subscribe(integer ->
            System.out.println(observable.getKey() + ": " + integer)
        )
    );

This code queries the view, extracts all rows, loads the full document for each row, groups it by the “type” property in the JSON document and then uses the count() operator to count the number of rows emitted by each observable. This prints something like:

brewery: 1412
beer: 5891

Filtering Observables

In addition to transforming Observables, you can also filter them. Filtering doesn’t change the emitted values itself, but rather how much and at which point (and if at all) they are emitted.

For example, you can filter based on some criteria:

// This will only let 3 and 4 pass.
Observable
    .just(1, 2, 3, 4)
    .filter(new Func1<Integer, Boolean>() {
        @Override
        public Boolean call(Integer integer) {
            return integer > 2;
        }
    }).subscribe();

Or take only the first N values emitted and then unsubscribe:

// Only 1 and 2 will pass.
Observable
    .just(1, 2, 3, 4)
    .take(2)
    .subscribe();

Or use only the first or last value emitted:

// Only 1 will pass
Observable
    .just(1, 2, 3, 4)
    .first()
    .subscribe();
// Only 4 will pass
Observable
    .just(1, 2, 3, 4)
    .last()
    .subscribe();

Finally, you can use distinct() to suppress duplicate values:

// 1, 2, 3, 4 will be emitted
Observable
    .just(1, 2, 1, 3, 4, 2)
    .distinct()
    .subscribe();
Note:distinct() also allows you to pass in a function which returns the key to select by. You can use this for example to separate out duplicate JsonDocuments.

Combining Observables

Multiple Observables can also be merged to form a combined one. Depending on how you want those to be merged, there are different operators available. Two of the most used ones are merge() and zip() which are covered here.

Merge really just merges all emitted values by the source observables in the order they arrive:

Observable
    .merge(evens, odds)
    .subscribe(new Action1<Integer>() {
        @Override
        public void call(Integer integer) {
            System.out.println(integer);
        }
    });

This prints something similar to:

2
4
6
8
10
1
3
5
7
9

With the zip operator, you can combine two streams in the stricly same order, defined by a function:

Observable<Integer> evens = Observable.just(2, 4, 6, 8, 10);
Observable<Integer> odds = Observable.just(1, 3, 5, 7, 9);

Observable
    .zip(evens, odds, (v1, v2) -> v1 + " + " + v2 + " is: " + (v1 + v2))
    .subscribe(System.out::println);

This zips each pairs togehter in order and prints:

2 + 1 is: 3
4 + 3 is: 7
6 + 5 is: 11
8 + 7 is: 15
10 + 9 is: 19

Error Handling

Error handling is a vital component of every real world application and needs to be considered from the start. RxJava provides sophisticated mechanisms to deal with errors that happen inevitably in your Observable flows.

In general, you want to react in the following ways:

  • Return a default value instead
  • Flip over to a backup Observable
  • Retry the Observable (immediately or with backoff)

Returning a default value is a good idea if you cannot afford to retry or you just don’t care (maybe because the flow is not absolutely crucial to your data flow). The following code throws an exception at the first emitted item, but falls back to a default value:

Note that you can pass in a function which also takes the Exception, so you can return different values for different exception types or use it for logging purposes.

// Prints:
// Default
// Oops: I don't like: Apples
Observable
    .just("Apples", "Bananas")
    .doOnNext(s -> {
        throw new RuntimeException("I don't like: " + s);
    })
    .onErrorReturn(throwable -> {
        System.err.println("Oops: " + throwable.getMessage());
        return "Default";
    }).subscribe(System.out::println);

You can also flip to a backup observable which will be called if the first one fails. The Java SDK has a getFromReplica() command which allows you to read stale data from its replicas and treat availability for consistency on reads. You can use this approach to fall back:

bucket
    .get("id")
    .onErrorResumeNext(bucket.getFromReplica("id", ReplicaMode.ALL))
    .subscribe();

Normally you want to have more control on which observable should be run next depending on the type of error. The following example will only go to the replica if a TimeoutException happened (if not the error is passed down):

bucket
    .get("id")
    .timeout(500, TimeUnit.MILLISECONDS)
    .onErrorResumeNext(new Func1<Throwable, Observable<? extends JsonDocument>>() {
        @Override
        public Observable<? extends JsonDocument> call(Throwable throwable) {
            if (throwable instanceof TimeoutException) {
                return bucket.getFromReplica("id", ReplicaMode.ALL);
            }
            return Observable.error(throwable);
        }
    });

Finally, it is possible to retry the Observable by resubscribing. This can be done as quickly as possible, or with a backoff interval (which is preferred when external resources are involved).

The following program desperately tries to read the numbers from 1 to 10, but a (not so hidden) flaw makes it randomly throw an exception. If that happens, the code retries. Since lots of values might be already emitted, we can use distinct() to filter those out.

Observable
    .just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    .doOnNext(integer -> {
        if (new Random().nextInt(10) + 1 == 5) {
            throw new RuntimeException("Boo!");
        }
    })
    .retry()
    .distinct()
    .subscribe(System.out::println);
Note:If you only want to retry for a max amount, replace the retry() with a retry(count) call.

If you want to retry with backoff, you can use a technique like the following:

Observable
    .range(1, 10)
    .doOnNext(integer -> {
        if (new Random().nextInt(10) + 1 == 5) {
            throw new RuntimeException("Boo!");
        }
    })
    .retryWhen(attempts ->
        attempts.zipWith(Observable.range(1, 3), (n, i) -> i)
        .flatMap(i -> {
            System.out.println("delay retry by " + i + " second(s)");
            return Observable.timer(i, TimeUnit.SECONDS);
        }))
    .distinct()
    .subscribe(System.out::println);

The attempts get passed into the retryWhen() method and zipped with the number of seconds to wait. The timer method is used to complete once its timer is done. If you run this code a few times to generate an exception (or more), you will see something similar to this:

1
2
3
4
delay retry by 1 second(s)
delay retry by 2 second(s)
5
6
7
8
9
10

Schedulers & Threads

Schedulers in RxJava are used to manage and control concurrency. Some operators implicitly use one and/or allow you to pass in a custom one.

RxJava ships with a bunch of preconfigured Schedulers by default, which are all accessible through the Schedulers class:

  • Schedulers.computation(): Event-loop style scheduler for purely computational work.
  • Schedulers.immediate(): Executes the work immediately on the current thread.
  • Schedulers.io(): Executes work on a Executor-backed pool which grows as needed.
  • Schedulers.newThread(): Creates a new thread for each unit of work.
  • Schedulers.trampoline(): Queues the work on the current thread and gets executed after the current work completes.
  • Schedulers.test(): Test scheduler used for testing and debugging, which allows manual advancing of the clock.

As a rule of thumb, the computation scheduler should always be used for in-memory processing, while the IO scheduler should only be used for blocking-style IO operations (so do not use it together with the Java SDK since it is asynchronous anyway!).

You can instruct an Observable to be executed on such a scheduler in four different ways:

  • Implicitly by using an operator that makes use of one
  • Explicitly by passing the Scheduler to such an operator
  • By using subscribeOn(Scheduler)
  • By using observeOn(Scheduler)

Operators like buffer, replay, skip, delay, parallel and so forth use a Scheduler by default if not instructed otherwise. A list of default schedulers can be found here: https://github.com/ReactiveX/RxJava/wiki/Scheduler#default-schedulers-for-rxjava-observable-operators

As a rule of thumb, all of those operators allow you to pass in a custom Scheduler if needed, but most of the time sticking with the defaults is a good idea.

Note:The Java SDK uses a internal scheduler similar to the computation Scheduler to proper isolate the inner mechanisms from user-land. It is possible to change that Scheduler through the environment, but not recommended.

If you want the whole subscribe chain to be executed on a specific scheduler, you use the subscribeOn() operator. Without a Scheduler set, the following code executes on the main thread:

Observable
    .range(1, 5)
    .map(integer -> {
        System.out.println("Map: (" + Thread.currentThread().getName() + ")");
        return integer + 2;
    })
    .subscribe(integer -> 
        System.out.println("Got: " + integer + " (" + Thread.currentThread().getName() + ")")
    );

This prints:

Map: (main)
Got: 3 (main)
Map: (main)
Got: 4 (main)
Map: (main)
Got: 5 (main)
Map: (main)
Got: 6 (main)
Map: (main)
Got: 7 (main)

If you add subscribeOn() somewhere in the flow (it doesn’t matter where):

Observable
    .range(1, 5)
    .map(integer -> {
        System.out.println("Map: (" + Thread.currentThread().getName() + ")");
        return integer + 2;
    })
    .subscribeOn(Schedulers.computation())
    .subscribe(integer ->
            System.out.println("Got: " + integer + " (" + Thread.currentThread().getName() + ")")
    );

You can see it is executed on the same thread, but on the computation thread pool:

Map: (RxComputationThreadPool-6)
Got: 3 (RxComputationThreadPool-6)
Map: (RxComputationThreadPool-6)
Got: 4 (RxComputationThreadPool-6)
Map: (RxComputationThreadPool-6)
Got: 5 (RxComputationThreadPool-6)
Map: (RxComputationThreadPool-6)
Got: 6 (RxComputationThreadPool-6)
Map: (RxComputationThreadPool-6)
Got: 7 (RxComputationThreadPool-6)

If you need tighter control which parts are executed on what pool, use observeOn(). Here, the order matters:

Observable
    .range(1, 5)
    .map(integer -> {
        System.out.println("Map: (" + Thread.currentThread().getName() + ")");
        return integer + 2;
    })
    .observeOn(Schedulers.computation())
    .subscribe(integer ->
            System.out.println("Got: " + integer + " (" + Thread.currentThread().getName() + ")")
    );

Everything before the observeOn call is executed in main, everything below in the Scheduler:

Map: (main)
Map: (main)
Map: (main)
Got: 3 (RxComputationThreadPool-6)
Got: 4 (RxComputationThreadPool-6)
Got: 5 (RxComputationThreadPool-6)
Map: (main)
Map: (main)
Got: 6 (RxComputationThreadPool-6)
Got: 7 (RxComputationThreadPool-6)

There is also a way to use Schedulers directly to schedule operations, please refer to the documentation here: https://github.com/ReactiveX/RxJava/wiki/Scheduler#using-schedulers

Subjects

A Subject is a hybrid between a Observable and a Subscriber. So it can both receive and emit events. Most of the time you don’t need Subjects and can handle everything fine through Observables alone, but there are certain cases when they come in handy.

There is a distinction between different Observables that have not been covered yet:

  • A cold Observable waits for a Subscription until it emits values and does this freshly for every Subscriber.
  • A hot Observable begins emitting values upfront and presents them to every subscriber subsequently. Subjects are hot Observables.
Note:Because of the network layer in between, the Java SDK needs to use Subjects for its request/response cycles. This also makes sense because if you subscribe twice to a bucket.get() call, you actually only want one network call instead of two.

Currently, there are four Subjects supported by RxJava, slightly differing in their functionality:

  • AsyncSubject: emits the last value (and only the last value) emitted by the source Observable, and only after that source Observable completes. (If the source Observable does not emit any values, the AsyncSubject also completes without emitting any values.)
  • BehaviorSubject: When an Subscriber subscribes to a BehaviorSubject, it begins by emitting the item most recently emitted by the source Observable (or an optional seed/default value if none has yet been emitted) and then continues to emit any other items emitted later by the source Observable(s).
  • PublishSubject: PublishSubject emits to a subscriber only those items that are emitted by the source Observable(s) subsequent to the time of the subscription.
  • ReplaySubject: ReplaySubject emits to any subscriber all of the items that were emitted by the source Observable(s), regardless of when the subscriber subscribes.

As an example: if you call bucket.get(), a AsyncSubject is created under the covers and returned to you immediately. In addition, it is passed down the IO layer and stored. When a response arrives from the server, the Subject is fed with the response and you get notified appropriately.

If you need to use a Subject, choose wisely which one to use in order to keep resource usage low (some of them cache data for subscribers) especially if you push lots of data through them. You can read more about them here: https://github.com/ReactiveX/RxJava/wiki/Subject

There is one last thing you need to know when dealing with Subjects: because you are not getting new values when resubscribing (since it’s cached), the following won’t work (doing a get call every second):

bucket
    .get("id")
    .delay(1, TimeUnit.SECONDS)
    .repeat()
    .subscribe();

This will only execute one get call, because subsequent attempts only load the cached value. For this reason Observable.defer() was added, which creates a new Observable for every subscriber that comes along:

Observable.defer(new Func0<Observable<JsonDocument>>() {
    @Override
    public Observable<JsonDocument> call() {
        return bucket.get("id");
    }
})
.delay(1, TimeUnit.SECONDS)
.repeat()
.subscribe();

Reference:
http://docs.couchbase.com/developer/java-2.0/observables.html
http://reactivex.io/intro.html