[转]使用HTML来生产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 > 
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应用的争执范畴了。

时间: 2024-10-06 04:30:13

[转]使用HTML来生产Android界面的相关文章

使用HTML来生产Android界面

使用HTML来生产Android界面 (2013-03-11 17:50:39) 转载▼   分类: Android 1. HTML 开发软件界面   因为android软件开发分工目前还没有细化,程序员往往需要负责软件界面的开发,   虽然软件的界面图片已经由美工设计好了,但如果使用layout技术把软件做成如图片所示的界面确实很困难,而且也比较耗时.   Android通过WebView实现了JS代码与Java代码互相通信的功能,使的android软件的界面开发也可以采用HTML网页技术, 

[转] 基于XMPP协议的Android即时通信系

转自:http://blog.csdn.net/lnb333666/article/details/7471292 以前做过一个基于XMPP协议的聊天社交软件,总结了一下.发出来. 设计基于开源的XMPP即时通信协议,采用C/S体系结构,通过GPRS无线网络用TCP协议连接到服务器,以架设开源的Openfn'e服务器作为即时通讯平台. 系统主要由以下部分组成:一是服务器,负责管理发出的连接或者与其他实体的会话,接收或转发XML(ExtensibleMarkup Language)流元素给授权的客

[Android Studio 权威教程]配置出“NB”的Android Studio

前几篇博客我们已经安装好了As,并且创建了我们的第一个HelloWrod ,这片blog我们继续配置出一个NB的Android Studio 假设你是一个才開始接触到AS或者想从Eclipse转型到AS的童鞋,那么请你持续关注我左边的专栏[Android Studio 权威教程],好的.開始我们的教程. 1.配置IDE主题 默认的主题是一个灰白色.看这特别的不好看.并且对于我们程序开发人员来讲每天要对着电脑好几个小时.特别的伤眼睛.我们来配置一个高大上的暗黑主题. 点击这个设置的小图标 这里Th

iOS第三方库汇总[转载]

iOS第三方库汇总[转载] 字数2179 阅读334 评论0 喜欢29 简介 此文用于总结,本人使用过或者收藏过的Github第三方类库,以便日后查阅,也便他人借鉴. 资料整理中不定期更新... 开源项目 CodeHub browse and maintain your GitHub repositories on any iOS device! Open-Source iOS Apps 开源iOS apps列表 APP相关 iVersion 提示版本更新 BonMot 字体相关的库,设置字体样

[转]Lua语言基础汇总(7) -- 协同程序

前言 协同程序与线程差不多,也就是一条执行序列,拥有自己独立的栈.局部变量和指令指针,同时又与其它协同程序共享全局变量和其它大部分东西.从概念上讲,线程与协同程序的主要区别在于,一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行.就是说,一个具有多个协同程序的程序在任意时刻只能运行一个协同程序,并且正在运行的协同程序只会在其显式地要求挂起时,它的执行才会暂停. 协同程序基础 Lua将所有关于协同程序的函数放置在一个名为“coroutine”的table中.函数create

[翻译]The Neophyte&#39;s Guide to Scala Part 12: Type Classes

The Neophyte's Guide to Scala Part 12: Type Classes 过去的两周我们讨论了一些使我们保持DRY和灵活性的函数式编程技术,特别是函数组合,partial function的应用,以及currying.接下来,我将会继续讨论如何使你的代码尽可能的灵活. 但是,这次我们将不会讨论怎么使用函数作为一等对象来达到这个目的,而是使用类型系统,这次它不是阻碍着我们,而是使得我们的代码更灵活:你将会学到关于 type classes 的知识. 你可能会觉得这是一

[转]useradd 与adduser的区别

转自:Deit_Aaron的专栏 添加用户:useradd -m 用户名  然后设置密码  passwd 用户名 删除用户:userdel  -r  用户名 1. 在root权限下,useradd只是创建了一个用户名,如 (useradd  +用户名 ),它并没有在/home目录下创建同名文件夹,也没有创建密码,因此利用这个用户登录系统,是登录不了的,为了避免这样的情况出现,可以用 (useradd -m +用户名)的方式创建,它会在/home目录下创建同名文件夹,然后利用( passwd +

[转]iOS应用程序生命周期(前后台切换,应用的各种状态)详解

转载地址:http://blog.csdn.net/totogo2010/article/details/8048652 iOS的应用程序的生命周期,还有程序是运行在前台还是后台,应用程序各个状态的变换,这些对于开发者来说都是很重要的. iOS系统的资源是有限的,应用程序在前台和在后台的状态是不一样的.在后台时,程序会受到系统的很多限制,这样可以提高电池的使用和用户体验. //开发app,我们要遵循apple公司的一些指导原则,原则如下: 1.应用程序的状态 状态如下: Not running

[转]关于NSAutoreleasePool&#39; is unavailable: not available in automatic reference counting mode的解决方法

转载地址:http://blog.csdn.net/xbl1986/article/details/7216668 Xcode是Version 4.2 Build 4D151a 根据Objective-c 2.0程序设计上的旧版本的代码会发生NSAutoreleasePool' is unavailable: not available in automatic reference counting mode的错误 需要手动关闭工程中ARC 工程中 Build Settings--->Apple