I’ve built a slightly more interesting application using Flutter. Using an
XML feed from
BoardGameGeek’s API, the application displays a list of the current hot games complete with thumbnail
images.
Here‘s the code. I
used a standard Flutter app template and also added a few
packages
to the project.
I’ve coded a substantial amount of Windows Presentation Foundation (WPF) and
Silverlight code over the years. One of the concerns that often came up was the UI
tree …, the more complex it was, the slower the app often was without lots of
tricks. Using the new inspector for Flutter apps, I selected one of the images in
the UI. Needless to say, there are a few objects created to
represent the UI tree. In fact, I had trouble capturing the image for this blog
post. :)
I don’t have evidence that this generally will be a performance problem. Maybe
with relatively simple mobile applications, a deep rich object based UI hierarchy
won’t affect performance as much as it might in a desktop application of
reasonable complexity. Regardless, it’s worth considering as you build a UI.
Back to what I built. When a user taps on a board game in the list, I’ve wired
the code to call the _showGameItem below. I appreciate that
there’s an easy way to navigate to a new page on the stack and show a UI, all
within a single function. Of course, I could have split it into multiple builder
functions if needed.
To register an event callback for the onTap, I’d tried
finding a Widget that exposed it directly. I’m accustomed to elements having
events (often bubbling events) that would have exposed something like
onTap. However, with the exception of specialized widgets like
Buttons for example, it’s not exposed on most Widgets (even those that have
UI). So, at the outer layer of the items being shown in the
ListView, I used a GestureDetector to capture the
tap event:
I would have preferred that the Container to have the event
available. Maybe it’s not as pure, but, meh. I’d like to reduce
the noise of building a UI and adding yet another layer just to capture an event is
a distraction.
Architectural elegance does not always lead to a framework that is easy or
friendly.
While I wasn’t really concerned about performance of my application or the
possible impact from hitting the BoardGameGeek API a few times, I used application
storage to cache a copy of the XML data that’s retrieved from BoardGameGeek
just to get some experience with the APIs. Further, I added code to store the next
time the file can be updated to the SharedPreferences object instance (to prevent it
from being updated too frequently). I liked the simple exception handling in Dart as
it’s relatively low impact to handle a specific exception type without caring
about the details by using the on clause (just by dropping the
catch(e)).
I noticed that the exception handler can specify one or two parameters. The first is
always the exception and the second is the stack trace (StackTrace). I’m not sure why the stack trace isn’t part of the exception object
though.
When the file is cached completely and successfully, the Widget state is updated,
which triggers an application refresh, which is what happens on lines 29-32.
Had Flutter been an option in the earlier days of Android, it would have been a
strong contender in the application building space, especially that it runs on
Android and iOS. From reading some of the issues on Github, the general consensus is
that the cross-platform Flutter competitor to beat is React Native. In fact,
I’m surprised that it has taken Google this long to produce a potentially
viable alternative to the Java Android development tools. I’d honestly thought
they’d announce something several years ago (I’ve watched Google I/O for
many years for the announcement).
If Android devices were upgraded more routinely (as are iOS devices), web
technologies such as installed progressive web applications could be a serious
contender and alternative for many application types. But, modern Android operating
system versions are very slow to roll out (if ever) to the majority of devices.
Over half of Android devices are running Android 6.0 or earlier.
Until the Android OEM ecosystem delivers timely updates to all phones newer than 5
years, solutions like Flutter (and competitors) remain a potentially reasonable way
to reach a large variety of devices without needing to update to recent OS releases.
However, it may be that the hardware hosting older versions, such as 6.0/Marshmallow
and earlier are not capable of adequately executing a modern app built with
technology like is used by Flutter.
Continued concerns
I still find the syntax of building a UI to be cumbersome and frustrating for
several reasons:
-
Using code to describe the UI is not effective for me. I can’t as quickly
look at a block of code and determine what the UI is likely to be. It’s
just too noisy.
-
I’m constantly frustrated by getting the right number of closing
parentheses to match the open parentheses. Using the auto formatting tools of
Android Studio for Dart doesn’t make it easier. There are 10 lines that
are marking the closing of some block. I’ll add an example below of how
messy it starts to look if they’re combined in a way that the auto
formatter suggests.
-
In fact, if it were easy, I’d want to lines to start with the Widget type
rather than child: new WidgetName(. But, there’s not an
obvious way to format the code that way as the named parameters
(child) are needed to provide the widget instance.
-
Layout is a mess of classes and initialization. The examples on the web site
make general sense, but when I’ve tried to innovate on my own and
understand how to build other UI patterns, I’ve struggled to find the
right combination of Widget classes that represent a desired layout. I imagine
that with practice I’d get better, but I also would likely create multiple
stateless Widgets to make some of the common patterns I’d expect to use
routinely.
Does Flutter have a future? Would you want to build an app that you wanted to still
be building on 3-4 years from now? As it’s still in Alpha form, I
wouldn’t do anything but explore.
Then, there’s Dart. The strength of many development options for mobile and
web development is the ability to concentrate on one programming language and have
it work on client and server. With Flutter and Dart, if you don’t have a
serverless-style architecture in place, you’ll need to use a second
programming language. And that may limit its adoption. Of course, developers that
work on multiple app platforms today have accepted this is just the price they have
to pay, so maybe that’s not a big deal. If you’ve got a development shop
that can have developers specialize, then this may be a non-issue entirely. For
startups and very small teams, it’s a potential obstacle that must be
considered.
Notes
If you try the code as I’ve put it on GitHub, you may encounter an error with
a codec. This is actually a bug in the Flutter framework and apparently is fixed
already and will be available generally at some point in a mainline branch.
You’ll just need to rerun it.
Example of Auto Formatting
Note the parentheses on lines 20 and 21. That style causes me to just keep adding
closing parentheses until the syntax is correct or the error is different.
They’re very difficult to count.
Android Studio
Android Studio is an acquired taste from a theme and style perspective. With a few
adjustments, it’s tolerable.
I’m not sure why Keywords in the Darcula theme are bright, bolded orange.
While keywords are important, they’re unnecessarily vibrant, especially in
code blocks describing the UI:
I turned off the bold minimally and changed the color of class names as an
experiment … it’s better, but not right yet.