Android平台下使用HTML5绘制离线图表

来源:互联网 发布:新时空软件 编辑:程序博客网 时间:2024/05/20 17:24

Android平台下使用HTML5绘制离线图表

一,Web app与Native app的结合

  说到HTML5在移动领域的开发,最出色的就是跨平台与低门槛,但是HTML5目前功能有限,达不到Native App所能获得的那种出色的用户体验,而传统的Native开发方法在性能和设备访问方面很出色,但在开发成本和更新方面有却又不足。兼顾上述两方面的考虑,在越来越多的项目中我们可以看到Hybrid App这样一种混合式编程的开发方式。
  Android平台下与HTML5进行交互的方式是使用native api创建一个WebView控件作为载体进行UI展示,使用JavaScript作为桥梁与HTML5页面进行交互。App的Web部分可能是驻留在服务器上的网页,但也可能是一组HTML、JavaScript、CSS和媒体文件,封装到App代码中,存储在设备本地。这两种方法都有其优势和局限性。放置在服务器上的HTML代码让开发者不必经历提交和批准过程——有些App商店要求这个过程,就可以对App进行小幅更新。遗憾的是,这个方法摈弃了任何离线可用性,因为设备与网络没有连接时,无法访问设备。另一种方法,把Web代码封装到App里面可以获得高性能的加载速度和离线访问能力,但是不允许远程更新。从绘制图表的需求上来看,后者更加符合我们的现在的业务场景。

二,使用HTML5绘制图表

  关于绘制图表,在HTML5里有许多技术成熟的JS库可以适用于不同需求场景,在这里我使用echart的JS库来进行代码演示:

<!DOCTYPE html><html lang="zh-cn"><head>    <meta charset="utf-8" />    <!-- Always force latest IE rendering engine (even in intranet) & Chrome Frame    Remove this if you use the .htaccess -->    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />    <title>ss</title>    <meta name="description" content="" />    <meta name="author" content="peng" />    <meta name="viewport" content="width=device-width; initial-scale=1.0" />    <!-- Replace favicon.ico & apple-touch-icon.png in the root of your domain and delete these references -->    <link rel="shortcut icon" href="/favicon.ico" />    <link rel="apple-touch-icon" href="/apple-touch-icon.png" /></head><body data-modules="analysis" data-sub="analysis-user">//设置图表高度,在这里可以做屏幕适配<div id="age-chart" style="width:100%;height:150px;"></div><script src="echarts.js"></script><script >window.Android.initPlugin();function showChart(dataArray){        var age_chart_container = echarts.init(document.getElementById('age-chart'));        // 指定图表的配置项和数据        var option = {                    grid:{                        top:10,                        bottom:15,                        right:0,                        left:25                        },//在这里填写传进来的dataArray数组            series: [{                name: '销量',                type: 'bar',                data: [ {                value:dataArray[0],                itemStyle:{                  normal:{color:'#4bd2c4'}              }              }            .....            {                value:dataArray[7],                itemStyle:{                  normal:{color:'#4bd2c4'}              }              }]            }]        };        age_chart_container.setOption(option);}        </script></body></html>

  在上面的代码中可以看到,我们定义的了一个方法叫 showChart(dataArray) ,这个方法需要android客户端主动传参进去,在上面的代码中我把传递的name参数作为X轴的下标进行赋值,而在实际项目中我们一般传入的是一个json字符串,由JavaScript来进行数据解析和处理工作。
  在初始化echart组件时,我们最后调用了 window.Android.initPlugin();这段代码进行初始化回调。这是因为我们的echart组件初始化是异步完成的,当echart的组件初始化完成后,我们通知android客户端调用showChart方法来绘制图表信息,整个流程是这样滴:

Created with Raphaël 2.1.0HTML5HTML5AndroidAndroid初始化完成,initPlugin()Android收到JS的回调showChart(json),传绘制参数HTML5解析json对象myCharts.setOption(option)绘制图表

需要注意的是,我使用的是在线JS库所以受到网络加载速度的影响,实际项目中我们使用离线包提高加载性能。

三,Android客户端内嵌H5

  大部分的Hybrid App使用的是页面替换的形式来进行混合式开发,在这里我们使用内嵌的方式来进行开发,原因是因为我们的项目已经使用native api进行开发了一段时间了,如果整个页面替换成html5会产生额外的维护成本。
  我们现在使用的内嵌方式,只是把以前的自定义绘图控件给替换掉,大小形式不变,整个页面的其他组件还是使用原生代码进行开发维护。布局文件如下:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="#987f62"    tools:context="com.example.administrator.myapplication2.MainActivity">    <WebView        android:id="@+id/web"        android:layout_width="wrap_content"        android:layout_height="wrap_content"></WebView></RelativeLayout>

没错就是这么简单!你只需要高度设置成wrap_content就行了,然而最后的显示高度取决于html5页面的style="width:100%;height:200px这段代码,所以如果你的页面展示效果不理想请找水平老司机…..

说完页面布局,现在让我们来看看Android客户端的交互逻辑代码:

   @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mWebView= (WebView) findViewById(R.id.web);                WebSettings settings = mWebView.getSettings();        settings.setJavaScriptEnabled(true);    //启用JS脚本        settings.setAllowFileAccess(true);        settings.setDomStorageEnabled(true);    //允许DCOM        mWebView.setWebViewClient(new WebViewClient() {            //当点击链接时,希望覆盖而不是打开新窗口            @Override            public boolean shouldOverrideUrlLoading(WebView view, String url) {                view.loadUrl(url);  //加载新的url                return true;    //返回true,代表事件已处理,事件流到此终止            }        });        mWebView.loadUrl("file:///android_asset/ps.html");            mWebView.addJavascriptInterface(new JavaScriptObject(this), "Android");//注册JavaScript接口    }    //  注册JS接口类    public class JavaScriptObject {        Context mContxt;        public JavaScriptObject(Context mContxt) {            this.mContxt = mContxt;        }        @JavascriptInterface        public void initPlugin(){           runOnUiThread(new Runnable() {               @Override               public void run() {                   loadJs();               }           });        }    } /**  * @author ZhongR  * @date 2016/7/5 16:10  * @description 传递参数来绘制图表  */    public void loadJs(){      mWebView.loadUrl("javascript:showChart([100,200,0,0,500,50,20,300])");    }

从上面的代码可以看到,Android客户端如果需要和Html5页面交互,注册JavaScript方法是必不可少的一步,在我们注册的initPlugin()方法中,我们调用了绘图方法,并且传参进去:mWebView.loadUrl("javascript:showChart([100,200,0,0,500,50,20,300])");细心的读者可以发现在这里我们使用的是UI线程调用loadJs()方法,这是因为WebKit所执行的线程是独立于android主线程之外的,所以JavaScript的方法回调也会在Android异步线程被执行。

四,小结

  HTML5技术与移动APP相结合的玩法还有很多种,今天的介绍是为了在不修改源代码的前提下,解决我们当前绘图需求而提出的一种解决方案。更多的时候我们会用到Html5页面的动态更新,离线缓存等特性来组合我们的APP。下面总结几点需要注意的地方:

  • Html5页面在内嵌android布局里面的时候,显示高度大小取决与Style-height里面设置的px值,android端不能指定高度。
  • Html5页面中的Js库加载完成后进行初始化echart是一个耗时操作,我们可以选择采用回调的方式通知客户端。
  • Android客户端中注册的JS方法一定是运行在非UI线程的,所以我们要避免一些主线程操作。
  • Android在API17版本上修复了JavaScript注入漏洞,为了兼容性考虑在注册Js方法的时候我们要加上注释@JavascriptInterface来保证安全性。
  • Html5页面可以将异常状态抛给android客户端,但是至少需要有一个默认可显示的图表。

  Demo下载地址:html5绘图demo

1 0