12 Amazing Practices to Simplify Flutter App Development

72

One of the prime responsibilities of a developer is to create a future-ready solution that keeps the maximum percentage of users engaged. This has therefore resulted in them building apps for the two popular OS currently in the market- iOS and Android.

However, while building these solutions, the professionals face a dilemma- if there is a pathway through which they can enter both the OS (Android and iOS) at the same time. This is where most of them embrace cross-platform app development. But while performing cross-platform app development, another major worry for them is selecting the best tech stack for this task.

A tech stack that is most in-demand among developers globally is Flutter. Holding 42% market share, it is the preferred choice among developers when they set.

Holding 42% market share in 2021, Flutter is recommended for building fully-functional and robust cross-platform apps.

Therefore, if you are considering using Flutter for app development make sure you know the practices that promise to make this journey memorable.

Read the lines below to build an app that performs with the utmost high quality and saves time for you when you write codes for iOS and Android.

1. Keep Extension Name & Classes in UpperCamelCase

While naming the convention, make sure the extension name, classes, etc. are in UpperCamelCase.

Look at the code below to understand:

class MainScreen { … }
enum MainItem { .. }
Typedef Predicate<T> = bool Function(T value);
Extension MyList<T> on List<T> { . . . }

Also ascertain that the names of the libraries, directories, etc. are in snake_case (lowercase_with_underscores)

Check the below code to know how you can do this:

library firebase_dynamic_links;
import 'socket/socket_manager.dart';

Last, keep the variables and the name parameters in lowerCamelCase

var item;
Const bookPrice = 3.14;
Final urlScheme = RegExp('^([a-z]+):');
void sum(int bookPrice) {
// …
}

2. Specify Member Type When Value Type is Known

Make sure to specify the member type when you are aware of the value type. This follows next by trying to avoid the use of var when required.

//Do
Int item = 10;
Final Car bar = Car();
String name = ‘michael’;
Const int timeOut = 20;//Don’t
Var item = 10;
Final car = Car();
Const timeOut = 2000;

3. When Making Build Function — Keep It Pure

Work towards moving out operations from the build method which may adversely affect the rebuild performance.

Look at the code below:

class _HelloWidgetState extends State<HelloWidget> {
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: getText(),
builder: (context, AsyncSnapshot<String> snapshot) {
return Text(snapshot.data ?? '');
});
}
}

The code depicts that with the presence of a pure build function, UI will be of exceptionally high UI without the requirement of an exceptionally high percentage of resources while performing the task.

4. Refactor Code Into the Widgets Instead of Methods

When you refract code into the widget, you get the guarantee of receiving the benefits of the entire widget lifecycle. Hence, the incidents of unnecessary rebuilds get eliminated. Therefore, it is recommended to refactor the code into the widget instead of into the methods so then overall performance gets enhanced.

Look at the code below to gain perspective on how you can perform this task.

class HelloWidget extends StatelessWidget {
const HelloWidget({
Key? key,
}) : super(key: key);@override
Widget build(BuildContext context) {
return Text('Hello');
}
}

5. Declare Multiple Variables with Shortcut

In case you want to declare multiple variables without spending too much time, do this with the shortcut as depicted in the code below.

int mark =10, 
total = 20,
amount = 30;

6. Use Widget Builder to Make the Main Widget More Lean and Readable

Refactor a widget into a separate one so that your main widget becomes reasonably leaner and easy to read, both, at the same time.

Check the below code to gain knowledge on how you can perform this.

import ‘package:flutter/material.dart’;
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme:
ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
),
}
}

7. Use Flutter BloC Widgets

Using the widgets will help you seamlessly rebuild the UI components. This is something that you should make sure to remember when using Flutter for app development.

When talking about the Flutter_bloc package, we need to remember that four main classes are easy to wrap around the Flutter widget, namely, BlocProvider, BlocListener, BlocBuilder, and BlocConsumer.

Check the support these four classes provide in rebuilding the UI components when responding to different state changes.

  • Using BlocProvider

With BlocProvider, you can create new blocs and close the BloC as well, at the same time. This is easy to access from the remaining subtree.

See the code to understand how BlocProvider performs the task of creating new blocs.

BlocProvider(
create: (BuildContext context) => BlocA(),
child: ChildA(),
);
  • Using BlocListener

With BlocWidgetListener, it becomes easy to handle situations or functionalities which in fact may be requiring once per stage changes.

BlocListener<BlocA, BlocAState>(
listener: (context, state) {
// do stuff here based on BlocA's state
},
child: Container(),
)
  • Using BlocBuilder

With the help of the widget, the overall boilerplate code requirement gets reduced. Therefore, the tasks of building and rebuilding the child subtree during state changes becomes easy to perform.

BlocBuilder<BlocA, BlocAState>(
builder: (context, state) {
// do stuff here based on BlocA's state
}
)
  • Using BlocConsumer

Only when the requirement of UI rebuilding and execution of reactions to changes made in the state of the bloc syntax becomes necessary, you should then use BlocConsumer.

See the code below to check how you can perform the task of reducing the overall boilerplate code with the help of this widget.

BlocConsumer<BlocA, BlocAState>(
listener: (context, state) {
// do stuff here based on BlocA's state
},
builder: (context, state){
// do stuff here based on BlocA's state
}
)

8. Better to Use ?? Operators for Conditional Expressions

It is better to use ‘??’ and ‘?’ operators respectively when performing conditional expressions instead of null checks.

//Don't
v = a == null ? b : a;
//Do
v = a ?? b;
//Don't
v = a == null ? null :
a.b;
//Do
v = a?.b;

9. Maintain a Well-Defined Architecture

Flutter requires developers to simply learn one language alone — C, C++, and Dart. Thereafter, tasks like coding and design become easy to perform.

Hence, when using the software development kit (Flutter), make sure to possess a well-defined architecture. This is after understanding the different options and discussing thereafter with the developers on the convenience level they have using either of them for app development.

10. Use debugPrint()

debugPrint() and print () help to log into the console. Therefore, if you as a developer use print() and output, it may become possible that Android may go on to discard some log lines. Hence, it is recommended to use debugPrint().

11. Use Dart Code Metrics

To enhance the overall quality of the app whose development has taken place with Flutter, it is recommended to use Dart Code Metrics. The static code analysis tool helps developers to monitor and improvise the overall quality of the code.

Hence, when you set out to enhance the overall code quality, make sure you perform the tasks listed below.

  • Try not to use the Border.all constructor
  • Extract callbacks
  • Use single widgets per file
  • Avoid returning the widgets and also unnecessary setState().

12. Use const constructor

It is recommended to avoid using unnecessary const keywords. Instead, it is better to use const constructor widgets. This will help to substantially reduce the work that you may have to perform in the garbage collector. This is certainly a booster in a situation where your app may require frequent rebuilding.

Look at the code below to check how const for Text widget dependency gets eliminated as a result of const being applied already to the parent widget.

const Container(
width: 100,
child: const Text('Hello World')
);

All these Flutter app development practices will ensure that the readability of the code is improved to a greater extent and also the performance of the app is of the highest quality.