We are building an Android app and want to render charts. Charts are diagrammatic representations of numeric data, which include bar and pie charts. We found two methods for rendering charts: native Android and JavaScript hosted in WebView. The native Android method requires Java packaged jar libraries such as AChartEngine and AndroidPlot. The WebView method uses HTML 5, CSS3, and JavaScript such as Chart.js and Flot.js. We took the WebView method because of simplicity and to reduce development time. The remainder of this article will focus on the WebView method.
Android OS Version
Due to many Android operating system (OS) versions, we have to choose which OSes to support. In each revision of the OS, UI components such as WebView behave differently. WebView in Android 4.4 (KitKat, API 19) is based on Chromium, which supports standard HTML 5 and CSS31,2. Previous Android versions (API 18 or lower) will operate in quirks mode with non-standard web features2.
Focusing on displaying charts locally on the device requires allowing WebView to access files from the URL. This is only required on Android 4.3 (Jelly Bean, API 18) or higher:
1
2
3
4
|
if(Build.VERSION.SKD_INT >= Build.VERSION_CODES.JELLY_BEAN){
webView.getSettings().setAllowUniversalAccessFromFileURLs(true);
webView.getSettings().setAllowFileAccessFromFileURLs(true);
}
|
We also noted that older OSes below Android 3.0 (Honeycomb, API 11) have a non-conformant WebView to standard web standards. For example, the performance is subpar. In order to compensate for these behavioural differences,we decided to disable the chart feature for these older OSes.
Project Setup for WebView
Like all Android applications, we create an XML layout file for the UI and set the necessary permissions in the app manifest.
Setting up the Android layout is straightforward:
1
2
3
4
5
6
|
<?xml version= "1.0" encoding= "utf-8">
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
|
Note: There is no need to include <uses-permission android:name="android.permission.INTERNET" />
in the AndroidManifest.xml
because we are loading HTML files locally, which does not require Internet access.
Loading a WebView Chart
Next, we’ll add the HTML to load in the proper directory and configure the WebView control. We’ll also have to change the HTML slightly for showing in a mobile web browser.
To load files from the URL requires placing files in <project dir>/src/assets/
and then loading HTML:
1
2
|
String webHtml = …;
webView.loadDataWithBaseURL("file:///android_asset", webHtml, "text/html", "UTF-8", null);
|
Displaying charts in WebView requires JavaScript:
1 |
webView.getSettings().setJavaScriptEnabled(true);
|
To make sure that the chart is displayed properly, include the following in the HTML:
1 |
<meta name = "viewport" content = "width=device-width, initial-scale=1.0, user-scalable=no">
|
Interacting with the WebView
For our application, the charts are not interactive. We disable touch events on the HTML page. By disabling touch events, we do not have to deal with unnecessary zooming, scrolling, and text selection:
1
2
3
4
5
6
|
webView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
|
WebView Lifecycle
We ran into a problem when leaving the activity. WebView will display the following message in logcat3:
EventHub.removeMessages(int what = 107) is not supported before WebViewCore is set upTo prevent this message from showing up use WebView stopLoading() method:
1
2
3
4
5
6
7
8
|
@Override
public void onStop() {
try{
webView.stopLoading();
}catch(Exception e){
e.printStackTrace();
}
}
|
Web Chart Libraries
Now that we are able to load a WebView to display HTML, several alternative libraries for rendering JavaScript charts are available. We tried two JavaScript libraries, Chart.js and Flot.js.
We selected Chart.js to display the bar and pie charts. This chart package is easy and simple to use. It does not require jQuery. We loaded the chart package in our own chart using the following HTML:
1
2
3
4
5
|
<head>
...
<script type = "text/javascript" src="file:///android_asset/Chart.js"> </script>
...
</head>
|
Chart.js does not provide axis titles or a legend in the bar chart. For the pie chart, it does not provide the option to label the pie chart sections. However, a forked version of Chart.js adds these features.
An example using the pie chart with the forked Chart.js:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<body>
...
<script type="text/javascript">
...
var pieChartData = [{value: 0, color:"#B163A3", label: "A", labelColor: "black"},{value: 0, color:"#009874", label: "B", labelColor: "black"},
{value: 0, color:"#DD4124", label: "C", labelColor: "black"}];
var canvasEl = document.getElementById("canvas");
var ctx = canvasEl.getContext("2d");
...
var options = { animation: false };
var myPie = new Chart(ctx).Pie(pieChartData, options);
}...
</script>
</body>
|
Flot.js provides customization through plugins. It requires jQuery, which is included in the package or can be downloaded directly from the JQuery website. Load the script just before the end of the HTML:
1
2
3
4
5
6
7
8
9
|
<body>
...
<script type="text/javascript" src="file:///android_asset/flot-0.9-work/lib/jquery.js"></script>
<script type="text/javascript" src="file:///android_asset/flot-0.9-work/lib/jquery.colorhelpers.js"></script>
<script type="text/javascript" src="file:///android_asset/flot-0.9-work/jquery.flot.js"></script><script type="text/javascript" src="file:///android_asset/flot-0.9-work/jquery.flot.categories.js"></script>
<script type="text/javascript" src="file:///android_asset/flot-0.9-work/jquery.flot.tickrotor.js"></script>
<script type="text/javascript" src="file:///android_asset/flot-0.9-work/jquery.flot.axislabels.js"></script>
...
</body>
|
jquery.colorhelpers.js
: makes it easier to add color to the chartjquery.flot.js
: the chart scriptjquery.flot.categories.js
: allows plotting text or categories with the datajquery.flot.tickrotor.js
: allows rotation of the x- and/ or y-axis tick labels4jquery.flot.axislabels.js
: display x- and y-axis labels5The following shows how to use the plugins, this is placed after loading the .js files:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<body>
...
<script type="text/javascript">
$(function() {
var data = [ [0,0.0],[1,0.0],[2,0.0],[3,0.0],[4,0.0],[5,0.0],[6,0.0] ];
var options = {
xaxes: [ { ticks:[ [0,"A"],[1,"B"],[2,"C"],[3,"D"],[4,"E"],[5,"F"],[6,"G"] ],rotateTicks: 90 } ],
series: { bars: { show: true, barWidth: 0.6, align: "center" } },
xaxis: { mode: "categories", tickLength: 0, axisLabel: "Name", position: 'bottom', color: '#009874'},
yaxis: { axisLabel: "Total", position: 'left', color: '#B163A3' } };
$.plot("#placeholder", [ data ], options);
});
</script>
</body>
|
Concluding Remarks
The WebView approach is effective for displaying charts. Our method, however, only works for displaying non-interactive charts with low development time. Interactive WebViews may encounter the same performance issues as the PhoneGap approach6,7 such as include lack of responsiveness and non-native appearance. Since we do not require user interactivity, the WebView approach enables us to render charts using well-developed JavaScript libraries instead of platform-specific Android libraries.
1 Google Developers: “WebView for Android”
2 Android.com: “Migrating to WebView in Android 4.4”
3 Stack Overflow: “Android : EventHub.removeMessages(int what = 107) is not supported before the WebViewCore is set up”
4 GitHub Mark Côté: flot-tickrotor
5 GitHub Mark Côté: flot-axislabels
6 Andrew Trice: “Performance & UX Considerations For Successful PhoneGap Apps”
7 Greg Avola: “Creating apps with PhoneGap: Lessons learned”