使用HTML来生产Android界面

(2013-03-11 17:50:39)

  分类: Android

1. HTML 开发软件界面
   因为android软件开发分工目前还没有细化,程序员往往需要负责软件界面的开发,
   虽然软件的界面图片已经由美工设计好了,但如果使用layout技术把软件做成如图片所示的界面确实很困难,而且也比较耗时。
   Android通过WebView实现了JS代码与Java代码互相通信的功能,使的android软件的界面开发也可以采用HTML网页技术,
   这样,广大网页美工可以参与进android软件的界面开发工作,从而让程序员从中解脱出来。

2. WebView

WebView 控件可以显示一张网页。
   <WebView

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:id="@+id/webView"

/>

首先要将一张由美工MM设计的精美的网页复制到项目中来,建议放在 assets 目录下,assets 目录下的资源将不会被添加到 R 文件中。
   然后在 Activity 里首先找到 WebView 控件,然后调用它的 loadUrl 方法,就可以载入一张网页,显示在界面上。
     WebView webView = (WebView) findViewById(R.id.webView);

webView.loadUrl("file:///android_asset/index.html");

注意这里用到的是文件访问协议:file:///,而我们项目中的 assets 文件夹部署到手机后,就变成了 android_asset。
        有两点注意:file:/// 是三个斜杠
                   是 asset 不是 assets

loadUrl 提供了一个很重要的重装后的方法,将在第4点说到。

3. 当然,这样一种机制太死板了,一个数据纯静态的网页,意义不大。
   Android 提供了一种与网页 JS 代码通信的机制。
   这种机制使 HTML 网页中,可以通过 JS 来访问 JAVA 对象的方法。
   这里又要用到 WebView 的另一个方法:addJavascriptInterface(Object obj, String interfaceName)

WebView 的作用就相当于 HTML 页面和 JAVA 对象的中间人,它们的所有活动都需要这个中间人来处理一下。
   例如,addJavascriptInterface 就可以将一个 JAVA 对象提供给 HTML 页面的 JS 代码来访问。
   仔细想一下,这技术也没什么稀奇的,无非就是反射的一种应用而已。被 WebView 来管理的 HTML 本身已不是传统意义的 HTML 静态网页了。
   因为,处理它的再也不是浏览器了,既然如此。HTML 的意义就仅剩下 ”一个普通文档“ 的意义了。既然如此,WebView 要怎么来解释这个文档,还不是它设计者一句话的事情。
   因此,其设计人员规定,当解释到类似 "contact.getContacts()" 的 JS 代码时,以 "contact" 作为键,找到它所对应的 JAVA 对象,再通过反射技术,调用这个对象的 getContacts() 方法。若方法有返回值,则将返回值返回到 JS 调用的地方。感觉过程甚至和 JSP 有点类似了。
   这是一种非常巧妙的思路。个人觉得,Android 可以照着这个思路,干得更彻底一点 —— 当然强烈鄙视最后变成了 "JSP"。
   contact.getContacts():中的 contact 最终之所以能作为键找到对应的 JAVA 对象,是因为在加载这张网页前。我们在程序中调用了 WebView 的 addJavascriptInterface 方法
   方法的第一个参数,就是要交给 WebView 这个中间人管理的POJO。第二个参数就是这个 JAVA 对象对外公开的名字,就是我上面说的 ”键“ 的概念。
   webView.addJavascriptInterface(new ContactsPlugin(), "contact");

于是,通过在 JS 里面使用 contact.getContacts() 就相当于执行了 : new ContactsPlugin().getContacts()

4. 在 JAVA 代码里访问 JS

方式是使用 WebView 的 loadUrl(),只不过这时候不再是 load 一张网页了,而是告诉 WebView,请帮我在你管辖下的 HTML 里找一段 JS 代码来执行。
   第一步:打开 webView 对 JavaScript 的支持(默认不支持):webView.getSettings().setJavaScriptEnabled(true);

第二步:让 webView 执行一段 JavaScript 代码 :webView.loadUrl("javascript:show('JAVA to JS')");

这句代码,将告诉 WebView,在它管辖下的 HTML 中执行这样一段 JS :show('JAVA to JS')

单把它看成一段 JS 代码,很明显,它是在调用一个方法。于是,这句代码的最终结果就是,HTML 中,我们定义的这样一个 JS 代码执行了:
     <script type="text/javascript">

function show(data) {

alert(data);

}

</script>

这个就更神奇了。
   但是只要我们转换一下思路,别把 HTML 当成以前传统的 HTML 、别把 JS 当成传统的 JS 就好。
   我个人觉得可以这样来理解,WebView 大概上讲有些类似于 WEB 服务器的概念了。只要我们将 JAVA 对象 和 所谓的HTML 交给了它管理,它会以特殊的方式来处理这两者被我们打上特殊标记的地方。最后拼凑出最终界面,显示给用户。

5. 例:
       ** 实现联系人列表显示。要求用户在启动程序之后,动态从数据库获取联系人信息,显示在界面上。
          点击联系人的电话号码,实现电话拨号。
          使用 HTML 语言来描述界面。
       ** 拷贝 index.html 到项目 assets 文件夹下
              * index.html

view plaincopy to clipboardprint?
01. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
02.                <html> 
03.                <head> 
04.                <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
05.                <title>Insert title here</title> 
06.                <mce:script type="text/javascript"><!--  
07.                       
08.                     function show(jsondata){  
09.                                    
10.                             var jsonobjs = eval_r(jsondata);  
11.                             var table = document.getElementByIdx_xx_x("personTable");  
12.                             for(var y=0; y<jsonobjs.length; y++){  
13.                                    // 添加行  
14.                                    var tr = table.insertRow(table.rows.length);  
15.                                    // 编号列  
16.                                    var td1 = tr.insertCell(0);  
17.                                    td1.innerHTML = jsonobjs[y].id;  
18.                                          // 性名列  
19.                                    var td2 = tr.insertCell(1);  
20.                                    td2.align = "center";  
21.                                    td2.innerHTML = jsonobjs[y].name;  
22.                                          // 电话列,电话号码为超链接  
23.                                    var td3 = tr.insertCell(2);  
24.                                    td3.align = "center";  
25.                                    // <a href='javascript:contactsAction.call("139999999999")>139999999999</a> 
26.                                    td3.innerHTML = "<a href="javascript:contactsAction.call(\""+ jsonobjs[y].mobile+ "\")" mce_href="javascript:contactsAction.call(\""+ jsonobjs[y].mobile+ "\")">"+ jsonobjs[y].mobile+ "</a>";  
27.                                   }  
28.                     }  
29.                  
30.// --></mce:script> 
31.               
32.                </head> 
33.                <!-- 页面加载的时候将执行下面的 JS 代码,将调用 ContactsPlugin 的 getContacts() 方法--> 
34.                <body onload="javascript:contactsAction.getContacts();"> 
35.                   <table border="0" width="100%" id="personTable" cellspacing="0"> 
36.                            <tr> 
37.                                   <td width="20%">编号</td><td width="40%" align="center">姓名</td><td align="center">电话</td> 
38.                            </tr> 
39.                   </table> 
40.                   <a href="javascript:window.location.reload()" mce_href="javascript:window.location.reload()">刷新</a> 
41.                </body> 
42.</html>

** Activity 里初始化联系人数据,并调用 HTML 中的 show 方法想表格增加行,添加联系人数据到表格显示
              * MainActivity

view plaincopy to clipboardprint?
01.public class MainActivity extends Activity {  
02.                    private final static String TAG = "HtmlUIMainActivity";  
03.                    private WebView webView;  
04.                    private ContactService contactService;  
05.                     
06.                     @Override 
07.                     public void onCreate(Bundle savedInstanceState) {  
08.                          super.onCreate(savedInstanceState);  
09.                          setContentView(R.layout.main);  
10.                          contactService = new ContactService();  
11.                          webView = (WebView) findViewById(R.id.webView);  
12.                          webView.getSettings().setJavaScriptEnabled(true);  
13.                          webView.addJavascriptInterface(new ContactsPlugin(), "contactsAction");  
14.                          webView.loadUrl("file:///android_asset/index.html");  
15.                      }  
16.                  
17.                       
24.                      private class ContactsPlugin {  
25.                              
29.                             @SuppressWarnings("unused")  
30.                         public void getContacts() {  
31.                                    List<Contact> contacts =contactService.getContacts();  
32.                                    try {  
33.                                       JSONArray array  = new JSONArray();  
34.                                       for(Contact contact : contacts) {  
35.                                              JSONObject jsonObject = new JSONObject();  
36.                                              jsonObject.put("id", contact.getId());  
37.                                              jsonObject.put("mobile", contact.getMobile());  
38.                                              jsonObject.put("name", contact.getName());  
39.                                              array.put(jsonObject);  
40.                                       }  
41.                                       String json = array.toString();  
42.                                       webView.loadUrl("javascript:show('"+ json +"')");  
43.                                 } catch (JSONException e) {  
44.                                       Log.i(TAG, e.toString());  
45.                                 }  
46.                              }  
47.                               
50.                              @SuppressWarnings("unused")  
51.                          public void call(String phoneCode) {  
52.                                    Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + phoneCode));  
53.                                    startActivity(intent);  
54.                              }  
55.                      }  
       ** 布局文件,只需要定义一个 WebView 就可以了
              * main.xml

view plaincopy to clipboardprint?
01.<?xml version="1.0" encoding="utf-8"?> 
02.<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android
03.       android:orientation="vertical" 
04.       android:layout_width="fill_parent" 
05.       android:layout_height="fill_parent" 
06.       > 
07.       <WebView   
08.         android:layout_width="fill_parent" 
09.         android:layout_height="fill_parent" 
10.         android:id="@+id/webView" 
11.        /> 
12.</LinearLayout> 
       ** 功能清单,需要声明拨号权限
              * AndroidManifest.xml

view plaincopy to clipboardprint?
01.<?xml version="1.0" encoding="utf-8"?> 
02.<manifest xmlns:android="http://schemas.android.com/apk/res/android
03.        package="wjh.android.htmlui" 
04.        android:versionCode="1" 
05.        android:versionName="1.0"> 
06.<application android:icon="@drawable/icon" android:label="@string/app_name"> 
07.            <activity android:name=".MainActivity" 
08.                 android:label="@string/app_name"> 
09.            <intent-filter> 
10.                <action android:name="android.intent.action.MAIN" /> 
11.                <category android:name="android.intent.category.LAUNCHER" /> 
12.            </intent-filter> 
13.            </activity> 
14.               
15.</application> 
16.<uses-sdk android:minSdkVersion="8" /> 
17.<uses-permission android:name="android.permission.CALL_PHONE"/> 
18.</manifest>

6. 流程
   1. 使用 HTML 来描述软件界面。

2. 当用户在界面中触发一个业务感兴趣的事件的时候,触发并执行一段特殊的 JS 代码。
   3. 这段特殊的 JS 代码可以被 WebView 解析,并最终调用 JAVA Bean 的某个方法,完成业务操作。
   4. 在 JAVA 代码中,通过 WebView 在页面执行一段 JS 代码,实现对用户操作的响应或对页面展示的数据做动态改变。

写着写着,才发现,成 AJAX 了。不禁有点兴奋。这至少比我们自己写 XML 半标记、半代码的来实现界面要好多了。无论从软件开发分工、各层之间的解耦、以及程序员的舒适度来看。

7. 缺点,界面效果貌似不如用 layout 界面 XML 文件开发的软件界面华丽。
   就目前来说,对 HTML、JS、CSS 等 web 技术支持到何种程度,还有待进一步发现和总结。
   但是我目前做的测试表明,基本上一些 W3C 标准,和一些公认的规范,WebView 都是支持的。
   至于到底两种方式谁好。一方面来说,似乎就成了桌面应用和WEB应用的争执范畴了。

使用HTML来生产Android界面的更多相关文章

  1. Android界面组件的四种启动方式

    Android界面组件启动有四种方式 standard,singleTop,singleTask,singleInstance. standard:每次调用都会都会产生新的组件. singletop: ...

  2. android 界面设计基本知识Ⅲ

    本章继续讲述在android界面设计中相关的知识点.介绍内容包括BroadcastReceiver(广播),Service(服务),Widget(小部件),WebView(网页加载控件). 1.Bro ...

  3. android 界面设计基本知识Ⅱ

    上一章讲述了Android界面设计时,一些基本控件的使用,本章主要讲述自定义控件,Fragment和Headler线程机制. 1.自定义控件 (1)基本知识 dp.sp和dx      px:像素点  ...

  4. 【Android源代码下载】收集整理android界面UI效果源码

    在Android开发中,Android界面UI效果设计一直都是很多童鞋关注的问题,今天给大家分享下大神收集整理的多个android界面UI效果,都是源码,都是干货,贡献给各位网友! 话不多说,直接上效 ...

  5. 在Android界面特效中如何做出和墨迹天气及UC中左右拖动的效果

    (国内知名Android开发论坛eoe开发者社区推荐:http://www.eoeandroid.com/) 在Android界面特效中如何做出和墨迹天气及UC中左右拖动的效果 相信这么多手机APP中 ...

  6. Android界面布局基本知识简述

    Android手机操作系统在模拟器中进行相关的编写,可以帮助我们实现各种功能需求.尤其是在界面的操作方面显得更为突出.在这里我们就可以对Android界面布局的相关操作来对这方面的知识进行一个深入的了 ...

  7. Android界面刷新方法

    Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且这些操作必须在UI线程中 ...

  8. android界面设计之布局管理

    谈到android界面设计,各种布局样式不得不提!传统的布局方式有6种,我们会一一介绍. 在android studio2.2版本之后出现了一款超棒的布局方式,真正意义上的所见即所得,后面我们也会讲到 ...

  9. Android界面跳转几种情况

    Android界面简单跳转, Intent intent =new Intent(MainActivity.this,SecondActivity.class); startActivity(inte ...

随机推荐

  1. [No000033]码农网-如何锻炼出最牛程序员的编码套路

    最近,我大量阅读了Steve Yegge的文章.其中有一篇叫"Practicing Programming"(练习编程),写成于2005年,读后令我惊讶不已: 与你所相信的恰恰相反 ...

  2. 如何在Kali Linux下编译Windows Exploit

    前言 微软的Windows在企业或是个人应用领域占据着最大的市场份额,在渗透测试过程中你会经常遇到很多Windows的工作站和服务器.另一方面,大多数渗透测试人员主要使用基于Linux的发行版渗透测试 ...

  3. NOIP1999 旅行家的预算

    题目描述 一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的).给定两个城市之间的距离D1.汽车油箱的容量C(以升为单位).每升汽油能行驶的距离D2.出发点每升汽油价格P和沿 ...

  4. java(搜索不区分大小写)

    ref.put("myfield", Pattern.compile(".*myValue.*" , Pattern.CASE_INSENSITIVE));

  5. 各种AJAX方法的使用比较

    转:http://www.cnblogs.com/fish-li/archive/2013/01/13/2858599.html#_label6 AJAX技术经过这么多年的发展,出现了一些框架或类库用 ...

  6. JavaScript String 对象

    JavaScript String 对象 String 对象 String 对象用于处理文本(字符串). String 对象创建方法: new String(). 语法 var txt = new S ...

  7. hadoop怎么读?怎么发音

    hadoop不是一个英文单词,是作者发明的词,hadoop名称来源作者小孩的一个}h毛填充黄色大象玩具. 它的发音是:[hædu:p]

  8. iOS原生项目中集成React Native

    1.本文的前提条件是,电脑上已经安装了CocoaPods,React Native相关环境. 2.使用Xcode新建一个工程.EmbedRNMeituan [图1] 3.使用CocoaPods安装Re ...

  9. PAT 1031. 查验身份证(15)

    一个合法的身份证号码由17位地区.日期编号和顺序编号加1位校验码组成.校验码的计算规则如下: 首先对前17位数字加权求和,权重分配为:{7,9,10,5,8,4,2,1,6,3,7,9,10,5,8, ...

  10. Python __init__.py 作用详解

    __init__.py 文件的作用是将文件夹变为一个Python模块,Python 中的每个模块的包中,都有__init__.py 文件. 通常__init__.py 文件为空,但是我们还可以为它增加 ...