接口幂等性这么重要,它是什么?怎么实现?

什么是幂等性?

对于同一笔业务操作,不管调用多少次,得到的结果都是一样的。

幂等性设计

我们以对接支付宝充值为例,来分析支付回调接口如何设计?

如果我们系统中对接过支付宝充值功能的,我们需要给支付宝提供一个回调接口,支付宝回调信息中会携带(out_trade_no【商户订单号】,trade_no【支付宝交易号】),trade_no在支付宝中是唯一的,out_trade_no在商户系统中是唯一的。

回调接口实现有以下实现方式。

方式1(普通方式)

过程如下:

1.接收到支付宝支付成功请求
2.根据trade_no查询当前订单是否处理过
3.如果订单已处理直接返回,若未处理,继续向下执行
4.开启本地事务
5.本地系统给用户加钱
6.将订单状态置为成功
7.提交本地事务

上面的过程,对于同一笔订单,如果支付宝同时通知多次,会出现什么问题?当多次通知同时到达第2步时候,查询订单都是未处理的,会继续向下执行,最终本地会给用户加两次钱。

此方式适用于单机其,通知按顺序执行的情况,只能用于自己写着玩玩。

方式2(jvm加锁方式)

方式1中由于并发出现了问题,此时我们使用java中的Lock加锁,来防止并发操作,过程如下:

1.接收到支付宝支付成功请求
2.调用java中的Lock加锁
3.根据trade_no查询当前订单是否处理过
4.如果订单已处理直接返回,若未处理,继续向下执行
5.开启本地事务
6.本地系统给用户加钱
7.将订单状态置为成功
8.提交本地事务
9.释放Lock锁

分析问题:
Lock只能在一个jvm中起效,如果多个请求都被同一套系统处理,上面这种使用Lock的方式是没有问题的,不过互联网系统中,多数是采用集群方式部署系统,同一套代码后面会部署多套,如果支付宝同时发来多个通知经过负载均衡转发到不同的机器,上面的锁就不起效了。此时对于多个请求相当于无锁处理了,又会出现方式1中的结果。此时我们需要分布式锁来做处理。

方式3(悲观锁方式)

使用数据库中悲观锁实现。悲观锁类似于方式二中的Lock,只不过是依靠数据库来实现的。数据中悲观锁使用for update来实现,过程如下:

1.接收到支付宝支付成功请求
2.打开本地事物
3.查询订单信息并加悲观锁

4.判断订单是已处理
5.如果订单已处理直接返回,若未处理,继续向下执行
6.给本地系统给用户加钱
7.将订单状态置为成功
8.提交本地事物

重点在于for update,对for update,做一下说明:
1.当线程A执行for update,数据会对当前记录加锁,其他线程执行到此行代码的时候,会等待线程A释放锁之后,才可以获取锁,继续后续操作。
2.事物提交时,for update获取的锁会自动释放。

方式3可以正常实现我们需要的效果,能保证接口的幂等性,不过存在一些缺点:
1.如果业务处理比较耗时,并发情况下,后面线程会长期处于等待状态,占用了很多线程,让这些线程处于无效等待状态,我们的web服务中的线程数量一般都是有限的,如果大量线程由于获取for update锁处于等待状态,不利于系统并发操作。

方式4(乐观锁方式)

依靠数据库中的乐观锁来实现。

1.接收到支付宝支付成功请求
2.查询订单信息

3.判断订单是已处理
4.如果订单已处理直接返回,若未处理,继续向下执行
5.打开本地事物
6.给本地系统给用户加钱
7.将订单状态置为成功,注意这块是重点,伪代码:

注意:
update t_order set status = 1 where order_id = trade_no where status = 0; 是依靠乐观锁来实现的,status=0作为条件去更新,类似于java中的cas操作;关于什么是cas操作,可以移步:什么是 CAS 机制 ( http://www.itsoku.com/article/63 )?
执行这条sql的时候,如果有多个线程同时到达这条代码,数据内部会保证update同一条记录会排队执行,最终最有一条update会执行成功,其他未成功的,他们的num为0,然后根据num来进行提交或者回滚操作。

方式5(唯一约束方式)

依赖数据库中唯一约束来实现。

我们可以创建一个表:

对于任何一个业务,有一个业务类型(ref_type),业务有一个全局唯一的订单号,业务来的时候,先查询t_uq_dipose表中是否存在相关记录,若不存在,继续放行。

过程如下:

1.接收到支付宝支付成功请求
2.查询t_uq_dipose(条件ref_id,ref_type),可以判断订单是否已处理

3.判断订单是已处理
4.如果订单已处理直接返回,若未处理,继续向下执行
5.打开本地事物
6.给本地系统给用户加钱
7.将订单状态置为成功
8.向t_uq_dipose插入数据,插入成功,提交本地事务,插入失败,回滚本地事务,伪代码:

说明:
对于同一个业务,ref_type是一样的,当并发时,插入数据只会有一条成功,其他的会违法唯一约束,进入catch逻辑,当前事务会被回滚,最终最有一个操作会成功,从而保证了幂等性操作。
关于这种方式可以写成通用的方式,不过业务量大的情况下,t_uq_dipose插入数据会成为系统的瓶颈,需要考虑分表操作,解决性能问题。
上面的过程中向t_uq_dipose插入记录,最好放在最后执行,原因:插入操作会锁表,放在最后能让锁表的时间降到最低,提升系统的并发性。

关于消息服务中,消费者如何保证消息处理的幂等性?
每条消息都有一个唯一的消息id,类似于上面业务中的trade_no,使用上面的方式即可实现消息消费的幂等性。

总结

1.实现幂等性常见的方式有:悲观锁(for update)、乐观锁、唯一约束
2.几种方式,按照最优排序:乐观锁 > 唯一约束 > 悲观锁

参考链接


接口幂等性这么重要,它是什么?怎么实现?

Using a Thread Pool in Android

Android上使用线程池

In my last post Using HanderThread in Android, I showed how to offload short blocking tasks to a worker thread. While HandlerThread is good for tasks running in a sequential manner, there are cases where background tasks do not have dependencies on each other. To get these tasks done as quickly as possible, you might want to exploit the powerful multi-core processor on the mobile device and run the tasks concurrently on more than one worker thread.

A thread pool is a good fit for this scenario. Thread pool is a single FIFO task queue with a group of worker threads. The producers (E.g. the UI thread) sends tasks to the task queue. Whenever any worker threads in the thread pool become available, they remove the tasks from the front of the queue and start running them.

Comparing with starting a random number of individual worker threads, using a thread pool prevent the overhead of killing and recreating threads every time a worker thread is needed. It also gives you fine control over the number of threads and their lifecycle. E.g. ThreadPoolExecutor allows you to specify how many core threads, how many max threads the pool should create and the keep alive time for the idle threads.

Android supports Java’s Executor framework which offers the following classes for using a thread pool.

  • Executor: an interface which has a execute method. It is designed to decouple task submission from running.
  • Callable: An Interface similar to runnable but allow a result to be returned.
  • Future: Like a promise in JavaScript. It represents the result for an asynchronous task.
  • ExecutorService: an interface which extends Executor interface. It is used to manage threads in the threads pool.
  • ThreadPoolExecutor: a class that implements ExecutorService which gives fine control on the thread pool (Eg, core pool size, max pool size, keep alive time, etc.)
  • ScheduledThreadPoolExecutor: a class that extends ThreadPoolExecutor. It can schedule tasks after a given delay or periodically.
  • Executors: a class that offers factory and utility methods for the aforementioned classes.
  • ExecutorCompletionService: a class that arranges submitted task to be placed on a queue for accessing results.

Basic Thread Pool

The simplest way of creating a thread pool is to use one of the factory methods from Executors class.

newFixedThreadPool creates a thread pool with a a fixed number of thread in the pool specified by the user. The user can call setCorePoolSized(int) later to resize the thread pool.

newCachedThreadPool creates a new thread when there is a task in the queue. When there is no tasks in the queue for 60 seconds, the idle threads will be terminated.

newSingleThreadExecutor creates a thread pool with only one thread.

To add a task to the thread pool, call one of the following methods.

The second method returns a future object. It can be used to retrieve the result from the callable by calling future.get() or cancel the task by calling future.cancel(boolean mayInterruptIfRunning).

Advanced Thread Pool

If you want to have finer control over the thread pool, ThreadPoolExecutor class can be used. In the following example, I first find the available processors of the phone. The thread pool is configured to have core size as the NUMBER_OF_CORES, the maximum core size as the NUMBER_OF_CORES x 2, idle threads’ keep-alive time as 1 second, task queue as a LinkedBlockingQueue object and a custom thread factory.

Cancel Tasks

To stop the tasks in the task queue from execution, we just need to clear the task queue. To allow the running threads to be stopped, store all future objects in a list and call cancel on every object which is not done.

Handle Activity Lifecycle

One thing the thread pool framework does not handle is the Android activity lifecycle. If you want your thread pool to survive the activity lifecycle and reconnect to your activity after it is re-created (E.g. after an orientation change), it needs to be created and maintained outside the activity.

In my example, I made a static singleton class called CustomThreadPoolManager. It has a private constructor. It creates an instance of itself and return that single instance in the static getInstance method. It also holds a weak reference to the Activity. The reference is later used to communicate with the UI thread (see the next section).

In the Activity, get the thread pool singleton instance by calling the getInstance static method. Set the activity to the CustomThreadPoolManager. As CustomThreadPoolManager keeps the reference to the Activity as a weak reference, you don’t need to worry about leaking the Activity.

Communicate with UI Thread

When each task finishes, you may need to send some data back to the UI thread. A safe way of doing this is to send a message to the handler of the UI thread. First, extend Handler class and define what the UI thread should do when a message is received.

In the CustomThreadPoolManager, use the Activity’s weak reference to send the message to the UI thread.

In the CustomCallable, as it has reference to the CustomThreadPoolManager, it can send the message by calling CustomThreadPoolManager’s sendMessageToUiThread method.

Source Code

The full source code for the example used in this post is available on Github.

也可本站下载一份 代码拷贝

参考链接


Using a Thread Pool in Android

Activity singleInstance/singleTop启动模式的理解

Android有四种启动模式,分别是standard,singleTop,singleTask,singleInstance。下面分别简单的介绍下这四种启动模式的作用。

standard

Android 默认的一种启动模式。不需要为activity设置launchMode。这种启动模式简单的来说就是当你startActivity的时候,他就创建一个。

singleTop

这种模式模式从字面意思就能看得出来,就是当前的activity处于栈顶的时候,当你startActivity当前的activity的时候,它不会创建新的activity,而是会复用之前的activity。举个例子,startActivity了一个ActivityA,ActivityA又startActivity了ActivityB,当在ActivityB再次startActivity一个ActivityB的时候,它不会创建一个新的ActivityB,而是复用之前的ActivityB。
这里需要注意的是,只有当前的activity处于栈顶的时候才管用。举个例子:startActivity了一个ActivityA,ActivityA又startActivity了ActivityB,ActivityB又startActivity了ActivityA,那么ActivityA还是会重新创建,而不是复用之前的ActivityA。

singleTask

单一任务。意思就是说当前的activity只有一个实例,无论在任何地方startActivity出来这个activity,它都只存在一个实例。并且,它会将在他之上的所有activity都销毁。通常这个activity都是用来作为MainActivity。因为主页只需要存在一个,然后回到主页的时候可以将所有的activity都销毁起到退出应用的作用。举个例子,startActivity了一个ActivityA,ActivityA的启动模式为singleTask,那么在ActivityA里startActivity了一个ActivityB,在ActivityB里startActivity了一个ActivityC。此时在当前的任务栈中的顺序是,ActivityA->ActivityB->ActivityC。然后在ActivityC里重新startActivity了一个ActivityA,此时ActivityA会将存在于它之上的所有activity都销毁。所以此时任务栈中就只剩下ActivityA了。

singleInstance

这个模式才是重点,也是比较容易入坑的一种启动模式。字面上理解为单一实例。它具备所有singleTask的特点,唯一不同的是,它是存在于另一个任务栈中。上面的三种模式都存在于同一个任务栈中,而这种模式则是存在于另一个任务栈中。

注意事项

以往的理解中,只要在AndroidManifest.xml中声明singleTop或者singleInstance,那么在使用startActivity或者startActivityForResult的时候,自动就会保证singleInstance的情况下只有一个对象,singleTop的情况下不会两个相同的Activity叠加在一起。

但是现实是让人崩溃的。

使用如下的代码:

在两次触发startSingleTopActivity/startSingleInstanceActivity的时候,出现了两个叠加的Activity,如下:

可以看到出现两个单独的实例 Hist #2/Hist #1,而不是预期的忽略第二次调用。

在两次触发startSingleTopWithFlagsActivity/startSingleInstanceWithFlagsActivity的时候,只会出现了一个Activity,如下:

两者的区别就是

这句代码。

还是学艺不精啊。

完整例子代码,点击此处下载 MyApplication

参考链接


解决SourceTree 3.3.8访问Git库提示“access denied”

使用SourceTree 3.3.8,在检出版本库的时候,选择记住密码。过一段时间之后,版本库的密码修改之后,提示access denied

解决方法为删除已经记住的用户名密码,如下:

具体文件位置如下图:

继续阅读解决SourceTree 3.3.8访问Git库提示“access denied”

解决macOS系统curl报告https证书不正确(curl: (60) SSL certificate problem: Invalid certificate chain)

最近在使用brew升级git的时候,报告如下错误:

手工去下载数据,看到更具体的错误信息,如下:

解决方法为暂时要求curl忽略证书错误问题,如下:

注意,上述配置之后,可能会出现类似如下错误:

解决方法就是移除上面的配置,参考 OS X EI Capitan curl: (22) The requested URL returned error: 403 [[[!!! BREAKING CHANGE !!!]]] Support for clients that do not support Server Name Indication is temporarily disabled and will be permanently deprecated soon.

参考链接


How to fix curl: (60) SSL certificate: Invalid certificate chain

vue中template的三种写法

第一种(字符串模板写法):

直接写在vue构造器里,这种写法比较直观,适用于html代码不多的场景,但是如果模板里html代码太多,不便于维护,不建议这么写.

第二种:

直接写在template标签里,这种写法跟写html很像。

第三种:

写在script标签里,这种写法官方推荐,vue官方推荐script中type属性加上"x-template",即:

推荐这个写法的主要原因就可以把模版文件写到另外的一个JS文件里面,然后动态加载,实现模版复用以及文件分离。不至于一个页面里面实现太多的东西,导致页面代码混乱。

参考链接


16款优秀的Vue UI组件库推荐

Vue 是一个轻巧、高性能、可组件化的MVVM库,API简洁明了,上手快。从Vue推出以来,得到众多Web开发者的认可。
在公司的Web前端项目开发中,多个项目采用基于Vue的UI组件框架开发,并投入正式使用。
开发团队在使用Vue.js框架和UI组件库以后,开发效率大大提高,自己写的代码也少了,很多界面效果组件已经封装好了。
在选择Vue UI组件库的过程中,通过GitHub上根据star数量、文档丰富程度、更新的频率以及维护等因素,也收集整理了一些优秀的Vue UI组件库。

PS:国内的UI组件大部分都只有一部分的,常用的头部导航,底部导航,listview,grid表格很多都是没有的。

后面才发现,基于Vue的Quasar Framework 介绍 这个框架UI组件很全面,准备下次使用这个框架了

基于Vue的Quasar Framework 中文网
http://www.quasarchs.com/

quasarframework/quasar: Quasar Framework
https://github.com/quasarframework/quasar

Quasar(发音为/kweɪ.zɑɹ/)是MIT许可的开源框架(基于Vue),可帮助Web开发人员创建:
响应式网站
PWA(Progressive Web App)
通过Apache Cordova构建移动APP(Android,iOS,…)
多平台桌面应用程序(使用Electron)
Quasar允许开发人员编写一次代码,然后使用相同的代码库同时部署为网站、PWA、Mobile App和Electron App。使用最先进的CLI设计应用程序,并提供精心编写,速度非常快的Quasar Web组件。

当使用Quasar时,你不需要像Hammerjs,Momentjs或Bootstrap这样的额外重型库。它拥有这些功能,而且体积很小!

==============

1、 iView UI组件库
iView 是一套基于 Vue.js 的开源 UI 组件库,主要服务于 PC 界面的中后台产品。iView的组件还是比较齐全的,更新也很快,文档写得很详细。有公司团队维护,比较可靠的Vue UI组件框架。iView生态也做得很好,还有开源了一个iView Admin,做后台非常方便。官网上介绍,iView已经应用在TalkingData、阿里巴巴、百度、腾讯、今日头条、京东、滴滴出行、美团、新浪、联想等大型公司的产品中。
iView官网:https://www.iviewui.com/

2、Vux UI组件库
Vux是基于WeUI和Vue2.x开发的移动端UI组件库,主要服务于微信页面。Vux的定位已经很明确了,一是:Vue移动端UI组件库,二是:WeUI的基础样式库。Vux的组件涵盖了所有的WeUI的内容,还扩展了一些常用的组件。比如:Sticky、timeline、v-chart、XCircle。Vux是个人维护的。但是GitHub上star还是很高的,达到13k。在GitHub上看到对issue的关闭还是很迅速的。Vux文档基本的组件用法和效果都讲解到位了。在vux官网上也展示了很多Vux的使用案例。在微信页面开发中,基本没有太多的bug,开发还是比较顺手的。
Vux官网:https://vux.li/

3、Element UI组件库
Element,一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库。Element是饿了么前端开源维护的Vue UI组件库,更新频率还是很高的,基本一周到半个月都会发布一个新版本。组件齐全,基本涵盖后台所需的所有组件,文档讲解详细,例子也很丰富。没有实际使用过,网上的Element教程和文章比较多。Element应该是一个质量比较高的Vue UI组件库。
Element官网:http://element.eleme.io/#/zh-CN

4、Mint UI组件库
Mint UI基于 Vue.js 的移动端组件库,同样出自饿了么前端的项目。Mint UI是真正意义上的按需加载组件。可以只加载声明过的组件及其样式文件。Mint UI 采用 CSS3 处理各种动效,避免浏览器进行不必要的重绘和重排,从而使用户获得流畅顺滑的体验。网上的视频教程很多都是基于Mint UI来讲的,开发移动端web项目还是很方便,文档也很简介明了。很多页面Mint UI组件都已经封装好,基本可以照着例子写,简单的调整一下就可以实现。不过,在GitHub上看最后一次代码提交在2018年1月16日。不知道是项目比较稳定没有更新,还是项目有被废弃的可能。
Mint UI官网:http://mint-ui.github.io/#!/zh-cn

5、Bootstrap-Vue UI组件库
Bootstrap-VUE提供了基于vue2的Bootstrap V4组件和网格系统的实现,完成了广泛和自动化的WAI ARA可访问性标记。Bootstrap 4是最新发布的版本,与 Bootstrap3 相比拥有了更多的具体的类以及把一些有关的部分变成了相关的组件。同时 Bootstrap.min.css 的体积减少了40%以上。Bootstrap4 放弃了对 IE8 以及 iOS 6 的支持,现在仅仅支持 IE9 以上 以及 iOS 7 以上版本的浏览器。想当初刚流行响应式网站的时候,Bootstrap是世界上最受欢迎的建立移动优先网站的框架,Bootstrap可以说风靡全球。就算放在现在很多企业网站都是采用Bootstrap做的响应式。Bootstrap-Vue可以让你在Vue中也实现Bootstrap的效果。
Bootstrap-Vue官网:https://bootstrap-vue.js.org/

6、Ant Design Vue UI组件库
Ant Design Vue是 Ant Design 3.X 的 Vue 实现,开发和服务于企业级后台产品。在GitHub上可以找到几个Ant Design的Vue组件。不过相比较而言,Ant Design Vue更胜一筹。Ant Design Vue共享Ant Design of React设计工具体系,实现了所有Ant Design of React的组件,支持现代浏览器和 IE9 及以上(需要 polyfills)。可以让熟悉Ant Design的在使用Vue时,很容易的上手。
Ant Design Vue官网:https://vuecomponent.github.io/ant-design-vue/docs/vue/introduce-cn/

7、AT-UI UI组件库
AT-UI 是一款基于 Vue.js 2.0 的前端 UI 组件库,主要用于快速开发 PC 网站中后台产品,支持现代浏览器和 IE9 及以上。AT-UI 更加精简,实现了后台常用的组件。
AT_UI官网:https://at-ui.github.io/at-ui/#/zh

8、Vant UI组件库
Vant是一个轻量、可靠的移动端 Vue 组件库。Vant是有赞团队开源的,主要维护也是有赞团队。Vant Weapp 是有赞移动端组件库 Vant 的小程序版本,两者基于相同的视觉规范,提供一致的 API 接口,助力开发者快速搭建小程序应用。截止到目前,Vant已经开源了50+ 个经过有赞线上业务检验的组件。比如:、AddressEdit 地址编辑、AddressList 地址列表、Area 省市区选择、Card 卡片、Contact 联系人、Coupon 优惠券、GoodsAction 商品页行动点、SubmitBar 提交订单栏、Sku 商品规格弹层。如果做商城的,不太在意界面,实现业务逻辑的话,用Vant组件库开发还是很快的。
Vant官网:https://youzan.github.io/vant/#/zh-CN/intro

9、cube-ui UI组件库
cube-ui 是基于 Vue.js 实现的精致移动端组件库。由滴滴内部组件库精简提炼而来,经历了业务一年多的考验,并且每个组件都有充分单元测试,为后续集成提供保障。在交互体验方面追求极致。遵循统一的设计交互标准,高度还原设计效果;接口标准化,统一规范使用方式,开发更加简单高效。支持按需引入和后编译,轻量灵活;扩展性强,可以方便地基于现有组件实现二次开发。
cube-ui官网:https://didi.github.io/cube-ui/#/zh-CN

10、Muse-UI UI组件库
Muse-UI基于 Vue 2.0 优雅的 Material Design UI 组件库。Muse UI 拥有40多个UI 组件,用于适应不同业务环境。Muse UI 仅需少量代码即可完成主题样式替换。Muse UI 可用于开发的复杂单页应用
Muse-UI官网:https://muse-ui.org/#/zh-CN

11、N3-components UI组件库
N3组件库是基于Vue.js构建的,让前端工程师和全栈工程师能快速构建页面和应用。N3-components超过60个组件 组件列表、自定义样式、支持多种模化范式(UMD)、使用ES6进行开发。
N3官网:https://n3-components.github.io/N3-components/component.html

12、Mand Mobile
Mand Mobile是面向金融场景的Vue移动端UI组件库,丰富、灵活、实用,快速搭建优质的金融类产品,让复杂的金融场景变简单。Mand Mobile含有丰富的组件30+的基础组件,覆盖金融场景,极高的易用性组件均有详细说明文档、案例演示,汲取最前沿技术,组件化轻量化实现,兼顾稳定和品质,努力实现金融场景的全覆盖。
Mand Mobile官网:https://didi.github.io/mand-mobile/#/zh-CN/home

下面是1.x的文档和演示地址:(文档地址已经迁移了)

https://mand-mobile.github.io/1x-doc/
https://mand-mobile.github.io/2x-doc/

之前的地址打不开了

13、we-vue UI组件库
we-vue 是一套基于 Vue.js 的移动关组件库,结合 weui.css 样式库,封装了一系列组件,非常适于微信公众号等移动端开发。we-vue 包含35+ 个组件,单元测试覆盖率超 98%,支持 babel-plugin-import,完善的在线文档,详细的在线示例。
we-vue官网:https://wevue.org/

14、veui UI组件库
veui是一个由百度EFE team开发的Vue企业级UI组件库。目前文档还没有,只有demo。
GitHub上说是正在进行的一项工作。那我们就耐心等待吧。
veui官网:https://ecomfe.github.io/veui/components/#/

15、Semantic-UI-Vue UI组件库
Semantic-UI-Vue是基于 Vue.js对Semantic-UI 框架的实现。
Semantic作为一款开发框架,帮助开发者使用对人类友好的HTML语言构建优雅的响应式布局。Semantic-UI-Vue提供了一个类似于 Semantic-UI 的 API 以及一组可定制的主题。
Semantic-UI-Vue官网:https://semantic-ui-vue.github.io/#/
在选择框架的时候一定要根据实际Web开发情况和团队的熟悉程度来选择。一个好的UI组件库对一个Web项目来说很重要

16.Vue.js Material Component Framework — Vuetify.js

https://vuetifyjs.com/zh-Hans

Vuetify完全根据Material Design规范开发。每个组件都是手工制作的,为您的下一个伟大的应用程序带来最好的UI工具。开发并没有停留在Google规范中的核心组件上。通过社区成员和赞助商的支持,更多的组件将被设计并提供给大家享受。

这个主要是国外比较流行的vue ui组件,各种功能都有,有中文翻译的,但有些还是英文的,翻译得不是很好

PS:国内的UI组件大部分都只有一部分的,常用的头部导航,底部导航,listview,grid表格很多都是没有的。

参考链接


读取的XML节点中带有冒号怎么办?

昨天,编程读取XML的时候,遇上了类似下面的一段XML

起初没有特别的留意,于是乎就像平时读取XML一样使用了。

但是,运行报错,不允许传入冒号:之类的字符,后来查阅资料发现,节点中,冒号前的a代表是的命名空间,冒号后的才是根节点名称。在Root节点中,也对命名空间进行了声明 xmlns:a="http://ww.abc.com/" ,知道了这么一回事后,再来看看如何去读取,正确的读取是:

从代码可以看出,我声明了一个XNamespace类型的变量,并且把XML文件中出现的命名空间 http://ww.abc.com/ 赋值给它,然后再读取节点的时候,与真正的节点名称book进行拼接就可以了!

XML中出现命名空间的原因是,当你需要使用多个XML一起工作时,由于两个文档都包含带有不同内容和定义的节点元素,就会发生命名冲突,加上命名空间使用可以避免发生冲突,这与C#编程中类的命名空间的用处差不多。

另外,如果需要了解更多操作XML的可以访问下面这篇文章,写得很详细:

http://www.cnblogs.com/nsky/archive/2013/03/05/2944725.html

参考链接