- Examining performance differences between Native, Flutter, and React Native mobile development.
- Alex Sullivan
- The Nuggets translation Project
- Permanent link to this article: github.com/xitu/gold-m…
- Translator: LeeSniper
- Proofread by: LeviDing
Deciding whether your company’s mobile application is truly Native or implemented in a cross-platform approach (such as React Native or Flutter) can be a difficult decision. One factor that is often considered is speed — we all agree that most cross-platform methods are slower than native methods, but it’s hard to put an exact figure on it. Therefore, when we think about performance, we often rely on intuition rather than concrete data.
Because I wanted to add some structure to the performance analysis above, and because I was interested in how Flutter fulfilled its performance promise, I decided to build a very simple application for the Native, React Native, and Flutter versions to compare their performance.
The test application
I built the application as simple as possible, while ensuring that it still provided at least some information. It’s a timer app — specifically, the app displays a blob of text that counts over time. It displays the number of minutes, seconds, and milliseconds that have passed since the application started. Pretty simple.
Here’s what it looks like in its initial state:
This is what it looks like after 1 minute, 14 seconds and 890 milliseconds:
Riveting.
But why a timer?
I chose the timer app for two reasons:
- It is easy to develop on every platform. At the heart of this application is some type of text view and repeat timer, easily translated into three different languages and stacks.
- It shows how efficient the underlying system is at drawing content on the screen.
Let’s take a look at the code
Fortunately, the application is small enough that I can add the code directly here.
Native Android Apps
Here’s the MainActivity of the native Android app:
class MainActivity : AppCompatActivity() {
val timer by lazy {
findViewById<TextView>(R.id.timer)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initTimer()
}
private fun initTimer() {
val startTime = elapsedRealtime()
val handler = Handler()
val runnable: Runnable = object: Runnable {
override fun run() {
val timeDifference = elapsedRealtime() - startTime
val seconds = timeDifference / 1000
val minutes = seconds / 60
val leftoverSeconds = seconds % 60
val leftoverMillis = timeDifference % 1000 / 10
timer.text = String.format("%02d:%02d:%2d", minutes, leftoverSeconds, leftoverMillis)
handler.postDelayed(this, 10)
}
}
handler.postDelayed(runnable, 1)
}
}
Copy the code
React Native
Here’s the app.js file for the React Native App:
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<Timer />
</View>
);
}
}
class Timer extends Component {
constructor(props) {
super(props);
this.state = {
milliseconds: 0,
seconds: 0,
minutes: 0,
}
let startTime = global.nativePerformanceNow();
setInterval(() => {
let timeDifference = global.nativePerformanceNow() - startTime;
let seconds = timeDifference / 1000;
let minutes = seconds / 60;
let leftoverSeconds = seconds % 60;
let leftoverMillis = timeDifference % 1000 / 10;
this.setState({
milliseconds: leftoverMillis,
seconds: leftoverSeconds,
minutes: minutes,
});
}, 10);
}
render() {
let { milliseconds, seconds, minutes } = this.state;
let time = sprintf("%02d:%02d:%2d", minutes, seconds, milliseconds);
return (
<Text>{time}</Text>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',}});Copy the code
Flutter
Finally this is our Flutter main.dart file:
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _startTime = new DateTime.now().millisecondsSinceEpoch;
int _numMilliseconds = 0;
int _numSeconds = 0;
int _numMinutes = 0;
@override
void initState() {
super.initState();
Timer.periodic(new Duration(milliseconds: 10), (Timer timer) {
int timeDifference = new DateTime.now().millisecondsSinceEpoch - _startTime;
double seconds = timeDifference / 1000;
double minutes = seconds / 60;
double leftoverSeconds = seconds % 60;
double leftoverMillis = timeDifference % 1000 / 10;
setState(() {
_numMilliseconds = leftoverMillis.floor();
_numSeconds = leftoverSeconds.floor();
_numMinutes = minutes.floor();
});
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new Text(
sprintf("%02d:%02d:%2d", [_numMinutes, _numSeconds, _numMilliseconds]), ), ) ); }}Copy the code
Each application follows the same basic structure — they all have a timer that repeats every 10 milliseconds and recalculates the number of minutes, seconds, and milliseconds that have passed since the timer started.
How do we measure performance?
For those unfamiliar with Android development, Android Studio is the preferred editor/environment for building Android applications. It also comes with a number of useful parsers to analyze your applications-specifically, it has a CPU parser, a memory parser, and a network parser. So we will use these analyzers to determine performance. All the tests were run on Thoughtbot’s Nexus 5X and my own first-generation Google Pixel. React Native applications will run with the –dev flag set to false and Flutter applications will run in a profile configuration to simulate a published application rather than a JIT-compiled debug application.
Show me the data!
Now comes the most interesting part of this article. Let’s take a look at the results running on the Nexus 5X at the Thoughtbot office.
Native app results on Nexus 5X
React Native on Nexus 5X
Results of the Flutter application on Nexus 5X
The first thing these results show is that when it comes to performance, Native Android apps don’t beat React Native and Flutter apps by a long shot. The CPU usage on the Native application is less than half that of the Flutter application. Flutter uses less CPU than the React Native application, but the difference is not significant. The memory usage of the Native application was also low and increased on both React Native and Flutter applications, but this time the React Native application performed better than the Flutter application.
The next interesting thing is how similar the React Native and Flutter applications are in performance. While this application is undoubtedly trivial, I would have expected the JavaScript bridge to be more affected because the application is sending so many messages through it so quickly.
Now let’s see what happens when we test it on Pixel.
Results of native apps on Pixel
Result of the React Native app on Pixel
Pixel above the result of the Flutter application
So, I was immediately surprised by the apparently higher CPU usage on the Pixel. It’s certainly a more powerful (and, in my opinion, smoother) phone than the Nexus 5X, so I naturally assume that the CPU utilization of the same app will be lower, not higher. I can understand why memory usage is higher, as there is more memory space on the Pixel and Android follows a “use it or waste it” policy to conserve memory. If any of you know, I’d love to know why CPU usage is higher!
The second interesting takeaway is that Flutter and React Native differ more significantly in their advantages and disadvantages than Native apps. React Native uses only slightly more memory than the Native app, while Flutter uses nearly 50% more memory than the Native app. On the other hand, the Flutter application is closer to the CPU utilization of the Native application, while the React Native application has difficulty keeping CPU utilization below 30%.
Most of all, I was surprised by how different the results were between the 5X and Pixel.
conclusion
I can confidently say that Native Android apps perform better than React Native apps or Flutter apps. However, I am not confident that React Native will perform better than Flutter or vice versa. More testing will be needed to find out if the Flutter can truly deliver better real performance than the React Native.
Matters needing attention
The above analysis is not the final result. The few tests I ran could not be used to show that React Native is faster than Flutter or vice versa. They should only be interpreted as part of the larger problem of analyzing cross-platform applications. There are a lot of things that this little application doesn’t touch that affect real-world performance and user experience. It’s worth pointing out that all three applications run smoothly in Debug and Release mode.
If you find any mistakes in your translation or other areas that need to be improved, you are welcome to the Nuggets Translation Program to revise and PR your translation, and you can also get the corresponding reward points. The permanent link to this article at the beginning of this article is the MarkDown link to this article on GitHub.
The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, front-end, back-end, blockchain, products, design, artificial intelligence and other fields. If you want to see more high-quality translation, please continue to pay attention to the Translation plan of Digging Gold, the official Weibo, Zhihu column.