Android freemarker模板引擎应用

p1qc8r5t 8年前
   <p><strong>什么是freemarker?</strong></p>    <p>在说这个之前我们都知道web和原生控件之争就那么点事。性能,加载速度,流量,数据交互….</p>    <p>如果我用webView加载一个url页面,要先通过网络解析css,解析html代码,然后渲染生成页面</p>    <p>什么是freemarker?简单点就是,事先把上面这个html文件,放到应用中,用的时候只要传入数据就行</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/2fd0f0c0d092aad708f73ded58ca7330.png"></p>    <p><strong>freemarker优点和应用</strong></p>    <p>节约流量,加快网页加载速度</p>    <p>比如某些图表功能,用js库实现比较方便,只要事先放入html模板,传入数据就行。大大节省了流量及加载速度</p>    <p>或者事先已经有网页功能的页面,就不需要在制作Android界面了</p>    <p>此功能在IOS上通用,所以只要一个模板,就可以用在IOS和Android上,大大节约开发时间</p>    <p><strong>实现原理</strong></p>    <p>webView加载本地模板引擎流程</p>    <p>main.tpl ——–> main.ftl+数据 ———> main.html ———> webView.load(main.html)</p>    <p>1、导入freemarker库</p>    <pre>  <code class="language-java">compile 'org.freemarker:freemarker-gae:2.3.25-incubating'</code></pre>    <p>2、将main.tpl文件放入assets目录下</p>    <pre>  <code class="language-java"><!--main.tpl文件-->  <html>  <head>    <title>Welcome!</title>  </head>  <body>    <h1>Welcome ${user}!</h1>    <p>Our latest product:  </body>  </html></code></pre>    <p>3、根据main.tpl转成main.ftl</p>    <pre>  <code class="language-java">private void prepareTemplate() throws IOException {      //获取app目录  data/data/package/file/      String destPath = getFilesDir().getAbsolutePath();      File dir = new File(destPath);      //判断文件夹是否存在并创建      if (!dir.exists()) {          dir.mkdir();      }      //需要生成的.ftl模板文件名及路径      String tempFile = destPath + "/" + "main.ftl";      if (!(new File(tempFile).exists())) {          //获取assets中.tpl模板文件          InputStream is = getResources().getAssets().open("main.tpl");          //生成.ftl模板文件          FileOutputStream fos = new FileOutputStream(tempFile);          byte[] buffer = new byte[7168];          int count = 0;          while ((count = is.read(buffer)) > 0) {              fos.write(buffer, 0, count);          }          fos.flush();          fos.close();          is.close();      }  }</code></pre>    <p>4、将 main.ftl和数据 生成main.html文件</p>    <pre>  <code class="language-java">private void genHTML(Product object) {      String destPath = getFilesDir().getAbsolutePath();      FileWriter out = null;      //数据源      Map root = new HashMap();      root.put("user", "user"); //传入字符串      //root.put("product", object.url());     //传入对象(会报错)      try {          Configuration cfg = new Configuration(new Version(2,3,0));          cfg.setDefaultEncoding("UTF-8");            //设置报错提示          cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);          //设置报错提示          cfg.setLogTemplateExceptions(true);          out = new FileWriter(new File(destPath + "main.html"));          //设置.ftl模板文件路径          cfg.setDirectoryForTemplateLoading(new File(destPath));          //设置template加载的.ftl模板文件名称          Template temp = cfg.getTemplate("main.ftl");          //讲数据源和模板生成.html文件          temp.process(root, out);          out.flush();      } catch (MalformedTemplateNameException e) {        } catch (IOException e) {        } catch (Exception e){        }finally {          try {              if (out != null)                  out.close();          } catch (IOException e) {              e.printStackTrace();          }      }  }</code></pre>    <p>5、webView加载main.html</p>    <pre>  <code class="language-java">webview.post(new Runnable() {      @Override      public void run() {          String templateDirRoot = getFilesDir().getAbsolutePath();          String url = "file://" + templateDirRoot + "main.html";          webview.loadUrl(url);      }  });</code></pre>    <p><strong>问题注意点</strong></p>    <p>1、为什么要先把mian.tpl转成main.ftl文件,而不直接把mian.ftl文件放到assets中,然后template直接加载main.ftl文件</p>    <p>因为assets中的文件无法直接读取,所以要先把文件放到data/data/package/….再操作</p>    <p>2、突然发现2016年版的freemarker无法传递对象。</p>    <p>比如在main.ftl文件中${model.name}就无法再继续转成main.html,提示如下错误</p>    <pre>  <code class="language-java">Unresolved exception class when finding catch block: java.beans.IntrospectionException</code></pre>    <p>官方说可以,但个人测试了无数遍,就是无法编译对象传值</p>    <p>如下方式可以获取到name</p>    <pre>  <code class="language-java">//activity.java  User user = new User();  user.setName="张三"  Map map = HashMap();  map.put("name", user.getName());    //main.tpl  <html>  <body>    ${name}  <body>  <html></code></pre>    <p>如下方式无法获取到name</p>    <pre>  <code class="language-java">//activity.java  User user = new User();  user.setName="张三"  Map map = HashMap();  map.put("user", user);    //main.tpl  <html>  <body>    ${user.name}  <body>  <html></code></pre>    <p><strong>总结</strong></p>    <p>最后没发现webView页面加载快多少,可能数据量少。毕竟要对SD卡操作。流量确实省了,也少了java和html直接的数据交互代码。</p>    <p>当然你会用这玩意后,在老板面前就死命的推荐应用中多用html,省下一大笔时间</p>    <p> </p>    <p>来自:http://www.androidchina.net/6533.html</p>    <p> </p>