1. 程式人生 > >Android freemarker模板引擎應用

Android freemarker模板引擎應用

什麼是freemarker?

在說這個之前我們都知道web和原生控制元件之爭就那麼點事。效能,載入速度,流量,資料互動….

如果我用webView載入一個url頁面,要先通過網路解析css,解析html程式碼,然後渲染生成頁面

什麼是freemarker?簡單點就是,事先把上面這個html檔案,放到應用中,用的時候只要傳入資料就行

freemarker優點和應用

節約流量,加快網頁載入速度

比如某些圖表功能,用js庫實現比較方便,只要事先放入html模板,傳入資料就行。大大節省了流量及載入速度

或者事先已經有網頁功能的頁面,就不需要在製作Android介面了

此功能在IOS上通用,所以只要一個模板,就可以用在IOS和Android上,大大節約開發時間

實現原理

webView載入本地模板引擎流程

main.tpl ——–> main.ftl+資料 ———> main.html ———> webView.load(main.html)

1、匯入freemarker庫

compile 'org.freemarker:freemarker-gae:2.3.25-incubating'

2、將main.tpl檔案放入assets目錄下

<!--main.tpl檔案-->
<html>
<head>
  <title>Welcome!</title>
</head>
<body>
  <h1>Welcome ${user}!</h1>
  <p>Our latest product:
</body>
</html>

3、根據main.tpl轉成main.ftl

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();
    }
}

4、將 main.ftl和資料 生成main.html檔案

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();
        }
    }
}

5、webView載入main.html

webview.post(new Runnable() {
    @Override
    public void run() {
        String templateDirRoot = getFilesDir().getAbsolutePath();
        String url = "file://" + templateDirRoot + "main.html";
        webview.loadUrl(url);
    }
});

問題注意點

1、為什麼要先把mian.tpl轉成main.ftl檔案,而不直接把mian.ftl檔案放到assets中,然後template直接載入main.ftl檔案

因為assets中的檔案無法直接讀取,所以要先把檔案放到data/data/package/….再操作

2、突然發現2016年版的freemarker無法傳遞物件。

比如在main.ftl檔案中${model.name}就無法再繼續轉成main.html,提示如下錯誤

Unresolved exception class when finding catch block: java.beans.IntrospectionException

官方說可以,但個人測試了無數遍,就是無法編譯物件傳值

如下方式可以獲取到name

//activity.java
User user = new User();
user.setName="張三"
Map map = HashMap();
map.put("name", user.getName());

//main.tpl
<html>
<body>
  ${name}
<body>
<html>

如下方式無法獲取到name

//activity.java
User user = new User();
user.setName="張三"
Map map = HashMap();
map.put("user", user);

//main.tpl
<html>
<body>
  ${user.name}
<body>
<html>

總結

最後沒發現webView頁面載入快多少,可能資料量少。畢竟要對SD卡操作。流量確實省了,也少了java和html直接的資料互動程式碼。

當然你會用這玩意後,在老闆面前就死命的推薦應用中多用html,省下一大筆時間