Flutter For Dummies
Book image
Explore Book Buy On Amazon
At its core, Flutter is an API for creating apps. Most Flutter apps run on mobile devices, but Flutter apps can run on laptop and desktop computers, too. Flutter certainly wasn't the first API for mobile devices, so why should anyone consider using Flutter to create apps?

Flutter allows for cross-platform development

To get to the heart of Flutter, let’s consider a scenario that was retold by an app developer.

My favorite burger joint advertised a new mobile ordering app. I needed the app so that I could quickly hop off a commuter train, grab a burger, and run to a nearby tech meeting. I did this several times each month. But I had a problem: The app ran only on iPhones, and I had an Android phone.

Behind the scenes, the burger joint's app developers were hard at work converting their iPhone app to an Android app. This was no minor task, because Android's API doesn't recognize the same commands as iPhone's API. Going from one API to the other isn't straightforward. It's not a matter of making routine code changes. To convert from one kind of phone to another, developers rewrite thousands (and maybe even millions) of lines of code. The process is time-consuming and expensive.

So I waited and waited for the restaurant to have an Android app. I was so desperate for a delicious cheeseburger that I finally broke down and bought a second phone. But that turned out to be a bad idea. As soon as my new iPhone arrived, the burger place released its shiny, new Android app.

The moral of this story comes down to things called platforms. People throw around the word platform as if the word means everything and nothing. But in app development, a platform is a particular operating system along with the hardware the OS runs on.

What makes the Android platform different from its iOS counterpart? To create radio buttons in Android's API, you write code of the following kind:

<RadioGroup>
 
  RadioButton
    android:id="@+id/radioButton1"
    android:text="Red"
    android:onClick="onRadioButtonClicked" />

RadioButton android:id="@+id/radioButton2" android:text="Yellow" android:onClick="onRadioButtonClicked" />

RadioButton android:id="@+id/radioButton3" android:text="Green" android:onClick="onRadioButtonClicked" /> </RadioGroup>

Try converting that code to work on an iPhone. The iOS API doesn't have radio buttons, so, to adapt an Android app with radio buttons for iOS, you write code to make things that look like radio buttons. You also code rules for the radio buttons to follow — rules like "only one button at a time can be selected."

If you don't want to create radio buttons from scratch, you can replace Android's radio buttons with an iOS picker component, a thing that looks like an old automobile odometer. One way or another, replacing an app's components takes time and costs money.

Some companies give up and create apps for only one platform — iPhone or Android. Other companies hire two teams of programmers — one for iPhone development and another for Android development. Still other companies have one team of programmers that work on both versions of the code. For the companies' managers, the problem is exasperating. Why spend nearly twice the money and create two apps that do almost the same things?

The app developer community has names for this ugly situation:

  • Software written for one platform isn't compatible with other platforms.
  • The mobile phone arena suffers from fragmentation: The market is divided between two different operating systems, and the Android half is divided among many vendors' phones.
A program that makes direct use of either the Android or iOS API is called native code, and native code written for Android can't run on an iOS device. In the same way, native code written for iOS is meaningless to an Android device. What's a developer to do?

A framework is a second-level API. What the heck does that mean? A framework is an API that serves as an intermediary between the developer and some other API. If direct use of the Android or iOS API is problematic, you switch to a framework's API. The framework's API deals head-on with Android's and iOS's problems.

Frameworks like Flutter offer an alternative to native app development. When you write a Flutter program, you don't write code specifically for Android or iOS. Instead, you write code that can be translated into either system's API calls. Here's how you create radio buttons in the Flutter framework:

Radio(
 value: TrafficLight.Red,
 groupValue: _trafficLightValue,
 onChanged: _updateTrafficLight,
),
Radio(
 value: TrafficLight.Yellow,
 groupValue: _trafficLightValue,
 onChanged: _updateTrafficLight,
),
Radio(
 value: TrafficLight.Green,
 groupValue: _trafficLightValue,
 onChanged: _updateTrafficLight,
)
Your computer translates code of this kind into either Android API calls or iOS API calls — or both. That's cool!

Flutter offers a quick-and-easy development cycle

There's no doubt about it — a long and arduous app development cycle hinders productivity. These days, shaving a few seconds off the turnaround time can make a huge difference.

Here's what happens when you create an app for mobile devices:

  1. You write some code, or you modify some existing code.

    You don't write Android or iOS code on a phone of any kind. Phones aren't powerful enough for all the editing and other stuff you need to do. Instead, you create an app's code on a laptop or desktop computer. This laptop or desktop computer is called your development computer.

  2. You issue a command for your development computer to build the code.

    Building the code takes place in several stages, one of which is called compiling. Compiling means automatically translating your program from the source code you wrote to detailed object code instructions. Think of object code as a bunch of zeros and ones. It's very detailed and extremely unintuitive. Humans hardly ever read or write object code but, at the heart of things, processors respond only to object code instructions.

    In addition to the translation step, the build process connects the program you wrote with additional code that your program needs in order to run. For example, if your program accesses the Internet, the build process integrates your code with existing network code.What happens next?

  3. The development computer deploys your code to a target device.

    This so-called "device" may be a real phone connected to your computer or a picture of a phone on your computer's screen. One way or another, your program starts running.

  4. You press buttons, type text, and otherwise test your app to find out whether it's doing the things you want it to do.

    Of course, it's not doing all those things. So you return to Step 1 and keep trying.

Steps 2 and 3 can be painfully slow. For some simple iPhone and Android apps, several minutes may go by as a computer prepares code for the program's next run. This sluggishness reduces productivity considerably.

But along with Flutter comes some good news. Flutter uses the Dart programming language, and Dart comes with these two (count ’em — two) compilers:

  • Ahead-of-time (AOT) compiler

    With an AOT compiler, your development computer translates an entire program and makes the translated code available for devices to run. No further translation takes place when the devices run your program. Each target device devotes its processing power to the efficient running of your code.An app running on AOT-compiled code runs smoothly and efficiently.

  • Just-in-time (JIT) compiler

    With a JIT compiler, your development computer translates enough code to start the app running. It feeds this code to a test device and continues translating while the test device runs the app. If the developer presses a button on the test device's screen, the JIT compiler hurries to translate that button's code.An app running on a JIT compiler may appear to be sluggish because the compiler translates code while the app runs. But using a JIT compiler is a great way to test an app.

Here's what happens when you develop a Flutter app:
  1. You write some code.
  2. You issue a command for your development computer to build the code.

    The first time around, building code can take some time.

  3. The development computer deploys your code to a target device.Again, you face a noticeable time lag.
  4. In testing your code, you find out that it's not doing all the things you want it to do.
  5. You modify your existing code, and then . . .
  6. You issue a command for your development computer to rebuild the code.
Here's where Flutter's magic happens. Dart's JIT compiler recompiles only the part of the app that you've modified and sends the change straight to the target device. The modified code starts running in a fraction of a second. You save hours of time every day because you're not waiting for code changes to take effect.

Flutter gives you two ways to apply changes to a running app:

  • With hot restart, the app begins its run anew, removing any data that you've entered during the most recent test, displaying the app as if you're running it for the first time.
  • With hot reload, the app takes up from where it left off, with the data you last entered intact, if possible. The only changes are the ones dictated by your modifications to the code.
Flutter's hot restart and hot reload are both blazingly fast. They turn the app development cycle into a pleasure rather than a chore.

Flutter provides a great way to think about app development

The language you speak influences the way you think. If you don't believe this, look up the Sapir-Whorf hypothesis. You're bound to find it on your favorite linguistics website.

Spoken languages are neither good nor bad, but programming languages can have good qualities and bad qualities. Most hybrid apps are written in the JavaScript programming language. Yes, JavaScript is one of the world's most widely used languages.

But, no, JavaScript doesn't encourage good software design. It's easy to write confusing code in JavaScript because its rules are quite permissive. You can write sloppy JavaScript code, and the code runs just fine. That is, it runs fine until someone enters unexpected input. When that happens, you have trouble figuring out how your code was working in the first place.

Even when you're not busy fixing errors, adding new features to JavaScript code can be difficult and frustrating. JavaScript aficionados will argue with every word in this paragraph but, one way or another, JavaScript has its downsides.

Apple's iOS platform uses the Swift and Objective-C languages, whereas Android uses Kotlin and Java. Objective-C dates back to the early 1980s and it's showing its age. The other three languages fare pretty well on the scale of good language features, but none of them is as straightforward and intuitive as Dart.

On top of that, both iOS and Android divide an app's code into two separate parts:

  • Layout: How the app looks.
  • Logic: The sequence of instructions that the app performs.
The Android radio button example above is neither Kotlin nor Java code. It's XML code. It has a different format and lives in a different file from the code that responds to radio button choices.

Separating layout from logic is a good thing. It puts distinct aspects of an app into different parts of the code. Developers can maintain each part independently. For an Android developer, that's a good thing.

But this isn't an article about Android development. It's about Flutter. To that end, consider that separating layout from logic is not optimal. Here's why:

You may have heard the all-encompassing mantra of Flutter app development:

In Flutter, almost everything is a widget.

And what is a widget? In a mobile app, every button is one of the app's widgets. Every text field is a widget. The app itself is a widget. The positioning of buttons and text fields is a widget. The animating of objects from one part of the screen to another is a widget. When you create a Flutter app, you put widgets inside of other widgets, which in turn are inside even more widgets. The code below has some fake code that illustrates the point:

Like a Wheel Within a Wheel

// Don't fall for the trickery. This isn't real Flutter code!
Application(
 Background(
  CenterWhateverIsInsideThis(
   Button(
    onPressed: print("I’ve been clicked."),
    Padding(
     Text(
      "Click Me"
     ),
    ),
   ),
  ),
 ),
)
This code has a Text widget inside of a Padding widget, which is inside of a Button widget inside a CenterWhateverIsInsideThis widget. That CenterWhateverIsInsideThis widget is inside a Background widget, which is inside an Application widget. The code is modeled after real Flutter code. The real Flutter code creates the app shown next. When the user presses the Button, the words I’ve been clicked appear.

Flutter app button An app with a button.

To see the real code that inspired the fake code you see here, check out this Flutter code and look for the big download link. The real code is in a file named app0101.

Compare the image above and the one below. The to image shows the app as the user sees it. The following image shows the same app as the Flutter developer codes it.

Flutter widget Widgets within widgets.

If you're not already a Flutter developer, the word widget might suggest a visible component, such as a button, a slider, an icon, or some other such thing. But in Flutter, things that aren't really visible are also widgets. For example, in the code listing above, CenterWhateverIsInsideThis is a widget. Having layout features like CenterWhateverIsInsideThis be widgets is a powerful idea. It means that Flutter developers can focus their attention on one overarching task — stuffing widgets inside other widgets. Flutter has a certain simplicity and elegance that other app development frameworks don't have.

Flutter has no built-in widget named CenterWhateverIsInsideThis. But don't be disappointed. Flutter's Center widget does what the fictitious CenterWhateverIsInsideThis widget is supposed to do.

Want to learn more about Flutter? Check out our Flutter Cheat Sheet.

About This Article

This article is from the book:

About the book author:

Dr. Barry Burd holds an M.S. in Computer Science from Rutgers University and a Ph.D. in Mathematics from the University of Illinois. Barry is also the author of Beginning Programming with Java For Dummies, Java for Android For Dummies, and Flutter For Dummies.

This article can be found in the category: