使用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. [No00000F]Excel快捷键大全 Excel2013/2010/2007/2003常用快捷键大全

    一个软件最大的用处是提高工作效率,衡量一个软件的好坏,除了是否出名之外,最主就是能否让一个新手更快的学会这个软件和提高工作速度.就拿Excel表格来说吧,平常办公中我们经常会用它来制作表格,统计数据或 ...

  2. 十种MySQL报错注入

    1.floor() select * from test where id=1 and (select 1 from (select count(*),concat(user(),floor(rand ...

  3. 浅谈Android Fragment嵌套使用存在的一些BUG以及解决方法

    时间 2014-03-18 18:00:55 eoe博客 原文  http://my.eoe.cn/916054/archive/24053.html 主题 安卓开发 自从Android3.0引入了F ...

  4. 布局 - panel

    panel一般作为其他组件的容器使用 很多组件都继承自panel 对于面板中的内容,支持异步从后台加载,当然,作为纯粹的面板,一般不会用到这个,但他的子类对于这个功能还是蛮实用的 <%@ tag ...

  5. WPF 4.0 DatePicker 快速录入

    WPF 4.0的DatePicker在通过键盘录入日期的时候是非常让人郁闷的.必须按照日期的格式来完整输入例如,比如输入“2010/10/10”才能识别.而实际上在一些要求快速录入的场合,用户更希望直 ...

  6. [转]向facebook学习,通过协程实现mysql查询的异步化

    FROM : 通过协程实现mysql查询的异步化 前言 最近学习了赵海平的演讲,了解到facebook的mysql查询可以进行异步化,从而提高性能.由于facebook实现的比较早,他们不得不对php ...

  7. Java 基础命名空间

    java.lang (提供利用 Java 编程语言进行程序设计的基础类)java.lang.annotation(提供了引用对象类,支持在某种程度上与垃圾回收器之间的交互)java.lang.inst ...

  8. WPF 小技巧

    在使用mvvm模式开发时,对于Command的绑定是一件很伤脑筋的事情,尽管有强大的Blend类库支持: xmlns:Custom="http://www.galasoft.ch/mvvml ...

  9. bootstrap的popover插件在focus模式时在Safari浏览器无法使用的bug解决方案

    前言 最近在使用bootstrap的popover插件,效果如下: popover插件的focus模式时表现为当点击按钮时弹出浮动层,在点击浮动层外的任何一处,都隐藏浮动层. 但是在mac下的Safa ...

  10. Redis的五种数据结构

    Redis支持持久化只是它的一件武器,它提供了多达5种数据存储方式: 一  string(字符串) string是最简单的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个val ...