Full Transcript

Flutter Flutter is a highly adaptable and robust framework designed for crafting applications that work seamlessly across multiple platforms, focusing on crafting responsive and high-performance user interfaces. It enjoys broad adoption among developers and is a favored...

Flutter Flutter is a highly adaptable and robust framework designed for crafting applications that work seamlessly across multiple platforms, focusing on crafting responsive and high-performance user interfaces. It enjoys broad adoption among developers and is a favored solution for developing mobile apps, web applications, and various other software projects. Flutter is a popularly used framework in the industry, and there is a high demand for developers who are proficient in this technology. Flutter is a cross-platform UI toolkit that allows applications to interact directly with underlying platform services while allowing code reuse across operating systems like iOS, Android, webOS, etc. Architectural layers of Flutter 1. Embedder layer The embedder layer is at the bottom of the Flutter framework, which directly talks to the underlying operating system. In the embedder layer, the Flutter applications are packaged in the same way as any other native application. The embedder is written in a platform-specific language, such as Java and C++ for Android, Objective-C and Objective-C++ for iOS and macOS, and C++ for Windows and Linux. 2. Engine layer Engine layer, which is mostly written in C++. Every time a new frame needs to be painted, the engine is in charge of rasterizing (raster picture) composite sceneries. It implements Flutter’s basic API at a low level, including graphics, text layout, file, and network I/O, among other things. Flutter framework Flutter framework, where developers will mostly interact to build the apps. The framework is written in the Dart language, so developers are required to learn Dart to build their apps. Some core features like widgets help us build UI elements shipped to us directly under the Flutter framework when it's first installed, and other features (like camera, webview, etc.) can be downloaded from pub.dev. in Flutter, the developer provides a mapping from different application states to the corresponding interface state. And the framework takes on the task of updating the interface at runtime when the application state changes. What Are Widgets? Widgets are the UI building blocks that we see on the screen. Making an app with Flutter is simply creating a bunch of widgets and tying them together. We have a Text widget to show text on the screen, a ListView widget to show contests in a list just like posts in an Instagram feed, and a Scaffold widget we can use to bring a new screen to our app. Widget tree When we build a Flutter app, we make a tree of widgets. At the root of that tree, we have a MyApp widget that will be called inside the main function of main.dart, which will be the starting point. The MyApp widget will build a MaterialApp widget, and this will eventually build a Scaffold widget, and so on. By doing this, we’ll have a tree of widgets that will be shown in the app as the UI. We’ll discuss the functioning of various common widgets later in the next section. Layouts in Flutter Widgets are at the heart of Flutter’s layout system. Almost everything in Flutter is a widget, including layout models. Widgets are the graphics, icons, and texts that are visible in a Flutter app. Things you can’t see, such as the rows, columns, and grids that arrange, limit, and align the visible widgets, are also widgets. We use layout widgets to place and align our visible widgets like text, images, etc. Common layout widgets Below are some of the common layout widgets: Container: This adds margins, borders, padding, background color, or other decorations to a widget. Row: This lays widgets horizontally. Column: This lays the widget vertically. GridView: This lays widgets out in a scrollable grid. ListView: This lays widgets out in a scrollable list. Stack: This overlaps one widget on top of another. Stateful and Stateless Widget State The state is a change in our domain objects. Assume we are making an Instagram app in which we have a post domain object with fields like postedBy, createdAt, numberOfLikes, etc. These fields together make up a state for this particular post object. Now suppose a follower clicks the “Like” button on this particular post. The numberOfLikes changes, so basically, the state changes. Whenever a state changes, we as a developer have two options—either to show the updated state (numberOfLikes in this example) or not to show it to the users. Stateful and stateless widgets Whenever we want to build a UI element on the screen that needs to be updated upon user interaction or if we want to change the state, use StatefulWidget. Otherwise, we use StatelessWidget. If we always use StatefulWidget, then we'll also be able to complete the app, but we will suffer some decrease in performance. Stateless widgets are built only once on the screen, hence, it improves the performance of the app. Widget Lifecycle The createState() method The createState() method must be overridden when a Dart class extends a StatefulWidget. The initState() method When a stateful widget is born and gets attached to the widget tree, it calls its first method, which is initState(). Here we can initialize variables, data, properties, etc. for any widget. The build() method We’ll create the widget or tree of widgets to be shown on the screen. The didChangeDependencies() method This method is called immediately after initState() and when dependency of the state it is holding changes through its dependent widget. The dispose() method We use this method when the widget is removed from its tree, like when the user presses the “Back” button from the current Scaffold widget. Future vs. Stream Futures Futures are just like its name itself. They will return value, or the function will complete the execution in the future. Think of our add function. We’ll write our code in such a way that it will not return a normal int data type. Rather, it will return the future, and it will also give us a callback to execute when add finishes its work so we don’t have to wait. Now let’s see this via an example: Streams Futures are like one shot. We call an async function, it will finish after some delay, and, then, complete its callback, if provided. And that’s it! Our relationship with the future ended there only. But the relationship with streams never ends until we forcefully cancel it, or it has nothing to provide us. Common Widgets Scaffold Scaffold widget in Flutter, which will act as a container that holds other UI widgets to build a screen. The Scaffold widget is used whenever we want to build a new screen. However, it won’t be directly visible to us. Think of it as a container that will hold the other widgets that we’ll eventually see on the screen Parameters The Scaffold widget takes the following parameters to build a screen for our app: appBar: This will take an instance of the AppBar class, and it will build the top label of our screen. body: Here, we can give any custom widget so that Scaffold will build it below AppBar. drawer: This will take an instance of the Drawer class. The hamburger menu we see on most apps can be built from this. floatingActionButton: This will take the FloatingActionButton widget and is shown as an overlay over our body widget. It will be similar to the “Compose” button in the Gmail app. The Scaffold widget also has other awesome properties that can enhance our UI, some of which we’ll use later in this course when building our todo app. Container Learn about the Container widget, which will help us containerize other Flutter widgets. The Container widget is the most general widget and can set any additional widget in its child property to add decoration or styling to it, like shape, color, etc. The Container widget helps us compose, decorate, and position child widgets. By default, the Container widget uses the size of its child. We can also later increase the size of the container by adding padding to its child widget or by giving constraints. Column and Row The Column widget won’t have the property of child. Rather, it will have the property of children because the developer is expected to put more than one child widget under it. This widget has other properties that position the child widgets The Row widget is similar to the Column widget but is aligned in a horizontal direction. Parameters The Row and Column widgets take the following parameters: crossAxisAlignment: The Row and Column widgets can position their children on the cross axes using the crossAxisAlignment attribute. The cross axis of a row is vertical, while the cross axis of a column is horizontal. mainAxisAlignment: The Row and Column widgets can position their children on their main axes using the mainAxisAlignment attribute. The main axis of a row is horizontal, while the main axis of a column is vertical. mainAxisSize: The mainAxisSize attribute specifies the amount of space a row and column can take up on their main axis. Either it will be the maximum (the size of the screen) or the minimum (the total size of the underlying children.) Stack The Stack is a Flutter widget that holds a list of widgets and arranges them one on top of the other. To put it another way, the Stack enables developers to combine several widgets into a single screen and render them from bottom to top. Whereas Column and Row widgets allow their children to be arranged in a specific direction and have a clear separation, meaning any child widget can not overlap with another child widget. On the other hand, the children of Stack can overlap each other. ListView Just like Column and Row widgets, ListView widgets are used to arrange the children in a list. The children of ListView are scrollable by default. There are two ways to construct a list of widgets in Flutter. One is simple ListView, which will take the children property just like Column or Row, and the other is ListView.builder, which will take a function itemBuilder(int index). Based on that index, we can build common or custom widgets for each index. For the ListView.builder, we have to provide the size of the list we’re going to build. Generally, we use ListView for smaller size lists and ListView.builder for larger lists because ListView.builder builds the child widgets on the go when they are about to be visible on screen, thus saving resources, unlike the normal ListView constructor. Parameters The ListView widget takes the following parameters: itemCount: This is the total list size that we need to specify beforehand. In the case of a paginated list, we can grow the list by increasing the count and rebuilding the ListView. itemBuilder: This is a function that gives us the index of the list member widget that we’re going to build. Like in our example, the index will go from 0 to 9 since the itemSize is 10. And, for an even index, we configure different widget properties. Although it isn’t common, for each index, we can have a totally different widget, if we want. reverse: By default, it’s false, but if true, the ListView will start generating widgets from bottom to top. Form Form widget in Flutter, which is like the ones we see on the login/signup page of any app. You must have seen the login or signup form where we have to fill in our name/username, email, and password from our keyboard, and the UI shows whatever you enter in their respective fields but not in the password that is obscured from us. Also, if a field doesn’t fulfill the validation, the respective field will throw an error with an appropriate message, like password is too short. All these features can be implemented in Flutter with the help of the Form widget. Parameters The Form widget takes the following widgets: decoration: We have used InputDecoration to give icon and text hints. Also, it gives us an animation of the hint moving to the top bar at the time of input. autocorrect: This is used to enable spelling autocorrections. onChanged: This is a function that gives us the current value of text input by the user. With onChanged, we can do many things, like showing results based on the current search of the user. validator: When the form is submitted, this function is called to enable the error description below the TextFormField. FutureBuilder FutureBuilder widget, which is used when the UI needs to be built with a delay. The name speaks for itself—the FutureBuilder widget will help us build our UI widgets in the future. Why might someone want to build a UI widget later in time instead of instantly? Let’s understand this by looking at a scenario. Suppose we want to build a news feed application. When the consumer opens our app, the app needs to fetch relevant news from the server and then show it to the UI. But fetching anything from the server will take some time, for obvious reasons, and that’s why we have to wait momentarily to render the UI. StreamBuilder StreamBuilder widget, which is used when a UI is built with a continuous stream of inputs. Imagine building an Instagram news feed page in its app in which Instagram’s newsfeed server will continuously give an updated result, i.e., a list of posts for the user. We’ll continuously listen to this stream of the list and update the news feed page accordingly. To make this entire process easier in Flutter, there’s a StreamBuilder widget that does all of these things. State Management When we build apps on the frontend, there are various states that keep changing because of user interactions. Some of them reside on a single page, like a radio button switch that is set to an on or off state. Some of these reside globally, like how the theme of the app can be switched from a light theme to a dark theme. Flutter is a declarative language. Flutter’s user interface is designed to represent the current status of our program. When the state of our app changes, we modify the state, which causes the user interface to redraw. There are various third-party packages out there that tackle this problem, each with a unique approach. We can find a list of third-party packages in Flutter’s documentation. https://docs.flutter.dev/data-and-backend/state-mgmt/options Provider Package The provider package, used for state management. The provider provides something to its underlying widget. We know that in Flutter we have widget trees that make up our whole UI, so a provider providing something at one node will be known by all of its child widgets. This is the key fundamental in the provider package. And what does it provide? Its actual state or value. Consumer Learn about the Consumer widget from the provider package. But there is a little problem with how we use the provider to rebuild the UI. it will listen to the change in the provider and call the build() method again, which essentially rebuilds the whole UI. We want to avoid rebuilding the whole UI since rebuilding consumes resources, although Flutter is optimized enough for big apps or a screen that updates continuously. We want to rebuild that part of the UI where the change is tangible. To solve this issue, we have a Consumer widget from the provider package. We just need to wrap those widgets that are changing with the Consumer widget. Managing State in Flutter Using BLoC Pattern Business logic component (BLoC) patterns allow Flutter applications to manage application state. The idea behind BLoC is that everything in the app should be represented as a stream of events. Widgets fire events and get responses. BLoC handles stream flow as a go-between based on the logic we specify. In other words, it’s a component that handles the business logic. The best part about the BLoC architecture is that we don’t need to import any libraries or learn any new syntax to build it. The implementation relies on the streams that the Dart programming language provides. A typical application has three layers: data, business logic, and user interface (UI). The widgets in our application make up the UI layer. The data layer houses the information that our application needs to display to the user to be relevant; this information may come directly from a database or an API. The layer that links the data layer and the UI layer is the business logic layer. It makes any calculations required in the middle and provides the data to the UI layer in an understandable way. Example: Let’s think of an e-commerce application, as in the illustration above. The interface that displays a list of available goods for purchase to the user is the UI layer. The functions that call the API to get the user’s list of available products are contained in the data layer. After making the necessary adjustments to the data so that the UI can make better use of it, the business logic layer sends the updated data to the UI layer. These necessary adjustments might involve deleting extra data that the UI layer won’t display. The data may also need to be formatted to meet UI requirements—for example, changing the price of a product in an e-commerce app from a float to a string that includes the currency. Each of these layers should be implemented entirely independently from the others. The code will be difficult to read and debug if these three layers are tightly coupled together. This is where the BLoC pattern comes in place. The BLoC pattern is a reactive programming model that works well with Flutter since its widgets are designed to adapt reactively to changes in business logic. Furthermore, BLoC can be used for dependency injection. Dependency injection is used when an application has to rely on a specific object to update the UI. Other state management libraries, such as Provider, rely entirely on dependency injection for state management. In BLoC, on the other hand, we get to pick the architecture that best fits our use case. The very definition of flexibility! Finally, BLoC works well in large-scale applications. Compared to alternative state management solutions, it provides the most readable code and has the most efficient architecture. This makes the code stable and easy to test and fix if it crashes Difference between flutter_bloc Library and RxDart RxDart is a library that provides reactive programming extensions to Dart. It’s based on the ReactiveX API, which is a popular API for reactive programming. Reactive programming is a programming paradigm that enables developers to write asynchronous, event-driven code. This is the paradigm that Dart’s Streams API originally helped us obtain. If you want a refresher on what streams are, you can go back to the Streams lesson of this course. What RxDart does is add to Dart’s original Streams API. It gives it superpowers that help us gain more stream classes, operators, and subjects. Differences between flutter_bloc library and RxDart BLoC and RxDart are both powerful state management solutions, but they have some key differences. Functionality The flutter_bloc library is designed specifically for Flutter development and provides a way to separate the business logic from the UI. It it’s a more focused solution that provides a clear separation of concerns. RxDart, on the other hand, is a more general-purpose library that can be used in any Dart project. It doesn’t necessarily have to be used to implement the BLoC pattern. It provides a way to handle complex data flows and streamline development. Ease of use The flutter_bloc library and RxDart are challenging to learn, especially for people new to reactive programming. When it comes to implementing the BLoC pattern, RxDart has a steeper learning curve than flutter_bloc. This is because RxDart requires us to implement the BLoC library manually using streams, while flutter_bloc gives us widgets and functions that help us easily create the BLoC pattern. Advantages of RxDart RxDart’s observables can push data, errors, and completion signals, whereas Dart Streams only emit data events and can throw errors but don’t have a built-in completion signal. A completion signal is a notification that a stream has completed its work and will not emit any more events. This signal is useful for determining when to clean up resources associated with the stream or when to perform additional processing after the stream has finished. RxDart was designed for asynchronous programming with an emphasis on concurrency and parallelism, while Dart Streams can be used for both synchronous and asynchronous programming but don’t have the same emphasis on concurrency and parallelism. Use BLoC for Every Screen Using BLoC for every screen is one of the best practices we can use when building an application. In this lesson, we’ll discuss the benefits of using BLoC for every screen. Benefits of using BLoC for every screen Simplifying complex UI logic: UI logic can become complex when dealing with user input, responding to network requests, and updating data. BLoC helps to simplify UI logic by separating the business logic from the presentation logic. This makes it easier to understand and maintain the codebase. Unit testing: By utilizing the BLoC design pattern on every screen, we can easily isolate and test the functionality of each screen independently. This approach can help to improve the overall maintainability and scalability of the application. How to use BLoC for every screen Every time we create a screen that has some state, we do the following: 1. Create a bloc folder in the same folder as your screen. 2. Implement the Bloc/Cubit. 3. Provide the BLoC to the screen using BlocProvider. 4. Use the BLoC for all business logic that needs to be done on the screen. Keep BLoCs simple Each BLoC should have a unique purpose and responsibility. If we find that a BLoC is handling too many responsibilities, it’s a sign that we should be using multiple BLoCs instead. For example, if we have a screen that displays a list of items and allows the user to edit each item, we should use separate BLoCs for displaying the list and editing each item. This makes each BLoC easier to understand and modify. BLoC is one of many state management methods that are offered in Flutter. There is some other methods: *Inherited widget The Inherited widget is a low-level state management solution provided by Flutter. It’s used to propagate data down the widget tree. It’s based on the concept of inheritance and can be used to share data between widgets in a tree. *Provider The Provider is one of the popular state management solutions in Flutter. It uses a simple, lightweight syntax to manage state across applications. The Provider is built on top of InheritedWidget, making it easy to use and highly performant *Riverpod Riverpod is a state management solution in Flutter that’s built on top of the Provider package. It’s a more modern and flexible approach to state management, providing a more intuitive and declarative syntax for managing state. *Redux Redux is another popular state management solution in Flutter that’s based on the Redux library from the JavaScript world. The main idea behind Redux is that the state of the application is stored in a single data store, which is immutable and can only be modified through actions. *Fish Redux Fish Redux is an implementation of the Redux pattern for state management in Flutter. It’s built on top of the Redux library and designed to simplify state management for complex applications. *GetIt GetIt is a simple yet powerful service locator package for Flutter. A service locator package is a design pattern that allows objects to locate services they need without being responsible for creating them. It’s great for small- to medium-sized projects where the state is not too complex. Responsive and Adaptive UI in Flutter The core concepts of responsive and adaptive UI in Flutter. You’ll start with common layout widgets before exploring application development using the most powerful widgets. Next, you’ll explore external packages that can extend responsiveness and adaptiveness beyond the core Flutter UI. At each step, you’ll see examples comparing and contrasting responsive and adaptive UIs with applications that do not invoke these principles. Finally, you’ll build functional widgets and application UI with hands-on coding environments What is a responsive design? In a responsive design, the UI automatically changes the layout based on changes in the number or orientation of available pixels. If we’re given a certain number of available pixels and their orientation, a responsive design can determine how the layout of the UI should be. Some of the standard widgets use responsive design by default. For instance, Scaffold will give AppBar the correct width depending on whether a phone is in landscape or portrait mode. adaptive design While responsiveness deals with how the UI looks on different devices, adaptiveness is concerned with what the application does on different devices. Each device has its own set of peripherals, such as a keyboard, touchscreen, mouse, and sensors, including GPS and temperature. For example, if an application wants to know the user’s location, it needs to access the GPS in some devices, while in other devices, it needs to infer the information from the IP address. Adaptive applications change the functionality depending on what the platform is capable of. Most of the packages we use already help make our applications adaptive. The url_launcher package will open the correct client whether we use a phone, a desktop, or a web browser. The location package will ask the user for permission and then provide the latitude and longitude of the user on any device. Easy Responsive Design with responsive_framework The main problem with making a Flutter application design responsive is displaying a pixel-perfect UI on multiple device types. The reason is that we need to recreate the same layout for each device. Here’s where a package like responsive_framework becomes useful. This package helps us by automatically scaling the UI of our application. When Flutter needs to layout the UI after the screen size changes, it resizes the widgets by stretching unconstrained dimensions and fixing constrained ones. responsive_builder To make our Flutter applications responsive, we can use MediaQuery and LayoutBuilder to define the pixel breakpoints for each device class—desktop, tablet, and smartphone. Another solution is to use an existing package that defines the most common breakpoints, such as responsive_builder. The responsive_builder package provides widgets that require less code when we’re implementing responsive design to your applications. The use of Ticker in Flutter We use a ticker to tell how often our animation is refreshed in Flutter. Signals are sent at a constant frequency, such as 60 times per second, using this type of signal-sending class. We understand it better with our watch, which ticks constantly. For each tick, a callback method is provided that has the time since the first tick at each second since it was started. The tickers are synchronized immediately, even if they begin at different times. Flutter Inspector. There is a powerful tool called Flutter Inspector for Flutter applications that allows you to visualize the blueprint of your widgets and their properties. Using it, you can diagnose various layout issues and understand the current layout. Flutter Inspector offers the following benefits: Select widget mode Toggle platform Show paint baselines Show debug paint Refresh widget Enable slow animations Show/hide performance overlay Execute code only in debug mode We first need to import the dart foundation in order to run the code only in debug mode: import 'package:flutter/foundation.dart' as Foundation; The next step is to use kReleaseMode as follows: if (Foundation.kReleaseMode){ // is Release Mode?? print('release mode'); } else { print('debug mode'); } The use of Mixins Multiple inheritances are not supported by Dart. Thus, we need mixins to implement multiple inheritance in Flutter/Dart. The use of mixins makes it easy to write reusable class code in multiple class hierarchy levels. Mixins can also be used to provide some utility functions (such as RenderSliverHelpers in Flutter). The packages and plugins in Flutter. A package is a collection of classes, interfaces, and sub-packages that enable the creation of modular code that can be shared easily among users. Applications can be quickly developed using packages instead of developing everything from scratch. You can import new widgets or functionality into an app using a package in Flutter. There is a slight difference between plugins and packages as given below: Plugins: Using native code, enables more usability and makes it easier to use the device. Packages: These are new code or components written in the dart programming language. Packages and plugins are often referred to as packages on DartPub, and specific distinctions between the two are made only during the creation of a new package. The flutter architecture Upper Layer: The upper layer consists of the Dart programming language along with the widgets, animations, illustrations, customizations, etc. The middle layer or the Flutter Engine: This layer deals with text display, formatting, layout, etc. Bottom Layer or the built-in service: This layer is for managing plugins or packages. What are different build modes in flutter? Depending on your development phase, the framework compiles your code in different ways or modes, which we called a build mode. Flutter's tooling allows the application to be compiled in three modes. Depending on our stage of development, we may choose between these compilation modes. Debug Mode: This mode enables debugging of apps on a physical device, emulator, or simulator. Assertions and service extensions are enabled here. Quick deployment is then achieved by optimizing compilation. Profile Mode: In this mode, some debugging abilities are maintained, enough to analyze the app's performance while testing. Tracing and some extensions are enabled in this case. On emulators and simulators, profile mode is disabled since their behavior does not reproduce real-world performance. The following command can be used to compile the profile mode: flutter run --profile Release Mode: When deploying the app, this mode is used to minimize the size of the footprint and maximize optimization. Debugging, assertions and service extensions are disabled here. Faster startup, faster execution, and less size are its key features. The following command can be used to compile the release mode: flutter run --release The difference between runApp() and main() in flutter. main(): This function starts the program. Flutter does not allow us to write any program without the main() function. runApp(): Using runApp(), you are able to return the widgets that are connected to the screen as a root of the widget tree that will be rendered on the screen. This function is called in the main function, which is the driver of the app. The difference between Hot reload and Hot restart. For any dart application, the initial execution requires a fair amount of time. Therefore, to solve this problem, flutter has two features: Hot Reload and Hot Restart, which reduce the execution time of our app after we run it. Hot Reload: It is considered an excellent feature of flutter that takes approximately one second to perform its functionality. With this function, you can make changes, fix bugs, create UIs, and add features easily and quickly. By utilizing the hot reload feature, we can quickly compile the new code in a file and send it to Dart Virtual Machine (DVM). As soon as DVM completes the update, it updates the app's UI. The preserved state is not destroyed in hot reload. Hot Restart: It has a slightly different functionality as compared to a hot reload. In this, the preserved states of our app are destroyed, and the code gets compiled again from the beginning. Although it takes longer than a hot reload, it's faster than a full restart function BuildContext. BuildContexts are used to identify or locate widgets in widget trees. Each widget has its own BuildContext, i.e., one BuildContext per widget. Basically, we're using it to find references to other widgets and themes. In addition, you can utilize it to interact with widget parents and access widget data. pubspec.yaml file. The pubspec.yaml file, also known as 'pubspec', is a file that is included when you create a Flutter project and is located at the top of the project tree. This file contains information about the dependencies like packages and their versions, fonts, etc., that a project requires. It makes sure that the next time you build the project, you will get the same package version. Additionally, you can set constraints for the app. During working with the Flutter project, this configuration file of the project will be required a lot. This specification is written in YAML, which can be read by humans. The following are included in this file: General project settings, like name of the project, version, description, etc. Dependencies within a project. The assets of the project (e.g., images, audio, etc.). Create HTTP requests in Flutter To create HTTP requests, use the HTTP package (import 'package:http/http.dart' as http;). In the following manner, we can make the Requests: http.get(‘https://jsonplaceholder.typicode.com/albums/1‘); It will return a Future. keys in flutter Keys in flutter are identifiers for widgets, elements, and semantic nodes, whereas GlobalKeys and LocalKeys are the subclasses of Key. Two database packages mostly used in Flutter. As far as Flutter is concerned, the following database packages are widely accepted and mostly used: *Firebase database: It gives users access to and control over the cloud database. Firebase basically provides a NoSQL database for Flutter apps with the ability to manage data retrieval and storage through JSON protocol. Data sync and quick loading make it one of the most suitable options for Flutter Apps. Features: NoSQL DB APIs (REST only) Authentication Analytics Storage *SQFlite database: Users can access and modify the SQLite database using this. With this database, you have full control over your database, queries, relationships, and anything you could desire. Features: Serverless Zero configuration Open-Source Compact Single DB file Limitations of Flutter Following are the limitations of a flutter: Lack of third-party libraries Larger release size Flutter works with Dart language which is not so advanced as C# or C-Sharp and JavaScript. Not so user-friendly for iOS developers as it is developed by Google and it takes time to resolve the issues for apple devices. Testing Flutter apps There are several levels of testing you can perform on a Flutter app to ensure it functions correctly. Here are the main ones: Unit testing: This involves testing individual units of code, like functions or methods, in isolation from the rest of the application. This helps identify bugs early in the development process. Widget testing: This focuses on testing individual widgets in a controlled environment. Widget tests verify that the UI of a widget looks and interacts as expected. Integration testing: This type of testing checks how well different units within your app work together. It ensures that widgets, services, and other components interact seamlessly. User testing: This involves simulating real user interactions with the app to identify usability issues and ensure a smooth user experience. Testing Packages for Flutter 1. Core Packages: test: This is the foundation for all testing in Flutter. It provides functionalities for writing tests (unit and integration), grouping tests, assertions (verifying expected behavior), and running tests. 2. Widget Testing: flutter_test: This package extends the test package with functionalities specifically for testing Flutter widgets. It allows you to pump widgets into a test environment, interact with them, and verify their behavior and appearance. 3. Mocking: mockito: This package helps with creating mock objects for dependency injection in unit tests. It allows you to isolate code under test and control the behavior of dependencies.

Use Quizgecko on...
Browser
Browser