[转载]android UI进阶之布局的优化

mikel阅读(892)

[转载]android UI进阶之布局的优化 – noTice520 – 博客园.

欢迎转载,但是请保留出处。http://www.cnblogs.com/noTice520/

好久没更新博客了,趁着清明来写点什么。

今天来讲下如何使用Android中提供的工具优化我们的布局。首先我们写一个最简单的框架布局。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="300dip"
android:layout_height="300dip"
android:background="#00008B"
android:layout_gravity="center"
/>
<TextView
android:layout_width="250dip"
android:layout_height="250dip"
android:background="#0000CD"
android:layout_gravity="center"
/>
<TextView
android:layout_width="200dip"
android:layout_height="200dip"
android:background="#0000FF"
android:layout_gravity="center"
/>
<TextView
android:layout_width="150dip"
android:layout_height="150dip"
android:background="#00BFFF"
android:layout_gravity="center"
/>
<TextView
android:layout_width="100dip"
android:layout_height="100dip"
android:background="#00CED1"
android:layout_gravity="center"
/>
</FrameLayout>


非常简单的一个布局,实现一个层叠的效果,运行效果如下图:

下面我们就用Android中提供的一个观察布局的工具,层级观察器,Hierarchy Viewer来观察我们的布局。Hierarchy Viewer工具是一个非常好的布局优化工具,同时,你也可以通过它学习他人的布局。应该说是一个非常实用的工具。

   Hierarchy Viewer在sdk的tools目录下,打开后最新界面如图所示:

  界面很简洁,列出了当前设备上的进程,在前台的进程加粗显示。上面有三个选项,分别是刷新进程列表,将层次结构载入到树形图,截取屏幕到一个拥有像素栅格的放大镜中。对应的在左下角可以进行三个视图的切换。在模拟器上打开写好的框架布局,在页面上选择,点击Load View,进入如图所示界面。

  左边的大图为应用布局的树形结构,上面写有控件名称和id等信息,下方的圆形表示这个节点的渲染速度,从左至右分别为测量大小,布局和绘制。绿色最快,红色最慢。右下角的数字为子节点在父节点中的索引,如果没有子节点则为0。点击可以查看对应控件预览图、该节点的子节点数(为6则有5个子节点)以及具体渲染时间。双击可以打开控件图。右侧是树形结构的预览、控件属性和应用界面的结构预览。点击相应的树形图中的控件可以在右侧看到他在布局中的位置和属性。工具栏有一系列的工具,保存为png或者psd,刷新等工具。其中有个load overlay选项可以加入新的图层。当你需要在你的布局中放上一个bitmap,你会用到它来帮你布局。点击左下角的第三个图标切换到像素视图,如下图所示。

  视图左侧为View和ViewGroup关系图,点击其中的View会在右边的图像中用红色线条为我们选中相应的View。最右侧为设备上的原图。中间为放大后带像素栅格的图像,可以在Zoom栏调整放大倍数。在这里能定位控件的坐标,颜色。观察布局就更加的方便了。

接下来再介绍下另一个布局优化工具-layoutopt。这是android为我们提供的布局分析工具。它能分析指定的布局,然后提出优化建议。  

  要运行它,打开命令行进入sdk的tools目录,输入layoutopt加上你的布局目录命令行。运行后如图所示,框出的部分即为该工具分析布局后提出的建议,这里为建议替换标签。

下面列出一些常会碰到的输出:

$ layoutopt samples/
samples/compound.xml
7:23 The root-level can be replaced with
11:21 This LinearLayout layout or its FrameLayout parent is useless
samples/simple.xml 提示未使用到该布局
7:7 The root-level can be replaced with
samples/too_deep.xml
-1:-1 This layout has too many nested layouts: 13 levels, it should have <= 10! 20:81 This LinearLayout layout or its LinearLayout parent is useless 24:79 This LinearLayout layout or its LinearLayout parent is useless 28:77 This LinearLayout layout or its LinearLayout parent is useless 32:75 This LinearLayout layout or its LinearLayout parent is useless 36:73 This LinearLayout layout or its LinearLayout parent is useless 40:71 This LinearLayout layout or its LinearLayout parent is useless 44:69 This LinearLayout layout or its LinearLayout parent is useless 48:67 This LinearLayout layout or its LinearLayout parent is useless 52:65 This LinearLayout layout or its LinearLayout parent is useless 56:63 This LinearLayout layout or its LinearLayout parent is useless samples/too_many.xml 7:413 The root-level can be replaced with
-1:-1 This layout has too many views: 81 views, it should have <= 80! samples/useless.xml 提示该布局中有太多的控件 7:19 The root-level can be replaced with
11:17 This LinearLayout layout or its FrameLayout parent is useless

通过这个工具,能很好的优化我们的UI设计,布局方法。好了,今天就写到这里了。希望对大家有帮助,有问题可以留言交流~这里说下有的网站转载了我的文章,我很开心。但是都不留个出处,那就不太好了。所以欢迎转载,但是请保留出处。http://www.cnblogs.com/noTice520/

[转载]Android的RatingBar的自定义效果

mikel阅读(925)

[转载]RatingBar的自定义效果 – 没有代码 – 博客园.

首先看看效果:

有时候Android系统提供给我们的ratingbar效果并不达到我们的要求,这个时候就可以自定义自己喜欢的ratingbar。

从上面的效果可以看出,自定义这样的组件,需要两张图片: 。一张用来未选择的效果,一张用来显示的效果。那还要中间那种一半是未选择一半时选择的呢?其实当你写好这样的组件后,系统就会自动帮你自动解析生成那种效果。

整个项目布局:

我们一步一步来分析:

<RatingBar

style=“@style/roomRatingBar”

Android:layout_marginLeft=“10dip”

android:layout_width=“wrap_content” android:layout_height=“wrap_content”

android:id=“@+id/room_ratingbar”></RatingBar>

从上面可看出自定义ratingbar主要是这段style=“@style/roomRatingBar” ,好我们去找到这段代码

/////////styles.xml

<?xml version=“1.0” encoding=“utf-8”?>

<resources>

<style name=“roomRatingBar” parent=“@android:style/Widget.RatingBar”>

<item name=“android:progressDrawable”>@drawable/room_rating_bar</item>

<item name=“android:minHeight”>16dip</item>

<item name=“android:maxHeight”>16dip</item>

</style>

</resources>

上面的意思是继承@android:style/Widget.RatingBar,重写android:progressDrawable属性,换成我们自定义@drawable/room_rating_bar文件。

控制该组件的最大和最小高度。好我们继续去找这自定义文件@drawable/room_rating_bar。

///// room_rating_bar.xml

<?xml version=“1.0” encoding=“utf-8”?>

<!–

This is the rating bar drawable that is used to show a room num.

–>

<layer-list xmlns:android=“http://schemas.android.com/apk/res/android”>

<item android:id=“@+android:id/background”

android:drawable=“@drawable/room_unselect”></item>

<item android:id=“@+android:id/secondaryProgress”

android:drawable=“@drawable/room_unselect”></item>

<item android:id=“@+android:id/progress”

android:drawable=“@drawable/room_select”></item>

</layer-list>

好了,越来越接近真相了。这里就是定义组件的背景图片、一级进度背景图片和二级进度背景图片(里面这些id都是系统的id,当系统运行到这里时会自动根据这个id去重画组件)

讲到这里大概明白怎么用了。其实很多组件都可以通过这样的方法来使用,但如果明白整个过程,那以后做起其他来都至少有一点得心应手的感觉吧。好!下来我也只能说说我的见解,因为本人对android的理解也不是很深入。

前提是下载android的源码,这里我就不讲了。在android framework\base\core\res\res\values(android framework是我保存源码的目录)目录下找到styles.xml文件,该文件是android系统运行时所要加载的文件,里面保存了所有组件的样 式定义。在里面你可以找到<style name=”Widget.RatingBar”>我们之前继承的其中一个组件样式,也有其他<style name=”Widget.RatingBar.Small”>、<style name=”Widget.SeekBar”>、<style name=”Widget.ProgressBar.Small”>等等。这样里面的属性我们继承后就可以被重写成其他的了。

项目:

http://files.cnblogs.com/not-code/testRatingBar.zip

[转载]Linux(centos)下Android环境的配置.

mikel阅读(1096)

[转载]Linux(centos)下Android环境的配置. – wilsonChan – 博客园.

Linux 下搭建Android环境 这几天在弄Linux,看到最近很火的Android,就尝试着在Linux上搭建一个Android的环境。

一直使用的是Centos就使用这个来作为开发的环境。

第一次配置大概弄了一整天,出现了很多的问题,同时也有解决问题的方法,可以作为参考,作为一个新手,如果有什么纰漏,还请各位大神指点。

-:安装JDK

没有使用Centos自带的JDK,选择重新安装,下载了最新版本的JAVA.

点击DownLoad选择Platform中的Linux,然后Continue。

选择需要的安装包,我选择的是“jdk-6u21-linux-i586-rpm.bin”

下载完成后添加权限

1 #chmod +x jdk-6u21-linux-i586-rpm.bin 2 然后执行 3 #./jdk-6u1-linux-i586-rpm.bin

如果过程中可能出现一些选择,直接yes

安装完成后查看当前系统jdk版本

1 #java -version

JDK安装完成后,进行IDE安装,我选用的是eclipse.

二.安装eclipse

这里使用的是Eclipse Classic 3.6.2.下载地址

同时在root文件夹中创建了Android文件夹,相关的IDE和sdk都保存在此。

Eclipse是绿色版,解压就可以用,解压完成,打开Eclipse设置workspace.

三.安装ADT(这一步很容易出问题)

我安装的是版本ADT-10.0.1.zip Android开发工具。
1. 启动 Eclipse, 然后进入 Help > Install New Software.
2. 在 Available Software 对话框里,点击 Add….
3. 出现 Add Site 对话框,在 Name 域里面输入一个名字 (如, “Android”) ,在 “Location” 域里面输入 https://dl-ssl.google.com/android/eclipse/
4. 注意:如果有问题,可以把 https 换成 http 试一下。点击 OK.
5. 回到 Available Software 界面,你应该看到 “Developer Tools” 。选取 checkbox 。点击 Next,  然后点击 Finish.进行安装。
6. 重起 Eclipse.

注意:

如果在下载这一步出问题的朋友,可以使用离线安装,下载ADT的文件,下载地址:http://dl.google.com/android/ADT-10.0.1.zip

解压到我们创建的Android工具文件夹中,然后用同样的方法定位。参看步骤3。

如果在安装插件的过程中,出现无法安装的问题,请安装 Google Plugin for Eclipse 3.6。

安装方法很简单,帮上面Location地址改成 http://dl.google.com/eclipse/plugin/3.6

详细安装方法请见.http://code.google.com/intl/zh-CN/eclipse/docs/install-eclipse-3.6.html

四.下载SDK.
for Linux版本. http://dl-ssl.google.com/android/repository/android-2.2_r01-linux.zip
需要知道的是这个 zip 包并不是一个完整的软件包。Android 软件包采用“组件”的形式,用户可以根据需要选取组件。

上述zip文件只包含了一个组件管理工具和一个基本的工具组件。

下载完成后解压到我们的Andoid文件夹中。

五.配置SDK.

1. 选取 Eclipse Window > Preferences…
2. 选择 Android
3. 点击 Browse… 定位 Android SDK 目录。例如我的目录:/home/Android/android-sdk-linux_86
4. 点击 Apply, 然后 OK.(会提示出错,肯定会出错..因为sdk的跟新还没有下载。)

六.跟新SDK

1.运行 Eclipse, 选取 Window > Android SDK and AVD Manager.
2.在左侧面板选择 Installed Packages
3.点击 Update All.
出现 Choose Packages to Install 对话,选择Accept All,点击Install
大概2GB的容量。想全部下载,睡个午觉或者干点别的什么吧(也可以选择自己需要的进行下载)。

下载完后.重启Eclipse,就可以信件Android Project.

注意:一般情况这个时候信件一个Project选择好模拟器就可以编译了..如果在编译中出现 找不到glibc2.7的错误

请看以下链接http://blog.sina.com.cn/s/blog_64a2c65a0100hl98.html 升级2.7.

最后编译成功.附上几张测试效果图

分类: else

[转载]电子商务网站搜索架构方案

mikel阅读(1086)

[转载]电子商务网站搜索架构方案 – 叶鹏 – 博客园.

说是电子商务搜索架构方案,其实就是lucene.net的应用,公司庙小,人少,也就自己平时看看,以前做过一点例子,这样就被拉上去写架构方案了。 我这个懒惰的家伙,在网上疯狂的搜集搜索架构方面的东西,因为做做架构,暂时没写代码,每天就看人家博客,结果两个星期了才弄了个大概的草图,这不清明节 过后就要详细方案了,现在只能把我的草图分享一下,希望大家板砖伺候,闷在家里鼓捣比较郁闷啊,效率太低。

基于lucene的搜索方案

一、            Lucene 简介

Lucene是apache的一个顶级开源项目,由java实现的全文检索引擎,能基于各种文档格式的全文索引和检索,包括word、pdf,不包括图形类。

Lucene.net 是C#版的lucene 是由java的lucene翻译过来的,也被apache列为开源项目对外发布,功能和java的基本一样,但是由于缺乏良好的技术支持和社区活跃度,目前已被apache放入孵化器

Lucene写入:源文件经过analyzer处理,包括分词,权重处理、生成document记录,写入存储器(硬盘或者内存)。

Lucene 读出:对搜索关键词进行analyzer处理,包括分词、权重、范围匹配处理.源码结构图如下:

具体流程如下图:

数据流图如下:

二、常用推荐引擎算法问题

采用基于数据挖掘的算法来实现推荐引擎是各大电子商务网站、SNS社区最为常用的方法,推荐引擎常用Content-Based 推荐算法及协同过 滤算法(Item-Based 、User-based)。但从实际应用来看,对于大部分中小型企业来说,要在电子商务系统完整采用以上算法还有很大的难 度。

1)、相对成熟、完整、现成的开源解决方案较少

粗略分来,目前与数据挖掘及推荐引擎相关的开源项目主要有如下几类:

数据挖掘相关:主要包括Weka、R-Project、Knime、RapidMiner、Orange 等

文本挖掘相关:主要包括OpenNLP、LingPipe、FreeLing、GATE 、Carrot2 等,具体可以参考LingPipe’s Competition

推荐引擎相关:主要包括Apache Mahout、Duine framework、Singular Value Decomposition (SVD) ,其他包可以参考Open Source Collaborative Filtering Written in Java

搜索引擎相关:Lucene、Solr、Sphinx、Hibernate Search等

2)、常用推荐引擎算法相对复杂,入门门槛较高

3)、常用推荐引擎算法性能较低,并不适合海量数据挖掘

以上这些包或算法,除了Lucene/Sor相对成熟外,大部分都还处于学术研究使用,并不能直接应用于互联网规模的数据挖掘及推荐引擎引擎使用。

(以上都是基于java的,需要自己去研究实现,有很大难度)

备注:除了分类查找和主动搜索,推荐系统也是用户浏览商品的重要途径,能帮助用户发现类似并感兴趣的产品,增加商品的访问量,将访问者转化为购买者,引导用户购买。最终产生的价值是提升用户购物体验和用户粘度,提高订单量,如Amazon30%的订单来自推荐系统。

采用Lucene实现推荐引擎的优势

对很多众多的中小型网站而言,由于开发能力有限,如果有能够集成了搜索、推荐一体化的解决方案,这样的方案肯定大受欢迎。采用Lucene来实现推荐引擎具有如下优势:

1)、Lucene 入门门槛较低,大部分网站的站内搜索都采用了Lucene

2)、相对于协同过滤算法,Lucene性能较高

3)、Lucene对Text Mining、相似度计算等相关算法有很多现成方案

在开源的项目中,Mahout或者Duine Framework用于推荐引擎是相对完整的方案,尤其是Mahout 核心利用了Lucene,因此其架构很值得借鉴。只不过Mahout目前功能还不 是很完整,直接用其实现电子商务网站的推荐引擎尚不是很成熟。只不过从Mahout实现可以看出采用Lucene实现推荐引擎是一种可行方案。

3、采用Lucene实现推荐引擎需要解决的核心问题

Lucene对于Text Mining较为擅长,在contrib包中提供了MoreLikeThis功能,可以较为容易实现Content-Based的推荐,但对于涉及用户协 同过滤行为的结果(所谓的Relevance Feedback),Lucene目前并没有好的解决方案。需要在Lucene中内容相似算法中加入用户协同过滤行为对因素,将用户协同过滤行为结果转化 为Lucene所支持的模型。

推荐引擎的数据源

电子商务网站与推荐引擎相关典型的行为:

购买本商品的顾客还买过

浏览本商品的顾客还看过

浏览更多类似商品

喜欢此商品的人还喜欢

用户对此商品的平均打分

因此基于Lucene实现推荐引擎主要要处理如下两大类的数据

1)、内容相似度

例如:商品名称、作者/译者/制造商、商品类别、简介、评论、用户标签、系统标签

2)、用户协同行为相似度

例如:打标签、购买商品、点击流、搜索、推荐、收藏、打分、写评论、问答、页面停留时间、所在群组等等

5、实现方案

5.1、内容相似度 基于Lucene MoreLikeThis实现即可。

5.2、对用户协同行为的处理

1)、用户每一次协同行为都使用lucene来进行索引,每次行为一条记录

2)、索引记录中包含如下重要信息:

商品名、商品id、商品类别、商品简介、标签等重要特征值、用户关联行为的其他商品的特征元素、商品缩略图地址、协同行为类型(购买、点击、收藏、评分等)、Boost值(各协同行为在setBoost时候的权重值)

3)、对评分、收藏、点击等协同行为以商品特征值(标签、标题、概要信息)来表征

4)、不同的协同行为类型(例如购买、评分、点击)设置不同的值setBoost

5)、搜索时候采用Lucene MoreLikeThis算法,将用户协同转化为内容相似度

以上方案只是基于Lucene来实现推荐引擎最为简单的实现方案,方案的准确度及细化方案以后再细说。

更为精细的实现,可以参考Mahout的算法实现来优化。

其他搜索引擎开源工具推荐:Sphinx,目前是基于出自俄罗斯的开源全文搜索引擎软件Sphinx,单一索引最大可包含1亿条记 录,在1千万条记录情况下的查询速度为0.x秒(毫秒级)。Sphinx创建索引的速度为:创建100万条记录的索引只需3~4分钟,创建1000万条记 录的索引可以在50分钟内完成,而只包含最新10万条记录的增量索引,重建一次只需几十秒。

Sphinx 是一个基于 GPL 2 协议颁发的免费开源的全文搜索引擎.它是专门为更好的整合脚本语言和SQL数据库而设计的.当前内置的数据源支持直接从连接到 的 MySQL 或 PostgreSQL获取数据, 或者你可以使用 XML 通道结构(XML pipe mechanism , 一种基于 Sphinx 可识别的特殊xml格式的索引通道)

基于LAMP架构的应用很广泛,目前了解的商业应用有康盛的Discuz企业版。

三、手机之家的搜索方案(参考用)

手机之家目前的Lucene应用,采用的是Lucene 2.4.1 + JDK 1.6(64 bit)的组合,运行在8 CPU, 32G内存的机器上,数据量超过3300万条,原始数据文件超过14G,每天需要支持超过35万次的查询,高峰时期QPS超过20。单看这些数据可能并没 有大的亮点,但它的重建和更新都是自动化完成,而且两项任务可以同时运行,另一方面,在不影响服务可靠性的前提下,尽可能快地更新数据(如果两者发生冲 突,则优先保证可用性,延迟更新),其中的工作量还是非常大的

PPT连接 http://www.slideshare.net/tangfl/lucene-1752150

在大规模的应用中,Lucene更适合用于狭义的“搜索”,而不应当负责数据的存储。我们看看Lucene的源代码也可以知道,Document和 Field的存储效率是不够好看的。手机之家的团队也发现了这一点,他们的办法是,用Lucene存放索引,用Memcache + Berkeley DB(Java Edition)负责存储。这样有两个好处,一是减轻了Lucene的数据规模,提高了程序的效率;另一方面,这套系统也可以提供某些类似SQL的查询功 能。实际上,Lucene本身似乎也注意到了这个问题,在Store中新增了一个db的选项,其实也是利用的Berkeley DB。

在大规模应用中,Cache是非常重要的。PPT中也提到,可以在程序提供服务之前,进行几次”预热“搜索,填充Searcher的Cache。据 我们(银杏搜索)的经验,也可以在应用程序中,再提供针对Document的Cache,这样对性能有较大的改善。Lucene自己似乎也注意到了这个问 题,在2.4版本中提供了Cache,并提供了一个LRU Cache实现。不过据我们测试,在极端情况下,这个Cache可能会突破大小限制,一路膨胀最后吃光内存,甚至从网络上找的许多LRU Cache实现在极端条件下都有可能出现这样的问题,最终自己写了一个LRU Cache,并修改多次,目前来看是稳定的。

在编写Java服务程序的时候,记得设置退出的钩子函数(RunTime.getRunTime.addShutdownHook)是一个非常好的 习惯。许多Java程序员都没有这种意识,或者有,也只是写一个finalize函数,结果程序非正常退出时,可能造成某些外部资源的状态不稳定。拿 Lucene来说,之前的IndexWriter是默认autoCommit的,这样每添加一条记录,就提交一次,好处是如果中断,则之前添加的记录都是 可用的,坏处则是,索引的速度非常低。在新版本中autoCommit默认为False,速度提升明显(我们测试的结果是,提高了大约8倍),但如果中途 异常退出,则前功尽弃。如果我们添加了退出的钩子函数,捕获到退出信号则自动调用writer.close()方法,就可以避免这个问题。

目前的Lucene是兼容JDK 1.4的,它的binary版本也是JDK1.4编译的,如果对性能要求比较高,可以自行下载Lucene Source Code,用更新版本的JDK编译出.jar文件,据我测试,速度大约有30%的提升。

四、            XX网搜索方案

4.1 初步解决方案:

实现站内产品的分词搜索、推荐关键词和简单排序,定时自动更新,索引读写分离。

基于服务器的搜索压力大,用户的搜索体验不够有好,初步解决方案目标是解决服务器的搜索压力,实现初步的分词搜索,索引的自动定时维护。

4.1.1 数据库产品表分析:

l        大类基表

l        产品分类扩展基表

l        品牌基表,品牌系列表基表

l        产品基表(主表)

l        颜色基表

产品基表的数据大概在8万条左右,占用空间40m左右,单表数据量相对来书还是比较小的。

4.1.2  Lucene索引程序:

通过lucene的索引程序将库里的数据读入流,然后写入lucene自定义的索引文件,这个索引文件不进行搜索操作,需要完成后替换到搜索索引。 在建立索引的过程中进行分词处理,分词组件采用eaglet开发的盘古分词组件(已基于apache开源协议开源,进一步功能需要自己二次开发)。

4.1.3  Lucene索引库:

基表的索引文件大概在100m左右,分为写入时的库和搜索时用的库,写入库完成后并入搜索库,考虑到新索引合覆盖就索引的瞬间可能产生的索引程序错误或者索引文件损坏,在覆盖的同时通过程序控制让搜索程序读取写索引里的文件。

l        搜索处理services:基于产品库的的搜索,如品牌,分类,价格区间。搜索程序依赖于接口,基于数据库的搜索和基于文件的搜索要按需要随时切换。搜索的同时需要利用分词组件分词处理,对分词后的结果进行检索,数据库检索的暂时不做分词处理。

l        查询处理:查询前台程序使用mvc,实现产品的分词高亮显示,按照类别分类查询,品牌分类查询,价格区间查询。

4.2 第二步关键词统计:

搜索关键词的搜集和搜索的联合处理,实现简单的搜索推荐功能。主要是对前台的搜索关键字进行统计分析,并与搜索的排序进行关联,关键词的处理和与主表的关联索引方案等初步处理完成后再做完整解决方案。

4.3 第三步优化完善:

实现索引文件的基于消息的增量自动更新,权重计算,推荐产品计算研究,实时搜索的研究。权重计算,需要重新开发自己的向量算法引擎,考虑当中。

实时搜索目前在学习当中。

4.3.1 权重计算

权重计算方法会将前台用户的统计数据和产品库进行关联开发一套天天网产品的权重排序计算方法,以下算法流程图只是一个构思。

权重计算设计

4.3.2 索引自动化更新

建立基于消息机制的一个索引更新与维护机制。

基于消息队列的索引生成程序

[转载]用Eclipse开发和调试Android应用程序(一)

mikel阅读(882)

[转载]用Eclipse开发和调试Android应用程序(一) – Android – mobile – JavaEye论坛.

前面介绍了Windows环境下,基于Android SDK(2.3) 和 Eclipse(helios)的Android开发环境的搭建,并创建了第一个应用程序Hello Android World。具体挺参考小生的blog:http://blog.sina.com.cn/deaboway 或者http://blog.csdn.net/deaboway 。

现在,我们已经可以使用Eclipse来创建和开发Android应用程序,本文将仍以Hello Android World工程来深入解析Eclipse中Android工程的结构以及调试。

写上篇的时候,刚好Android SDK Platform Honeycomb Preview, revision 1(android-3.0_pre_r01-linux.zip)已经加入http://dl-ssl.google.com/android /repository/repository.xml,却无法下载,因此我们的第一个Android应用程序是用的Android SDK Platform 2.3.1,即Android 9 AVD进行演示。现在Android SDK Platform Honeycomb Preview已经放到http://dl-ssl.google.com/android/repository/android- 3.0_pre_r01-linux.zip,敢为天下先是我等求知若渴的程序员的优秀品质,因此,本次我们使用最新版本的Android SDK Platform Honeycomb Preview来进行我们本次教程。

先看看最新的Honeycomb Preview的样子吧(由于是Preview版本,启动确实不敢恭维,根据传闻,前几天之所以该版本一度无法下载安装是因为google发现这个Preview版本太烂,面子上挂不住,所以又撤掉了,呵呵):

相比手机上目前使用的最高Android 2.3版本而言,Android 3.0 Honeycomb更适合平板电脑使用,是专门为Android平板电脑进行优化的系统版本。随着SDK的发布,更加有利于开发者和厂商针对 Android 3.0 Honeycomb平板电脑进行开发,包括Android平板电脑应用和匹配。

一、 Android 应用程序概述

1. Android 的嫡系组件

Android有四项一等公民(或称为嫡系组件),包括:Activity(活动)、ContentProvider(内容提供程序)、 BroadcastReceiver(广播接收器)与Service(服务)。它们都必须宣告于AndroidManifest.xml档案里。

Activity 活动

活动是最常用的 Android 应用程序形式。活动在一个称为视图(后文将介绍)的类的帮助下,为应用程序提供 UI。视图类实现各种 UI 元素,比如文本框、标签、按钮和计算平台上常见的其他 UI 元素。

一个应用程序可以包含一个或多个活动。这些活动通常与应用程序中的屏幕形成一对一关系。

应用程序通过调用 startActivity() 或 startSubActivity() 方法从一个活动转移到另一个活动。如果应用程序只需“切换”到新的活动,就应该使用前一个方法。如果需要异步的调用/响应模式,就使用后一个方法。在这两 种情况下,都需要通过方法的参数传递一个 intent。

由操作系统负责决定哪个活动最适合满足指定的 intent(后文将介绍)。

对于Activity,关键是其生命周期的把握(后文将介绍),其次就是状态的保存和恢复(onSaveInstanceState onRestoreInstanceState),以及Activity之间的跳转和数据传输(intent)。

Activity几乎承接着用户对应用程序(Application)的所有操作,Activity应该有一个窗口(Window),这个窗口是 可以通过不用的主题(Theme)改变样子的。Activity应该要注意它的生命周期(Lifecycle)、设备状态(Configuration) 改变时的影响以及运行状态和数据的保存,这个在一个应用程序是否可靠和人性化上至关重要。Activity里还应该要申明一些许可 (Permissions),以便使用Android的一些软硬件功能,这些申明可以由代码或者Manifest.xml给出。最后,每个 Activity(的入口)一定要在Manifest当中申明。

Service 服务

与其他多任务计算环境一样,“在后台”运行着一些应用程序,它们执行各种任务。Android 把这种应用程序称为“Service服务”。

Service是没有界面的程序,它是所谓的服务,也叫后台程序。应该要非常注意Service的启动(startService)和绑定 (bindService)这两种开启Service的方法之间的关系以及Service对应的生命周期,两种开户Service的方法对Service 的生命周期效果是不同的。还有就是申明许可以及申明Service,也是在代码内或者Manifest内申明。

BroadcastReceiver 广播接收器

广播接收器是一个应用程序组件,它接收请求并处理 intent。与服务一样,接收器在一般情况下也没有 UI 元素。广播接收器通常在 AndroidManifest.xml 文件中注册。广播接收器的类属性是负责实现这个接收器的 Java 类。

广播接收并不是通常所说的无线电广播,而是指由sendBroadcast()所发送出来的意图(Intent),即广播在这里的意思是意 图,BroadcastReceiver在注册(Registe)之后可以自动监听符合预先给定的条件的意图,如果有则会通知此 BroadcastReceiver的持有程序。

ContentProvider 内容提供程序 ——数据管理

内容提供程序是 Android 的数据存储抽象机制。我们以移动设备上常见的一种数据为例:地址簿或联系人数据库。地址簿包含所有联系人及其电话号码,用户在使用手机时可能需要使用这些 数据。内容提供程序对数据存储的访问方法进行抽象。内容提供程序在许多方面起到数据库服务器的作用。对数据存储中数据的读写操作应该通过适当的内容提供程 序传递,而不是直接访问文件或数据库。可能还有内容提供程序 的 “客户机” 和 “实现”。

ContentProvider是作保存应用程序数据和建立维持数据库之用,以便程序重新启动时回到以前的状态或者保存信息。应该注意应用程序的使用权限以及SQL语言的使用,Android用的是一个轻量级的数据库系统SQLite。

2. Android 生命周期

Android 程序的生命周期是由系统控制而非程序自身直接控制,这与桌面应用程序在程序自身收到关闭请求后执行一个特定的动作(比如从 main 函数中 return)而导致进程结束的思维不同。

在Android系统中,当某个activity调用startActivity(myIntent)时,系统会在所有已经安装的程序中寻找其 intentfilter和myIntent最匹配的一个activity,启动这个进程,并把这个intent通知给这个activity。这就是一个 程序的“生”。在Android中,所有的应用程序“生来就是平等的”,所以不光Android的核心程序甚至第三方程序也可以发出一个intent来启 动另外一个程序中的一个activity。Android的这种设计非常有利于“程序部件”的重用。

Android根据其重要性在内存不足的时候移去重要性最低的进程。重要性由高到低为:

1.前台进程。这样的进程拥有一个在屏幕上显示并和用户交互的activity或者它的一个IntentReciver正在运行。这样的程序重要性最高,只有在系统内存非常低,万不得已时才会被结束。

2.可见进程。在屏幕上显示,但是不在前台的程序。比如一个前台进程以对话框的形式显示在该进程前面。这样的进程也很重要,它们只有在系统没有足够内存运行所有前台进程时,才会被结束。

3.服务进程。这样的进程在后台持续运行,比如后台音乐播放、后台数据上传下载等。这样的进程对用户来说一般很有用,所以只有当系统没有足够内存来维持所有的前台和可见进程时,才会被结束。

4.后台进程。这样的程序拥有一个用户不可见的activity。这样的程序在系统内存不足时,按照LRU的顺序被结束。

5.空进程。这样的进程不包含任何活动的程序部件。系统可能随时关闭这类进程。

从某种意义上讲,垃圾收集机制把程序员从“内存管理噩梦”中解放出来,而Android的进程生命周期管理机制把用户从“任务管理噩梦”中解放出 来。Android使用Java作为应用程序API,并且结合其独特的生命周期管理机制同时为开发者和使用者提供最大程度的便利。

Activity 生命周期

Activity中常用的函数有SetContentView() findViewById() finish() startActivity(),其生命周期涉及的函数有:

void onCreate(Bundle savedInstanceState)

void onStart()

void onRestart()

void onResume()

void onPause()

void onStop()

void onDestroy()

注意的是,Activity的使用需要在Manifest文件中添加相应的,并设置其属性和intent-filter。

Service 生命周期

Service可以通过Context.startService()或Context.bindService()创建,通过 Context.stopService()、Service.stopSelf()、Service.stopSelfResult()或 Context.unbindService()来关闭。其生命周期涉及的函数有:

void onCreate()

void onStart(Intent intent)

void onDestroy()

其中onCreate()和onDestroy()可以被所有服务调用,无论是由Context.startService()还是 Context.bindService()发起的Service。但是,onStart()只能被由startService()发起的Service 调用。

如果一个Service运行其它对象绑定它,需要扩展如下callback方法:

IBinder onBind(Intent intent)

boolean onUnbind(Intent intent)

void onRebind(Intent intent)

BroadcastReceiver 生命周期

只包含一个方法:void onReceive(Context curContext, Intent broadcastMsg)

包含活动的组件的BroadcastReceiver将不会被系统关闭,但是仅包含不活动的组件的进程将随时会背系统关闭(当其它组建需要内存时)。

3. Intent 简介—— Android 的创新导航与触发机制

前文介绍了Android的四项一等公民:Activity(活动)、ContentProvider(内容提供程序)、 BroadcastReceiver(广播接收器)与Service(服务)。这四种组件是独立的,它们之间可以互相调用,协调工作,最终组成一个真正的 Android应用。

在这些组件之间的通讯中,主要是由Intent协助完成的。Intent是Android应用开发里很重要的一个元件,通过Intent可以从一 个Activity来启动另一个任意的Activity,不管是自己定义的还是系统定义的。在ActivityGroup(extends Activity)里面,Intent的flag设置对于子Activity的启动方式至关重要。

Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。

因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦。

Android应用程序框架的强大之处在于它将Web习惯引入到移动应用程序中。这并不意味着该平台提供了一个强大的浏览器,也不仅限于使用 JavaScript和服务器端资源,而是涉及Android平台的工作原理以及该平台的用户如何与移动设备交互这一核心问题。互联网的强大之处一言以蔽 之,在于一切事物通过一次单击即可获得。这些单击的内容对于用户来说就是URL(UniformResource Locator,统一资源定位符)或URI(Uniform Resource Identifier,统一资源标识符)。有效使用URI可帮助用户方便快捷地访问所需的日常信息。“把链接发给我”就说明了一切。

在移动设备上复制桌面设备体验的平台只能吸引一小部分忠实的用户。多级菜单、多次单击在移动市场中通常都不被人所接受。移动应用程序对直观易用的 要求比其他任何市场中的应用程序都要高。Intent和IntentFilter将“单击”范例引入到了Android平台移动应用程序使用和开发的核心 中。

Intent 结构

Intent是执行某操作的一个抽象描述,它描述了如下内容:

首先, 要执行的动作(action)的一个简要描述,如VIEW_ACTION(查看)、EDIT_ACTION(修改)等,Android为我们定义了一套标准动作:

MAIN_ACTION

VIEW_ACTION

EDIT_ACTION

PICK_ACTION

GET_CONTENT_ACTION

DIAL_ACTION

CALL_ACTION

SENDTO_ACTION

ANSWER_ACTION

INSERT_ACTION

DELETE_ACTION

RUN_ACTION

LOGIN_ACTION

CLEAR_CREDENTIALS_ACTION

SYNC_ACTION

PICK_ACTIVITY_ACTION

WEB_SEARCH_ACTION

此外,我们还可以根据应用的需要,定义我们自己的动作,并可定义相应的Activity来处理我们的自定义动作。

其次, 执行动作要操作的数据(data),Android中采用指向数据的一个URI来表示,如在联系人应用中,一个指向某联系人的URI可能 为:content://contacts/1。这种URI表示,通过 ContentURI这个类来描述,具体可以参考android.net.ContentURI类的文档。

此外, 除了action和data这两个重要属性外,还有一些附加属性:

category(类别),被执行动作的附加信息。例如 LAUNCHER_CATEGORY 表示Intent 的接受者应该在Launcher中作为顶级应用出现;而ALTERNATIVE_CATEGORY表示当前的Intent是一系列的可选动作中的一个,这 些动作可以在同一块数据上执行。

type(数据类型),显式指定Intent的数据类型(MIME)。一般Intent的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型而不再进行推导。

component(组件),指定Intent的的目标组件的类名称。通常 Android会根据Intent 中包含的其它属性的信息,比如action、data/type、category进行查找,最终找到一个与之匹配的目标组件。但是,如果 component这个属性有指定的话,将直接使用它指定的组件,而不再执行上述查找过程。指定了这个属性以后,Intent的其它所有属性都是可选的。

extras(附加信息),是其它所有附加信息的集合。使用extras可以为组件提供扩展信息,比如,如果要执行“发送电子邮件”这个动作,可以将电子邮件的标题、正文等保存在extras里,传给电子邮件发送组件。

总之, action、 data/type、category和extras 一起形成了一种语言。这种语言使系统能够理解诸如“查看某联系人的详细信息”之类的短语。随着应用不断的加入到系统中,它们可以添加新的action、 data/type、category来扩展这种语言。应用也可以提供自己的Activity来处理已经存在的这样的“短语”,从而改变这些“短语”的行 为。

解析 Intent

在应用中,我们可以以两种形式来使用Intent:

· 显式(直接)Intent:指定了component属性的Intent(调用setComponent(ComponentName)或者setClass(Context,Class)来指定)。通过指定具体的组件类,通知应用启动对应的组件。

· 隐式(间接)Intent:没有指定comonent属性的Intent。这些Intent需要包含足够的信息,这样系统才能根据这些信息,在在所有的可用组件中,确定满足此Intent的组件。

对于显式(直接)Intent,Android不需要去做解析,因为目标组件已经很明确,Android需要解析的是那些隐式(间 接)Intent,通过解析,将Intent映射给可以处理此Intent的Activity、BroadcastReceiver或Service。

Intent解析机制主要是通过查找已注册在AndroidManifest.xml中的所有IntentFilter及其中定义的 Intent,最终找到匹配的Intent。在这个解析过程中,Android是通过Intent的action、type、category这三个属性 来进行判断的,判断方法如下:

· 如果Intent指明定了action,则目标组件的IntentFilter的action列表中就必须包含有这个action,否则不能匹配;

· 如果Intent没有提供type,系统将从data中得到数据类型。和action一样,目标组件的数据类型列表中必须包含Intent的数据类型,否则不能匹配。

· 如果Intent中的数据不是content:类型的URI,而且Intent也没有明确指定它的type,将根据Intent中数据的scheme(比 如http:或者mailto:)进行匹配。同上,Intent的scheme必须出现在目标组件的scheme列表中。

· 如果Intent指定了一个或多个category,这些类别必须全部出现在组建的类别列表中。比如Intent中包含了两个类别:LAUNCHER_CATEGORY和ALTERNATIVE_CATEGORY,解析得到的目标组件必须至少包含这两个类别。

Intent 和 IntentFilter

Intent是对需要的声明。

IntentFilter是在需要时有能力和有兴趣提供协助的声明。

Intent由一系列描述所需动作或服务的信息构成。本节将介绍所请求的动作以及与之相关的数据。

IntentFilter可以是通用的,也可以特定于向某些Intent提供服务。

Intent的动作属性通常为动词,例如VIEW、PICK或EDIT。很多内置的Intent动作都是作为Intent类的成员定义的。应用程 序开发人员也可以创建新动作。要查看信息,应用程序可以采用以下Intent动作:Intent的数据部分采用URI的形式表示,并且可以是信息的任何部 分,例如联系人记录、网站位置或对媒体剪辑的引用。

IntentFilter定义Intent与应用程序之间的关系。IntentFilter可以与Intent的数据部分或动作部分相关,或同时 与两者相关。IntentFilter还包含一个category(类别)字段。类别可以帮助对动作进行分类。例如,CATEGORY_LAUNCHER 类别指示Android包含此Intent-Filter的Activity在主应用程序启动器或主界面上应该处于可见状态。

分发Intent后,系统会计算可用的Activity、Service,以及已注册的BroadcastReceiver,并将 Intent分发给大多数适当的接收者。

IntentFilter通常在应用程序的AndroidManifest.xml中使用标记进行定义。从本质上说,AndroidManifest.xml文件就是一个应用程序描述符文件。

下一节介绍,这是 Android 在移动设备屏幕上显示 UI 元素的机制。

4. Android 视图——显示用户界面( UI )元素

Android 活动通过视图显示UI元素。视图采用以下布局设计之一:

· LinearVertical – 后续的每个元素都排在前一个元素下面,形成一个单一列。

· LinearHorizontal – 后续的每个元素都排在前一个元素右边,形成一个单一行。

· Relative – 后续的每个元素相对于前一个元素有一定的偏移量。

· Table – 与 HTML 表相似的一系列行和列。每个单元格可以包含一个视图元素。

选择一种布局(或布局的组合)之后,就可以用各个视图显示 UI。

视图元素由大家熟悉的 UI 元素组成,包括:

· Button

· ImageButton

· EditText

· TextView(与标签相似)

· CheckBox

· Radio Button

· Gallery 和 ImageSwitcher(用来显示多个图像)

· List

· Grid

· DatePicker

· TimePicker

· Spinner(与组合框相似)

· AutoComplete(具有文本自动补全特性的 EditText)

视图是在一个 XML 文件中定义的。每个元素都有一个或多个属于 Android 名称空间的属性。

[转载]ASP.NET MVC HtmlHelper中的Form和Link的小扩展

mikel阅读(1305)

[转载]我对ASP.NET MVC HtmlHelper中的Form和Link的小扩展 – 迭戈 – 博客园.

项目中碰到的问题,或多或少的记录下来,一是积累,二是各位大牛给提供更好的建议。

1、HtmlHelper中的Link

您在开发web程序的时候很有可能会定义一个执行JavaScript的伪链接(这是我起的名字),例如:


<a onclick="alert('hello world')" href="javascript:void(0)">Click me</a>

之所以我喊它为伪链接是因为它并不会跳转页面(当然那种定义location.href的除外)。

问题出现在这个伪链接并不是一成不变的,是根据数据状态来确定的,例如,当某一列的值为0的时候显示该连接,为1的时候不显示该连接,

那么我们可以这么写(示例而已):

&lt;%if (1 == 1) {%&gt;
<a onclick="alert('hello world')" href="javascript:void(0)">Click me</a>
&lt;%} %&gt;
&lt;%else { %&gt;
其它的东西。。。
&lt;%} %&gt;

很好,假如我们的状态有很多种呢,你可能要用到switch,然后还会套嵌if else,那么我们的view无疑会变得Tag soup,使维护变得异常的麻烦。

还好,我们可以为HtmlHelper扩展一个方法,将这些逻辑都写到扩展方法里面。(可能有朋友说将这些链接放到独立的ViewUserControl中,但是依然不能解决问题,因为那会使我们的ViewUserControl变得和view一样)

写到方法里面的链接必然要用到HtmlHelper的方法:Html.LinkExtensions.ActionLink,这个方法几乎能够提供我们使用html标签时所有形式。为什么

要用几乎,是因为对应上面的伪链接的形式,它支持的并不好。我在查看了起源码之后,并没有找到合适的方法能让ActionLink生成类似:

<a onclick="alert('hello world')" href="javascript:void(0)">Click me</a>

的链接。所以我决定实现一个专门生成这种伪链接的ActionLink方法。和MVC自带的ActionLink一样,使用其TagBuilder很容易实现该操作:

1 ///
2  /// 生成类似a href="javascript:void(0) onclick="alert('click me');"&gt;Click Me /a 链接
3  ///
4  ///
<span> </span> 5  ///
6  ///
7  ///
8  public static string ActionLinkForJS(this HtmlHelper htmlHelper, string linkText, object htmlAttributes)
9 {
10 return ActionLinkForJS(htmlHelper, linkText, new RouteValueDictionary(htmlAttributes));
11 }
12
13  ///
14  /// 生成类似a href="javascript:void(0) onclick="alert('click me');"&gt;Click Me /a 链接
15  ///
16  ///
17  ///
///
///
public static string ActionLinkForJS(this HtmlHelper htmlHelper, string linkText, IDictionary htmlAttributes)
{
if (String.IsNullOrEmpty(linkText))
{
throw new ArgumentException("linkText");
}

TagBuilder linkTag = new TagBuilder("a");
linkTag.InnerHtml = linkText;
linkTag.MergeAttribute("href", "javascript:void(0)");
linkTag.MergeAttributes(htmlAttributes);

return linkTag.ToString(TagRenderMode.Normal);
}

这样就实现了让ActionLink生成伪链接。
2、HtmlHelper中的BeginForm

曾几何时,我一直在用HtmlHelper中的BeginForm来生成一个Form表单。最近的一次使用出现了问题,代码是这样的:

<%using (Html.BeginForm("List", "Complaint", null, FormMethod.Post, null))

因为页面有不少查询条件,类似于搜索。我会把搜索条件Post到Action里面:

public ActionResult List(ComplaintInfo paramComplaint)

页面的查询条件类似于:

请求List这个Action的时候如果传递一个id过去,会查询出来对应的一条数据,对应的URL是这样的:http://localhost:8886/Complaint/List/220

问题就出现在这里,页面生成Form标签的action属性是这样的:

<form action="/Complaint/List/220" method="post">

这种在Post到action的时候(请注意上面的List方法),会对参数进行ModelBinder,进而相当于传递了一个参数id过去,这样其它的查询条件

就失去了作用(因为id是主键)。我尝试将BeginForm的参数routeValues显示定义为null,问题依然存在。我现在就想根据传递的actionName,controllerName

进而拼接对应Form的action属性。例如,我上面的BeginForm方法应该生成统一的形式:

<form action="/Complaint/List" method="post">

而不是在把RouteValue一起放置在Form的action属性里面。

我仔细的查看了BeginForm的源码,发现问题出现在

UrlHelper方法

中使用Route组件得到VirtualPath方法,会自动将RouteData匹配到相应的URL,导致生成的Form的action属性并不会随我们所欲。知道了问题,

改起来也很容易:

public static MvcForm BeginForm(this HtmlHelper htmlHelper, string actionName, string controllerName, object routeValues, FormMethod method, object htmlAttributes)
 {
      return BeginForm(htmlHelper, actionName, controllerName, new RouteValueDictionary(routeValues), method, new RouteValueDictionary(htmlAttributes));
  }
 
  public static MvcForm BeginForm(this HtmlHelper htmlHelper, string actionName, string controllerName, RouteValueDictionary routeValues, FormMethod method, IDictionary<string, object> htmlAttributes)
  {
      TagBuilder tagBuilder = new TagBuilder("form");
      tagBuilder.MergeAttributes(htmlAttributes);
     // action is implicitly generated, so htmlAttributes take precedence.
      tagBuilder.MergeAttribute("action", string.Format("/{0}/{1}", controllerName, actionName));
     // method is an explicit parameter, so it takes precedence over the htmlAttributes.
      tagBuilder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method), true);
 
     HttpResponseBase httpResponse = htmlHelper.ViewContext.HttpContext.Response;
     httpResponse.Write(tagBuilder.ToString(TagRenderMode.StartTag));
     return new MvcForm(htmlHelper.ViewContext.HttpContext.Response);
 }

其实还有一种更简单直接的方法,就是不用BeginForm方法,而是直接写html:

<form action=”/Complaint/List” method=”post”>

到此便结束了(其实您可以利用tagbuilder类扩展很多东西出来),不知道您是否有更好的方案呢?欢迎在回复中写出来。

[转载]ASP.NET MVC HtmlHelper中的Form和Link的小扩展

mikel阅读(1354)

[转载]我对ASP.NET MVC HtmlHelper中的Form和Link的小扩展 – 迭戈 – 博客园.

项目中碰到的问题,或多或少的记录下来,一是积累,二是各位大牛给提供更好的建议。

1、HtmlHelper中的Link

您在开发web程序的时候很有可能会定义一个执行JavaScript的伪链接(这是我起的名字),例如:


<a onclick="alert('hello world')" href="javascript:void(0)">Click me</a>

之所以我喊它为伪链接是因为它并不会跳转页面(当然那种定义location.href的除外)。

问题出现在这个伪链接并不是一成不变的,是根据数据状态来确定的,例如,当某一列的值为0的时候显示该连接,为1的时候不显示该连接,

那么我们可以这么写(示例而已):

&lt;%if (1 == 1) {%&gt;
<a onclick="alert('hello world')" href="javascript:void(0)">Click me</a>
&lt;%} %&gt;
&lt;%else { %&gt;
其它的东西。。。
&lt;%} %&gt;

很好,假如我们的状态有很多种呢,你可能要用到switch,然后还会套嵌if else,那么我们的view无疑会变得Tag soup,使维护变得异常的麻烦。

还好,我们可以为HtmlHelper扩展一个方法,将这些逻辑都写到扩展方法里面。(可能有朋友说将这些链接放到独立的ViewUserControl中,但是依然不能解决问题,因为那会使我们的ViewUserControl变得和view一样)

写到方法里面的链接必然要用到HtmlHelper的方法:Html.LinkExtensions.ActionLink,这个方法几乎能够提供我们使用html标签时所有形式。为什么

要用几乎,是因为对应上面的伪链接的形式,它支持的并不好。我在查看了起源码之后,并没有找到合适的方法能让ActionLink生成类似:

<a onclick="alert('hello world')" href="javascript:void(0)">Click me</a>

的链接。所以我决定实现一个专门生成这种伪链接的ActionLink方法。和MVC自带的ActionLink一样,使用其TagBuilder很容易实现该操作:

1 ///
2  /// 生成类似a href="javascript:void(0) onclick="alert('click me');"&gt;Click Me /a 链接
3  ///
4  ///
<span> </span> 5  ///
6  ///
7  ///
8  public static string ActionLinkForJS(this HtmlHelper htmlHelper, string linkText, object htmlAttributes)
9 {
10 return ActionLinkForJS(htmlHelper, linkText, new RouteValueDictionary(htmlAttributes));
11 }
12
13  ///
14  /// 生成类似a href="javascript:void(0) onclick="alert('click me');"&gt;Click Me /a 链接
15  ///
16  ///
17  ///
///
///
public static string ActionLinkForJS(this HtmlHelper htmlHelper, string linkText, IDictionary htmlAttributes)
{
if (String.IsNullOrEmpty(linkText))
{
throw new ArgumentException("linkText");
}

TagBuilder linkTag = new TagBuilder("a");
linkTag.InnerHtml = linkText;
linkTag.MergeAttribute("href", "javascript:void(0)");
linkTag.MergeAttributes(htmlAttributes);

return linkTag.ToString(TagRenderMode.Normal);
}

这样就实现了让ActionLink生成伪链接。
2、HtmlHelper中的BeginForm

曾几何时,我一直在用HtmlHelper中的BeginForm来生成一个Form表单。最近的一次使用出现了问题,代码是这样的:

<%using (Html.BeginForm("List", "Complaint", null, FormMethod.Post, null))

因为页面有不少查询条件,类似于搜索。我会把搜索条件Post到Action里面:

public ActionResult List(ComplaintInfo paramComplaint)

页面的查询条件类似于:

请求List这个Action的时候如果传递一个id过去,会查询出来对应的一条数据,对应的URL是这样的:http://localhost:8886/Complaint/List/220

问题就出现在这里,页面生成Form标签的action属性是这样的:

<form action="/Complaint/List/220" method="post">

这种在Post到action的时候(请注意上面的List方法),会对参数进行ModelBinder,进而相当于传递了一个参数id过去,这样其它的查询条件

就失去了作用(因为id是主键)。我尝试将BeginForm的参数routeValues显示定义为null,问题依然存在。我现在就想根据传递的actionName,controllerName

进而拼接对应Form的action属性。例如,我上面的BeginForm方法应该生成统一的形式:

<form action="/Complaint/List" method="post">

而不是在把RouteValue一起放置在Form的action属性里面。

我仔细的查看了BeginForm的源码,发现问题出现在

UrlHelper方法

中使用Route组件得到VirtualPath方法,会自动将RouteData匹配到相应的URL,导致生成的Form的action属性并不会随我们所欲。知道了问题,

改起来也很容易:

public static MvcForm BeginForm(this HtmlHelper htmlHelper, string actionName, string controllerName, object routeValues, FormMethod method, object htmlAttributes)
 {
      return BeginForm(htmlHelper, actionName, controllerName, new RouteValueDictionary(routeValues), method, new RouteValueDictionary(htmlAttributes));
  }
 
  public static MvcForm BeginForm(this HtmlHelper htmlHelper, string actionName, string controllerName, RouteValueDictionary routeValues, FormMethod method, IDictionary<string, object> htmlAttributes)
  {
      TagBuilder tagBuilder = new TagBuilder("form");
      tagBuilder.MergeAttributes(htmlAttributes);
     // action is implicitly generated, so htmlAttributes take precedence.
      tagBuilder.MergeAttribute("action", string.Format("/{0}/{1}", controllerName, actionName));
     // method is an explicit parameter, so it takes precedence over the htmlAttributes.
      tagBuilder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method), true);
 
     HttpResponseBase httpResponse = htmlHelper.ViewContext.HttpContext.Response;
     httpResponse.Write(tagBuilder.ToString(TagRenderMode.StartTag));
     return new MvcForm(htmlHelper.ViewContext.HttpContext.Response);
 }

其实还有一种更简单直接的方法,就是不用BeginForm方法,而是直接写html:

<form action=”/Complaint/List” method=”post”>

到此便结束了(其实您可以利用tagbuilder类扩展很多东西出来),不知道您是否有更好的方案呢?欢迎在回复中写出来。

[转载]跨平台iPhone中调用WCF服务

mikel阅读(1488)

[转载]跨平台iPhone中调用WCF服务 – 用自己的语言写个Hello World – 博客园.

由于对移动平台充满着好奇与兴趣,最近着手了iPhone开发和学习。学习的路线是从objective-c到cococa。方法是看了两本入门的英文书,还有就是学习apple的sdk。对于产品的基本想法是服务端用.net,手机客户端用iPhone。

一些复杂的逻辑处理放到服务端实现,客户端与服务端通过XML交互,在iPhone客户端解析XML通过cocoa展示数据。由于iPhone和 DoNet是两个完全不同的平台。iPhone依靠mac系统平台,donet依赖windows系统平台。这篇文章我将通过一个hello world程序讲述一下通过WCF实现从mac系统到windows的跨平台的调用。

1、创建简单的WCF服务

服务契约代码如下:

实现如下:

2、在iPhone中调用WCF

与donet调用wcf服务不同,这里使用NSURLConnection去获取WCF服务端的数据,代码如下:

NSURLConnection的委托方法:

解析XML的中hello world的委托方法,对于objective-c解析xml可以看我的上一篇博客:

运行:

总结:本文通过一个简单的例子,说明了iPhone调用WCF的方法。用wcf实现跨平台还是蛮简单的!

代码:

wcf code:http://files.cnblogs.com/zhuqil/WcfService1.rar

cocoa code:http://files.cnblogs.com/zhuqil/wcf2.zip

[原创]SQLServer2008跨数据库导入数据配置教程

mikel阅读(835)

SQL SERVER企业管理器—>服务器—>服务器对象—>链接服务器—>新建—>常规选项页—>填写链接服务器名或IP,服务器类型选SQL SERVER
—>安全性选项页—>用此安全上下文进行,填写登陆数据库的登录名和密码,就可以了。

–查询示例
select * from 链接服务器名.数据库名.dbo.表名

–导入示例
select * into 表 from 链接服务器名.数据库名.dbo.表名

–创建链接服务器
exec sp_addlinkedserver ‘ITSV ‘, ‘ ‘, ‘SQLOLEDB ‘, ‘远程服务器名或ip地址 ‘
exec sp_addlinkedsrvlogin ‘ITSV ‘, ‘false ‘,null, ‘用户名 ‘, ‘密码 ‘

–查询示例
select * from ITSV.数据库名.dbo.表名

–导入示例
select * into 表 from ITSV.数据库名.dbo.表名

–以后不再使用时删除链接服务器
exec sp_dropserver ‘ITSV ‘, ‘droplogins ‘

–连接远程/局域网数据(openrowset/openquery/opendatasource)
–1、openrowset

–查询示例
select * from openrowset( ‘SQLOLEDB ‘, ‘sql服务器名 ‘; ‘用户名 ‘; ‘密码 ‘,数据库名.dbo.表名)

–生成本地表
select * into 表 from openrowset( ‘SQLOLEDB ‘, ‘sql服务器名 ‘; ‘用户名 ‘; ‘密码 ‘,数据库名.dbo.表名)

–把本地表导入远程表
insert openrowset( ‘SQLOLEDB ‘, ‘sql服务器名 ‘; ‘用户名 ‘; ‘密码 ‘,数据库名.dbo.表名)
select *from 本地表

–更新本地表
update b
set b.列A=a.列A
from openrowset( ‘SQLOLEDB ‘, ‘sql服务器名 ‘; ‘用户名 ‘; ‘密码 ‘,数据库名.dbo.表名)as a inner join 本地表 b
on a.column1=b.column1

–openquery用法需要创建一个连接

–首先创建一个连接创建链接服务器
exec sp_addlinkedserver ‘ITSV ‘, ‘ ‘, ‘SQLOLEDB ‘, ‘远程服务器名或ip地址 ‘
–查询
select *
FROM openquery(ITSV, ‘SELECT * FROM 数据库.dbo.表名 ‘)
–把本地表导入远程表
insert openquery(ITSV, ‘SELECT * FROM 数据库.dbo.表名 ‘)
select * from 本地表
–更新本地表
update b
set b.列B=a.列B
FROM openquery(ITSV, ‘SELECT * FROM 数据库.dbo.表名 ‘) as a
inner join 本地表 b on a.列A=b.列A

–3、opendatasource/openrowset
SELECT *
FROM opendatasource( ‘SQLOLEDB ‘, ‘Data Source=ip/ServerName;User ID=登陆名;Password=密码 ‘ ).test.dbo.roy_ta
–把本地表导入远程表
insert opendatasource( ‘SQLOLEDB ‘, ‘Data Source=ip/ServerName;User ID=登陆名;Password=密码 ‘).数据库.dbo.表名

[转载]推荐8个超棒的学习 jQuery 的网站

mikel阅读(950)

[转载]推荐8个超棒的学习 jQuery 的网站 – 梦想天空 – 博客园.

根据国外科技网站 W3Techs 一项调查了近100万个网站数据显示,JQuery是目前最流行的 JavaScript 库。对于初学者来说,有的时候很难找到一个好的学习JQuery的网站,所以本文收集了8个很棒的 jQuery 学习网站推荐给大家。

1. Learning jQuery

8 Great Websites to Learn Step-by-Step jQuery

最好的 jQuery 资源博客之一,从 jQuery 高手那里获得宝贵的经验。

2. jQuery Mix

8 Great Websites to Learn Step-by-Step jQuery

一个内容非常丰富的网站,有关 jQuery 的各种各样的信息。

3. jQuery for Designers

8 Great Websites to Learn Step-by-Step jQuery

非常棒的一个 jQuery 资源和教程网站,帮助你成长为 jQuery 高手。

4. 15 Days of jQuery

8 Great Websites to Learn Step-by-Step jQuery

这个网站虽然更新不定时,你仍然可以从他们的文章中学到很多东西。

5. jQuery4u

8 Great Websites to Learn Step-by-Step jQuery

jQuery4U 是另外一个有关 jQuery 资源、技巧和发展趋势的博客。

6. jQuery King

8 Great Websites to Learn Step-by-Step jQuery

jQuery King 让你学习 jQuery 更容易、更有趣。

7. jQFundamentals

8 Great Websites to Learn Step-by-Step jQuery

这是一本在线书籍,介绍 jQuery 库的基本内容。

8. jQuery How To

8 Great Websites to Learn Step-by-Step jQuery

这个网站不是每天都更新,不过你可以从他们的教程中学到很多有用的技巧。

(编译来源:梦想天空 原文来自:8 Great Websites to Learn Step-by-Step jQuery