使用HTML来生产Android界面
| 分类: 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界面的更多相关文章
- Android界面组件的四种启动方式
Android界面组件启动有四种方式 standard,singleTop,singleTask,singleInstance. standard:每次调用都会都会产生新的组件. singletop: ...
- android 界面设计基本知识Ⅲ
本章继续讲述在android界面设计中相关的知识点.介绍内容包括BroadcastReceiver(广播),Service(服务),Widget(小部件),WebView(网页加载控件). 1.Bro ...
- android 界面设计基本知识Ⅱ
上一章讲述了Android界面设计时,一些基本控件的使用,本章主要讲述自定义控件,Fragment和Headler线程机制. 1.自定义控件 (1)基本知识 dp.sp和dx px:像素点 ...
- 【Android源代码下载】收集整理android界面UI效果源码
在Android开发中,Android界面UI效果设计一直都是很多童鞋关注的问题,今天给大家分享下大神收集整理的多个android界面UI效果,都是源码,都是干货,贡献给各位网友! 话不多说,直接上效 ...
- 在Android界面特效中如何做出和墨迹天气及UC中左右拖动的效果
(国内知名Android开发论坛eoe开发者社区推荐:http://www.eoeandroid.com/) 在Android界面特效中如何做出和墨迹天气及UC中左右拖动的效果 相信这么多手机APP中 ...
- Android界面布局基本知识简述
Android手机操作系统在模拟器中进行相关的编写,可以帮助我们实现各种功能需求.尤其是在界面的操作方面显得更为突出.在这里我们就可以对Android界面布局的相关操作来对这方面的知识进行一个深入的了 ...
- Android界面刷新方法
Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且这些操作必须在UI线程中 ...
- android界面设计之布局管理
谈到android界面设计,各种布局样式不得不提!传统的布局方式有6种,我们会一一介绍. 在android studio2.2版本之后出现了一款超棒的布局方式,真正意义上的所见即所得,后面我们也会讲到 ...
- Android界面跳转几种情况
Android界面简单跳转, Intent intent =new Intent(MainActivity.this,SecondActivity.class); startActivity(inte ...
随机推荐
- 技术专题-PHP代码审计
作者:坏蛋链接:https://zhuanlan.zhihu.com/p/24472674来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 一.前言 php代码审计如字面 ...
- javascript的几个小技巧
1.在循环中缓存array.length 这个技巧很简单,这个在处理一个很大的数组循环时,对性能影响将是非常大的.基本上,大家都会写一个这样的同步迭代的数组. for(var i=0;i<arr ...
- 第六课——UIDynamicAnimator
今天我们要学习UIDynamicAnimator 仿真物理学 . UIKit 力学(Dynamics) 和动态效果(Motion Effects) . 创建力学基本流程: 创建运动管理 创建运动行为( ...
- WMSYS.WM_CONCAT(distinct(字段名)) 函数,字符串拼接函数。合并列
合并列函数 WMSYS.WM_CONCAT(distinct(字段名)) 函数 可以实现字符串拼接在一起,这种情况可以在要求把一个字段的多个值拼接在一起的时候使用.其中distinct可以去掉重复的值 ...
- css3实践之摩天轮式图片轮播+3D正方体+3D标签云(perspective、transform-style、perspective-origin)
本文主要通过摩天轮式图片轮播的例子来讲解与css3 3D有关的一些属性. demo预览: 摩天轮式图片轮播(貌似没兼容360 最好用chrome) 3D正方体(chrome only) 3D标签云(c ...
- Canvas之蛋疼的正方体绘制体验
事情的起因 之前写了篇谈谈文字图片粒子化 I,并且写了个简单的demo -> 粒子化.正当我在为写 谈谈文字图片粒子化II 准备demo时,突然想到能不能用正方体代替demo中的球体粒子.我不禁 ...
- Javascript将构造函数扩展为简单工厂
一般而言,在Javascript中创建对象时需要使用关键字new(按构造函数去调用),但是某些时候,开发者希望无论new关键字有没有被显式使用,构造函数都可以被正常调用,即构造函数同时还具备简单工厂的 ...
- WebService的两种方式SOAP和REST比较 (转)
我的读后感:由于第一次接触WebService,对于很多概念不太理解,尤其是看到各个OpenAPI的不同提供方式时,更加疑惑.如google map api采用了AJAX方式,通过javascript ...
- 用node.js实现简单的web服务器
node.js实现web服务器还是比较简单的,我了解node.js是从<node入门>开始的,如果你不了解node.js也可以看看! 我根据那书一步一步的练习完了,也的确大概了解了node ...
- Python【map、reduce、filter】内置函数使用说明(转载)
转自:http://www.blogjava.net/vagasnail/articles/301140.html?opt=admin 介绍下Python 中 map,reduce,和filter 内 ...
转载▼