首页 文章 精选 留言 我的

精选列表

搜索[学习],共10000篇文章
优秀的个人博客,低调大师

Android被逼学习小例子1

这个程序的功能就是当点击图片的时候,就会自动切换到下一个图片。对,就是这么简单的一个功能,高手请不要鄙视。 主要的代码如下: HelloWorldActivity.java代码为: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 package hello.com; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; import android.widget.LinearLayout; public class HelloWorldActivity extends Activity { /** Called when the activity is first created. */ int [] images = new int [] { R.drawable.ajax, R.drawable.java, R.drawable.ee, R.drawable.classic, R.drawable.xml, }; int currentImage = 0 ; @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.main); LinearLayout mainLayout = (LinearLayout) findViewById(R.id.root); final ImageView image = new ImageView( this ); mainLayout.addView(image); image.setImageResource(images[ 0 ]); image.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { if (currentImage >= 4 ) { currentImage = - 1 ; } image.setImageResource(images[++currentImage]); } }); } } main.xml代码为: 1 2 3 4 5 6 7 <? xml version="1.0" encoding="utf-8"?> < LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/root" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > </ LinearLayout > 其余的没多大变化,只是图片放在drawable-mdpi目录下面。 运行结果为: ============================================================================== 本文转自被遗忘的博客园博客,原文链接:http://www.cnblogs.com/rollenholt/archive/2012/05/16/2505357.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

ABP理论学习之多租户

本篇目录 什么是多租户 ABP中的多租户 什么是多租户 维基百科:“软件多租户是指一种软件架构,在这种软件架构中,软件的一个实例运行在服务器上并且为多个租户服务”。一个租户是一组共享该软件实例特定权限的用户。有了多租户架构,软件应用被设计成为每个租户提供一个专用的实例包括该实例的数据的共享,还可以共享配置,用户管理,租户自己的功能和非功能属性。多租户和多实例架构相比,多租户分离了代表不同的租户操作的多个实例。 多租户用于创建Saas(Software as-a service)应用(云处理)。有几种类型的多租户: 多部署-多数据库 这实际上不是多租户。但是,如果我们为每个具有分开数据库的客户(租户)运行该应用的一个实例,那么我们可以在单个服务器上为多个租户提供服务。我们可以确定该应用的多个实例在相同的服务器环境不会相互冲突。 这个对于一个不是为多租户设计的已存在应用也是可能的。创建这么一个应用更容易,因为该应用不需要了解多租户。但这种方式存在安装,使用和维护问题。 单部署-多数据库 在这种情况下,我们可以在一个服务器上运行应用的单个实例。对于每个登录用户,我们从master database中检测该用户的租户,并获得该租户的数据库信息(连接字符串)。然后我们可以将连接字符串存储到像session一样的变量中,同时,使用这个租户特定的连接字符串执行所有的数据库操作。 某种程度上,这样的应用应该设计成多租户。但是大多数的应用都独立于多租户。这种方式也存在一些安装,使用和维护问题。我们应该为每个租户创建并维护一个分离的数据库。 单部署-单数据库 这是最真实的多租户架构:我们只将具有单个数据库应用的单个实例部署到单个服务器上。在(RDBMS)每个表中,都存在一个TenantId(或相似)字段,该字段用于分离每个租户之间的数据。 这种方法安装和维护都很简单,但唯独创建这么一个应用很难,因为我们必须要阻止一个租户读取或写入其他租户的数据。我们可以为每个数据库的读取(select)操作添加一个TenantId过滤器。而且,我们可以在每次写入的时候检查一下该实体是否和当前的租户相关。这是乏味而易于出错的,但ABP通过使用自动的数据过滤帮助我们处理这个事情。 如果我们有很多具有大量数据的租户,那么这种方法可能会有性能问题。我们可以使用关系型数据库的表分割特征或者将租户按组分到不同的服务器上。 ABP中的多租户 ABP提供了创建单部署,单数据库,多租户架构的基础设施。 开启多租户 多租户默认是关闭的。我们可以在模块的PreInitialize方法中开启,如下所示: Configuration.MultiTenancy.IsEnabled = true; 租主vs租户 首先,我们应该定义多租户系统中的两个条目: 租主(Host):租主是单例的(只有一个租主)。租主会对创建和管理租户负责。因此,一个“租主用户”比所有的租户等级更高,并独立于所有租户,同时还能控制他们。 租户(Tenant):租主的一个客户,具有自己的用户角色,权限,设置等。每个租户都可以完全独立于其他租户使用应用。一个多租户应用会有一个或多个租户。如果是一个CRM应用,那么不同的租户也有它们自己的账户,契约,产品和订单。因此,当我们说“**租户用户”的时候,意思就是一个租户拥有的用户。 Session ABP定义了一个获取当前用户和租户id的IAbpSession接口。该接口用于多租户获取当前的租户id。因此,它可以基于当前的租户id过滤数据。ABP中有以下规则: 如果UserId和TenantId都是null,那么当前的用户没有登录到系统。因此,我们可以不知道当前用户是否是一个租主用户还是一个租户用户。在这种情况下,用户不能访问授权的内容。 如果UserId不是null,TenantId是null,那么当前用户是一个租主用户。 如果UserId不是null,TenantId也不是null,那么当前用户是租户用户。 更多关于session的信息请看后面的Session一节。 数据过滤器 当从数据库中检索实体时,我们必须添加一个TenantId过滤器来只获得当前的租户实体。当你为实体实现了IMustHaveTenant和IMayHaveTenant两个接口之一时,ABP会自动地完成数据过滤。 IMustHaveTenant接口 该接口通过定义TenantId属性来区分不同租户的实体。一个实现了IMustHaveTenant的实体例子如下: public class Product : Entity, IMustHaveTenant { public int TenantId { get; set; } public string Name { get; set; } //...其他属性 } 这样,ABP知道这是一个特定租户的实体,并且会自动地将一个租户的实体从其他实体中分离出来。 IMayHaveTenant接口 我们可能需要在租户和租户之间共享一个实体类型。因此,一个实体可能会被一个租户或租主拥有。IMayHaveTenant接口也定义了TenantId(类似于IMustHaveTenant),但在这种情况下是nullable。实现了IMayHaveTenant的一个实体例子: public class Role : Entity, IMayHaveTenant { public int? TenantId { get; set; } public string RoleName { get; set; } //...其他属性 } 我们可能会使用相同的Role类来存储租主角色和租户角色。这种情况下,TenantId表明这是一个租户实体还是一个租主实体。null值表示这是一个租主实体,非null值表示这被一个租户拥有,该租户的Id是TenantId。 IMayHaveTenant不像IMustHaveTenant一样常用。比如,一个Product类可以不实现IMayHaveTenant接口,因为Product和实际的应用功能相关,和管理租户不相干。因此,要小心使用IMayHaveTenant接口,因为它更难维护租户和租主共享的代码。 保存实体 一个租户用户不应该创建或编辑其他租户的实体。如果相关的数据过滤器开启了,那么ABP会检查该实体相对于数据库的改变。 想要获得更多关于数据过滤器的信息,请看后面关于数据过滤器的博客。 本文转自tkbSimplest博客园博客,原文链接:http://www.cnblogs.com/farb/p/ABPMultiTenancy.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

【NGN学习笔记】5 IMS技术

1.移动网络的发展--引子 20世纪80年代,商业性移动通信网络得到发展 第一代移动通信系统:TACS、NMT等模拟系统 第二代移动通信系统:GSM、IS-95、DECT、IS-136等数字系统,目前建设的2G移动网络使用两种主要技术,GSM网络使用TDMA技术,大约占70%,IS-95网络基于CDMA技术,大约占25%。 1992年开始对3G移动通信系统进行研究:R99、R4、R5、R6、R7、R8、R9…… 2G (GSM), 基于电路交换 2.5G (GPRS), 引入分组交换 3G时代的到来 1992年ETSI发起对即将到来的3G移动通信系统进行研究。采用2GHz附近的频率,支持多种空中接口: WCDMA——使用2GHz频谱的宽带码分多址接入 EDGE——用于GSM演进的增强数据传输速率 CDMA2000(1xRTT)——多载波SCDMA系统,用于在与IS-95相同的频带上建设CDMA网络 TD-SCDMA——由中国提出 支持分组数据业务,采用通用体系结构——UMTS(由3GPP负责制定),已有6个版本: 3GPP R99、R4、R5、R6、R7和R8 具体的: 3G (R99), 引入全新的UTRAN 3G (R4),电路域采用移动软交换 3G (R5), 引入IMS域 3G (R6),引入WLAN接入 3G (R7), 功能增强: CSI (Combination of CS and IMS services):研究如何将CS承载和IMS结合起来为用户提供统一的业务,CS传递实时业务,IMS分组域传递非实时业务 VCC (Voice Call Continuity):解决CS域和IMS之间语音业务切换的连续性问题 SMSIP: 研究如何通过IPCAN来提供短消息/多媒体消息业务 FBI: IMS如何支持固定接入,借鉴TISPAN的研究成果 LCS3: 如何在WLAN接入IMS的系统中提供定位业务 E2EQos: 研究端到端的Qos机制,研究IMS中计费和策略控制框架的合并 EC: 研究通过IMS如何提供紧急呼叫业务 2.IMS与现有通信系统之间的关系 标准化组织在IMS上的协作 3.IMS与软交换 IMS在3GPPRelease 5版本中提出,是对IP多媒体业务进行控制的网络核心层逻辑功能实体的总称。3GPP R5主要定义IMS的核心结构,网元功能、接口和流程等内容:R6版本增加了部分IMS业务特性、IMS与其他网络的互通规范和无线局域网(WLAN)接入特性等;R7版本加强了对固定、移动融合的标准化制订,要求IMS支持数字用户线(xDSL)、电缆调制解调器等固定接入方式。 软交换技术从1998年就开始出现并且已经历了实验、商用等多个发展阶段,目前已比较成熟。全球范围早已有多家电信运营商开展了软交换试验,发展至今,软交换技术已经具备了替代电路交换机的能力,并具备一定的宽带多媒体业务能力。在软交换技术已发展如此成熟的今天,IMS的出路在何方?又该如何发展和定位呢?首先需要对IMS和软交换进行较为全面的比较和分析。 如果从采用的基础技术上看,IMS和软交换有很大的相似性:都是基于IP分组网;都实现了控制与承载的分离;大部分的协议都是相似或者完全相同的;许多网关设备和终端设备甚至是可以通用的。 IMS和软交换最大的区别在于以下几个方面。 (1)在软交换控制与承载分离的基础上,IMS更进一步的实现了呼叫控制层和业务控制层的分离; (2)IMS起源于移动通信网络的应用,因此充分考虑了对移动性的支持,并增加了外置数据库——归属用户服务器(HSS),用于用户鉴权和保护用户业务触发规则; (3)IMS全部采用会话初始协议(SIP)作为呼叫控制和业务控制的信令,而在软交换中,SIP只是可用于呼叫控制的多种协议的一种,更多的使用媒体网关协议(MGCP)和H.248协议。 总体来讲,IMS和软交换的区别主要是在网络构架上。软交换网络体系基于主从控制的特点,使得其与具体的接入手段关系密切,而IMS体系由于终端与核心侧采用基于IP承载的SIP协议,IP技术与承载媒体无关的特性使得IMS体系可以支持各类接入方式,从而使得IMS的应用范围从最初始的移动网逐步扩大到固定领域。此外,由于IMS体系架构可以支持移动性管理并且具有一定的服务质量(QoS)保障机制,因此IMS技术相比于软交换的优势还体现在宽带用户的漫游管理和QoS保障方面。 3.IMS的特点和体系结构 1)特点: 采用分层的架构,便于网络演进和业务部署:接入层、承载层、会话控制层、业务应用层 接入无关性,提供优越的融合特性:核心功能与接入技术无关 基于SIP的会话控制,具备良好的多媒体业务支持能力 采用分布式开放性的体系结构,提供良好的可扩展性:开放的业务控制接口,拥有SIP的灵活和可扩展性 统一的用户数据管理(HSS) 归属网络服务控制,提供一致的用户通信体验 基于iFC(初始过滤规则)的业务触发机制,实现呼叫控制和业务逻辑的分离 2)分层体系结构: 3)功能实体简要归类 a)会话管理和路由类 服务呼叫会话控制功能S-CSCF 询问呼叫会话控制功能I-CSCF 代理呼叫会话控制功能S-CSCF b)数据库 归属用户服务器HSS 用户定位功能SLF c)网间配合实体 出口网关控制功能BGCF 媒体网关控制功能MGCF IP多媒体媒体网关功能IM-MGW 信令网关SGW d)服务 应用服务器AS 媒体资源控制功能 媒体资源处理功能 e)支撑实体 拓扑隐藏功能 THIG 安全网关SEG 策略决策功能 f)计费 4.功能实体详解 1)应用服务器 AS位于用户的归属网络或第三方网络 负责提供应用逻辑和应用的运行环境 处理和影响从IMS发来的SIP会话 发起SIP请求 发送计费信息给CCF和OCS 根据提供业务的方式不同,AS分三类 SIP AS:提供基于SIP的多媒体业务,如Presence OSA AS:由第三方提供基于OSA API开发的应用 CSE:提供传统的智能网业务 2)CSCF——Call Session Control Function IMS系统中完成呼叫控制功能的核心组件,主要功能:信令路由,会话管理,资源分配,安全认证,业务触发,计费控制。 a)P-CSCF:代理呼叫会话控制功能 IMS系统中用户的第一个接触点,主要功能: 作为SIP Proxy,在UE和S/I-CSCF间转发SIP请求和响应信令消息 异常会话释放/注册时,充当SIP UA发起SIP事务 检测紧急会话 向CCF(计费采集功能)提供计费信息 SIP信令完整性和机密性保护 SIP消息的压缩和解压 向S-CSCF订阅注册事件包 执行媒体监管 维护会话计时器 b)I-CSCF:问询呼叫会话控制功能 运营商归属网络中为所有连接到该运营商网络的用户的连接提供的一个联系点,主要功能: 注册阶段指定S-CSCF 获取S-CSCF的名字 前转SIP消息和响应给S-CSCF 向CCF提供计费信息 拓扑隐藏功能 c)S-CSCF:服务呼叫会话控制功能 IMS的核心所在,位于归属网络,提供注册和呼叫控制服务,主要功能: 注册服务功能 基于AKA的认证 从HSS下载用户信息和业务数据 消息路由和转发 会话控制功能 与业务平台交互 E.164号码与SIP URI之间的转换 维护会话计时器、执行媒体监管、支持紧急呼叫 向CCF或OCS提供计费信息 d)HSS:归属用户服务器 IMS中所有与用户和业务相关数据的主要存储器,主要数据包括:用户身份、注册信息、接入参数、业务触发信息。 HSS功能包括三部分: IMS功能 CS域HLR/AUC功能 PS域HLR/AUC功能 e)MRF:媒体资源功能,多用于多方会话 MRFC:媒体资源功能控制器--对IMS域内部的媒体资源进行控制,通过H.248协议维护、控制MRFP中的媒体资源,与S-CSCF交互,间接接受AS的控制,向CCF或OCS提供计费信息。 MRFP:媒体资源功能处理器--对IMS域内部的媒体资源进行处理,接受MRFC的控制:H.248,完成对媒体流的编解码、转换、混合和播放等功能。 f)网关功能 BGCF:外出网关控制功能--负责在IMS与PSTN/CS域互通时候选择到CS域的出口的位置,即选择MGCF或BGCF MGCF:媒体网关控制功能--IMS用户与CS用户互通的控制网关,控制IMS-MGW中媒体信道的连接,选择CSCF,进行协议转换:SIP与ISUP,并与SGW交互 IMS-MGW:IMS媒体网关功能--在IMS与CS间提供用户平面链路,在MGCF的控制下,完成媒体协议转换、回声消除、转码等功能 SGW:信令网关--SIP与SS7之间的转换,支持SIGTRAN 5.参考点 ISC:S-CSCF与AS平台之间,提供IMS业务控制机制的重要接口,基于SIP协议,传送AS提供的业务相关的SIP消息。 Cx:CSCF与HSS之间,提供S-CSCF分配、路由查询、认证授权、业务过滤控制等功能,基于Diameter协议。 Gm:UE与P-CSCF之间,基于SIP协议,完成注册、呼叫控制、事务处理等功能。 Mw:CSCF与CSCF之间,基于SIP协议,完成注册、呼叫控制、事务处理等功能。 Mg:MGCF与CSCF之间,基于SIP协议,负责将边缘功能MGCF连接到IMS上。 Mr:CSCF与MRFC之间,基于SIP协议,支持S-CSCF与MRFC之间的交互,是IMS域内实现多方会议的通道。 Mp:MRFC与MRFP之间,MRF内部通道,兼容H.248/Megaco,支持MRFC对MRFP提供的资源的控制。 Mn:MGCF与IMS-MGW之间,采用H.248,用于控制用户平面资源。 Mi:CSCF与BGCF之间,基于SIP协议,是IMS域内部与CS域互通的通道。 Mj:BGCF与MGCF之间,基于SIP协议,是IMS内部与CS域互通的通道。 Sh:HSS与AS(SIP AS及OSA AS)之间,基于Diameter协议,完成数据处理、订购通知。 Si:HSS与CAMEL SE之间,采用MAP协议,传输CAMEL订购关系信息。 6.IMS的主要协议 主要是SIP,SDP,H.248/Megaco,Diameter。 1)IMS对SIP的扩展 SIP压缩:SigComp 安全 CSCF路由 网络发起的呼叫释放 RFC3455定义了专用于3GPP IMS的SIP头 P-Charging-Vector P-Charging-Function-Address P-Visited-Network-ID P-Access-Network-Info P-Associated-URI 2)Diameter协议 Diameter是IETF开发的用于认证、授权和计费(AAA)的协议,基于远程拨入用户认证服务(RADIUS)协议构建而成。 Diameter基本协议基于RFC3588,客户/服务器协议,传递Diameter数据单元、协商能力集、处理错误并提供可扩展性,基于TCP或SCTP进行传输。 Diameter应用:定义了特定应用的功能和数据单元,有Diameter移动IP应用和Diameter SIP应用,应用于IMS系统。 3)Diameter SIP应用 定义了一个被SIP服务器用来实现对不同SIP资源进行授权的应用。 应用的接口: Cx:I/S-CSCF与HSS之间 Dx:SLF与I-CSCF之间 Sh:HSS与SIP AS及OSA AS之间 Dh:SLF与AS之间 命令: 7.IMS标识 1)IMS用户标识:私有用户身份和公共用户身份 a)私有用户身份: 由归属网络运营商定义的具有唯一性的全球身份,可用于在归属网络中从网络的角度唯一地标识用户。私有用户身份并不是标识用户本身,而是标识了用户与运营商的订购/签约关系,主要用于注册过程中对用户进行认证,也可以用于计费和管理目的。存储在ISIM (身份模块) 应用中,采用NAI (网络接入标识符) 的形式:form_user@realm。 b)公共用户身份: IMS网络中的用户身份,用于请求与其他用户进行通信时使用的身份,可以被公布到号码簿、主页等上,ISIM中至少要存储一个公共用户身份。通过注册过程在网络中注册,网络不对公共用户身份进行认证,公共用户身份的两种形式:SIP URI sip:joe.doer@rims.example.com 、 tel URL tel:+358 50 1234567。 公共用户身份与私有用户身份之间的关系: c)公共业务身份: 公共业务身份,对AS提供的业务进行标识,由用户根据需要在AS中创建,使用之前不需要进行注册。采用SIP URI形式,如标识消息列表业务的公共业务身份:sip:messagelist_joe@ims.example.com d)网络实体标识: 处理SIP路由的网络节点通过SIP URI标识,例子: sip:finland.scscf@ims.example.com。 2)IMS身份模块——ISIM ISIM是位于UICC上的应用,用于存储由运营商提供的IMS专用数据。 8.IMS的业务控制机制 1)IMS 用户配置 用户与运营商确定订购关系时,由运营商给用户分配IMS用户配置,永久存储在HSS中。 2)初始过滤规则 初始过滤规则用来表示业务触发信息,描述了S-CSCF何时将到来的SIP消息进一步路由到一个特定的应用服务器。 初始过滤规则的创建: 初始过滤规则在用户获得IMS订购关系时创建 创建初始过滤规则需要考虑的问题:触发点是什么?当触发点被匹配时,正确的AS是什么?各初始过滤规则的优先级是什么?如果应用服务器没有应答,应该怎么做? 初始过滤规则的结构: 3)IMS业务提供 IMS本身不是业务,而是基于SIP的控制体系,IMS业务触发由S-CSCF完成。IMS为业务的提供提供了必要的方法,包含3个步骤: 定义可能的业务或业务集 在用户注册时,以初始过滤规则的形式创建用户特定的业务配置数据 根据业务配置数据中的初始过滤规则将到达S-CSCF的SIP请求转发给AS 4)AS的选择与AS的行为 AS的选择(业务控制):S-CSCF下载初始过滤规则,注册阶段完成;S-CSCF进行业务控制,选择AS;存在多个过滤规则时,需要进行多次业务控制。 AS的可能行为:UAC、UAS、Proxy Server、Redirect Server、B2BUA。 9.IMS的典型流程 1)P-CSCF的发现 a)使用DHCP和DNS发现P-CSCF:IP-CAN作为DHCP中继代理,通过DHCP机制给出P-CSCF的域名或IP地址 b)使用PDP上下文激活信令发现P-CSCF 2)用户注册/注销 注册:特点是归属域注册,注册前后及注册期间的信息存储: a)用户初始注册: b)用户刷新注册/注销: c)隐性注册 通过一次注册过程注册多个公共用户身份的机制。需先在HSS中定义隐性注册集,通过订阅/通知机制,UE可以获得隐性注册的公共用户身份。 d)多个UE共享单个公共用户身份进行通信 前提:IMS支持多个UE注册相同的公共用户身份 多个UE共享单个公共用户身份的方法: 基于用户定义的优先级 基于SIP的Forking机制(顺序、并行) 3)会话建立 漫游移动发起端MO: 归属移动发起端MO: 漫游移动终止端MT: 归属移动终止端MT: 4)会话建立(S-CSCF到S-CSCF) a)会话的发起和终止由不同的网络运营商来服务 b)会话的发起和终止由相同网络运营商来服务 c)IMS会话建立 d)PSTN->IMS e)IMS-> PSTN 附:IMS典型网络互通架构 网络类型1:演进ISP 提供电话、VoD和标准ISP业务,通过热点也完成对无线的接入,所有的业务最终都由IMS进行控制。 网络类型2:传统电信运行商 其中一部分是软交换与PSTN互通,其中的应用服务器可以被其他网络结构使用。 网络类型3:3GPP移动网络 主要是接入方式的不同,GERAN或UTRAN。 网络类型4:WIMAX 这里没有IMS域,它是由一些SIP服务器等完成相应功能的。 以下是摘自http://blog.ixpub.net/html/96/12690296-146875.html的一篇关于IMS和软交换的对比,写的不错: 一、业务提供方式对比 1.软交换业务架构 由于软交换并未完全实现业务与控制的分离,因此传统的基本业务和一些补充业务仍然是通过软交换来实现(方式一)。但对于更多的增值业务,软交换还提供了多种方式进行业务提供,如图1所示。 图1软义换多方式业务提供示意图 方式二:智能网业务方式。业务逻辑在SCP中驻留和运行,软交换设备实现业务交换功能(SSP)触发智能业务到智能网SCP,与SCP配合实现智能网提供的业务。 方式三:SIP应用服务器方式。由运营商提供SIP应用服务器,其中的业务逻辑可直接访问和控制软交换设备提供的网络能力,通常实现运营商的自营业务。 方式四:第三方应用服务器方式。由运营商或者第三方服务提供商提供Parlay应用服务器,而运营商提供业务能力网关,Parlay应用服务器中的业务逻辑通过业务能力网关间接访问和控制软交换设备提供的网络能力,多用于运营商与第三方合作的业务,也可用于运营商自营业务。 2.IMS业务架构 在IMS系统中,实现了业务与控制的完全分离,所有的业务都是通过应用服务器来提供的,业务逻辑驻留于应用服务器中,用户数据统一存储在HSS,如图2所示。图中的应用服务器包括三类:SIP应用服务器,OSA应用服务器及IM-SSF。SIP应用服务器(SIP AS)用于实现基于SIP的增值应用;SIP/OSA应用服务器(SIP/OSA AS)通过OSA业务能力服务器(OSA SCS)与IMS核心网进行交互;而IM-SSF用于支持IMS用户使用现有智能网的能力。目前IM-SSF支持使用CAMEL的业务能力,为考虑固定网络的智能网业务,IM-SSF的功能可以扩展到对INAP的支持。 图2IMS业务架构 在这一架构中,IMS的核心网元S-CSCF只通过ISC接口与应用平台交互,从而使得业务接口和触发方式得以标准化,进而获得更好的开放性。对三种应用服务器的具体应用如下: (1)基于SIP的应用服务器(SIP AS) SIP应用服务器和S-CSCF之间直接利用SIP及其扩展的呼叫信令协议,因此不需要进行呼叫信令协议之间的转换工作。另外由于基于SIP可以非常方便的实现语音、数据以及视频等多媒体类的会话,因此基于SIP的应用服务器可以高效率的提供各种新型的融合业务。 (2)基于OSA的应用服务器(OSA SCS) 在对第三方应用方面,IMS采用Parlay/OSA API。在Parlay/OSA API中,提供给应用的网络功能实体被定义为若干业务能力特征(SCF)的集合,由业务能力服务器(SCS)支持,这些SCF为应用开发提供了必要的网络接入功能。第三方应用服务器通过Parlay/OSA API和SCS相连接,而OSA SCS则在第三方应用服务器和S-CSCF之间负责API和ISC之间的映射。 (3)基于智能网的业务服务器(IM-SSF) 现有的移动智能网以及固定智能网都已经提供了丰富的智能网业务,并且有着庞大的用户群,为了兼容已有的网络资源,实现技术和服务提供的平滑过渡,IMS需要接入现有的智能网,并且还可以实现将现有智能网的业务延伸到IMS用户。目前通过IM-SSF接入现有移动智能网CAMEL已经完备。从CAMEL角度来看,IM SSF是智能网的服务交换节点SSP,相当于CAMEL中业务交换功能SSF和呼叫控制功能CCF。IM SSF在S-CSCF和CAMEL之间实现SIP消息和CAP信令的映射。为支持固定智能网,IM-SSF需要支持INAP协议,相关的研究还正在进行中。 从上面的分析可以看出,软交换和IMS都可以实现智能网提供业务和应用服务器提供业务,并且都可以开放接口给第三方使用,供第三方开发业务。但是由于软交换与不同的业务平台之间采用的接口不同,而IMS则统一采用ISC接口,另外对于IMS,由于3GPP,OMA等组织形成了大量的基于应用服务器的业务规范,并可以作为业务引擎,供其他的业务调用。因此IMS在业务提供的方便性、灵活性以及扩展性等方面都显示出了优势。 二、业务触发机制对比 1.软交换触发机制 软交换触发机制有两类: (1)基于智能网的触发机制 软交换可作为SSP,根据用户的主叫属性以及被叫属性(DP点触发)完成业务触发,在SCP或者应用服务器的智能业务逻辑控制下实现智能业务。 (2)基于应用服务器的触发机制 根据用户的profile或呼叫相关信息触发到应用服务器。应用服务器提供标准接口与前端服务器连接,接受来自前端服务器的业务触发信息和交互业务处理过程的信息。业务触发信息可能包括鉴权信息(如主叫号码、账号、密码)、发起方主机IP地址、被叫号码、业务标识、业务配置信息。 2.IMS触发机制 IMS的业务触发机制是基于iFC(Initial Filter Criteria)实现的。业务的触发在S-CSCF中完成,业务数据在注册阶段从HSS中下载到S-CSCF中,包括Initial Filter Criteria。在收到用户会话请求后,S-CSCF首先检查Initial Filter Criteria中的触发标准是否满足,然后再进行到用户的路由和呼叫控制。如果满足则通过ISC接口的SIP消息,将业务触发到对应的业务平台。业务平台然后根据业务的既定逻辑流程,通过SIP消息对S-CSCF中的业务进行后续控制。 从上述分析可以看出,软交换的业务触发机制表现为多样性,既有基于传统智能网模式的又有基于用户业务数据的。而对于基于应用服务器的业务,软交换与IMS的业务触发机制有很多的相似之处,但由于软交换在标准化方面的局限性,造成了业务触发方面无法规范化,也就决定了其在实际应用中只能由设备供应商自行提供解决方案。相比较,IMS就提供了比较完善的标准化,从而使得业务实现和互通更加规范统一。 三、业务实现流程对比 尽管基于软交换和基于IMS都可以提供宽带多媒体类的业务,但由于软交换在提供宽带多媒体业务方面缺乏相关的规范,因此现有的各种业务多是厂家基于自己的平台进行开发的,并对协议进行了私有扩展,业务之间的互通性较差。而在IMS网络架构下,由于IMS的业务规范好,各种部件的标准化程度高,因此业务之间的互通性好。下面以目前最常用的即时消息(IM)和状态呈现(Presence)两种业务的流程说明其区别: 1.基于软交换的业务流程示例 以国内某主流软交换提供厂商为例,在其基于软交换实现宽带多媒体业务时,用户与业务应用服务器采用HTTP和SIP两种消息的进行交互。对于数据业务采用HTTP协议,用户可使用Web客户端,最大程度实现业务的可达性,另外可通过HTTPS,实现安全的传输机制。对于媒体业务采用SIP,完成与呼叫相关的业务处理。为完成用户与应用服务器之间消息的实时传送,该厂商对HTTP协议进行了修改,实现用户Web浏览器与应用服务器之间建立一条持续的HTTP连接(Persistent HTTP connection)。采用这种方式实现即时消息和状态通知的流程如图3、4所示: 图3基于软交换的业务流程示意:即时消息 图4基于软交换的业务流程示意:状态通知 2.基于IMS的业务流程示例 对于基于IMS提供的业务,由于目前业务的标准化程度高,特别是IMSinOMA Enabler规范的实施,更好的协调了OMA与3GPP/3GPP2的IMS之间的合作关系,目前已经发布了Presence,PoC,XDMS等一系列符合IMSinOMA框架的规范,成为业界遵循的标准。例如对于即时消息,在SIP消息中定义了Message消息可以直接用于即时消息的传递,具体流程如图5所示: 图5基于IMS的业务流程示意:即时消息(Page-Mode) 对于Presence业务,则规定了状态订阅使用SIP的SUBSCRIBE消息,状态更新使用SIP的PUBLISH消息,状态更新通知使用SIP的NOTIFY消息。如果用户的状态有更新,则通过PUBLISH消息更新自己的状态信息到Presence服务器;用户希望知道好友的状态,需要首先到Presence服务器订阅好友的状态,Presence服务器对用户进行权限检查,如果好友允许该用户知道自己的状态信息,好友的状态变化后,Presence服务器再把状态变化信息通知给用户。业务流程如下面的图6、7所示: 图6基于IMS的业务流程示意:发布状态(Publish) 图7基于IMS的业务流程示意:订阅/通知状态变化(Subscriber/Notify) 因此从业务流程上可以看出,尽管基于软交换与基于IMS都使用了SIP协议,但在使用的信令消息上有一定的区别。另外在具体的信令消息参数上也有所不同 本文转自gnuhpc博客园博客,原文链接:http://www.cnblogs.com/gnuhpc/archive/2012/12/11/2813494.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

学习OpenStack之 (1):安装devstack

1. 系统准备 ubuntu 12.04 server 虚拟机。 2G内存。 依次运行以下命令来安装git: sudo apt-get update sudo apt-get upgrade sudo apt-get install git 2. 下载安装包 $gitclonehttps: //github .com /openstack-dev/devstack .git #克隆devstack的Git代码仓库 3. 配置 从2013/10起OpenStack引入新的配置方式即使用配置文件 local.conf。从官方网站看这个文件应该存在于devstack目录中,找了后发现在samples目录中。创建 local.conf包含下面内容: [[local|localrc]] ADMIN_PASSWORD=secrete #Admin密码 DATABASE_PASSWORD=$ADMIN_PASSWORD //预设密码,这样在运行stack.sh的时候就不会要求输入密码 RABBIT_PASSWORD=$ADMIN_PASSWORD //同上 SERVICE_PASSWORD=$ADMIN_PASSWORD //同上SERVICE_TOKEN=a682f596-76f3-11e3-b3b2-e716f9080d50其他可使用配置项:安装路径: 默认: DEST=/opt/stack 示例:DEST=/opt/mystack 屏幕输出目录: 默认只是console输出:SCREEN_LOGDIR=”“ 示例:SCREEN_LOGDIR=$DEST/logs/screen #输出到文件,每个screen输出用时间戳命名的一个文件日志:默认: ``LOGFILE=”” LOGDAYS=7 LOG_COLOR=True`` //日志相关。默认日志仅在console输出 示例local.conf文件: [[local|localrc]] LOGDAYS=1 LOGFILE=$DEST/logs/stack.sh.log SCREEN_LOGDIR=$DEST/logs/screen ADMIN_PASSWORD=1111 DATABASE_PASSWORD=$ADMIN_PASSWORD RABBIT_PASSWORD=$ADMIN_PASSWORD SERVICE_PASSWORD=$ADMIN_PASSWORD SERVICE_TOKEN=a682f596-76f3-11e3-b3b2-e716f9080d50 4. 以非root用户运行以下命令 cd devstack ./stack.sh 注意: 1. 不可以使用root用户运行该命令,可使用 /devstack/tools/create-stack-user.sh命令创建一个用户,比如stack 2. 保证该用户下sudo可以免密码运行,否则脚本执行过程中会出现权限问题 方法:修改/etc/sudoers, 在行root ALL=(ALL:ALL) ALL后添加stack ALL=(ALL) ALL然后保存文件 遇到的一些问题及解决办法: 1. 网速太慢,git clone失败 要么用网速快的机器;要么找一个已经装好devstack的机器,将/opt/stack所有文件拷贝到你的环境中,必要的话将git clone全部注释掉,再运行stack.sh 2. 一些依赖的包没有安装,比如下面的mysql-server-5.5:在ubuntu上装上这些包重新运行stack.sh即可 Reading package lists... Building dependency tree... Reading state information... Some packages could not be installed. This may mean that you have requested an impossible situation or if you are using the unstable distribution that some required packages have not yet been created or been moved out of Incoming. The following information may help to resolve the situation: The following packages have unmet dependencies: mysql-server : Depends: mysql-server-5.5 but it is not going to be installed E: Unable to correct problems, you have held broken packages. 成功: Horizon is now available at http://9.*.236.90/ Keystone is serving at http://9.*.236.90:5000/v2.0/ Examples on using novaclient command line is in exercise.sh The default users are: admin and demo The password: 1111 This is your host ip: 9.*.236.90 stack.sh中的执行顺序: 支持OS类型包括Ubuntu 12.04或以上;Fedora F18或以上 禁止使用root运行 读取local.conf 检查stackrc文件是否存在 检查Devstack是不是已经在运行。如果在运行,则退出 配置目标安装目录,包括创建目录,设置权限 配置hostname,logging等 读取各组件的安装和启动script 如果没有配置密码,则需要用户输入各密码 配置数据库 配置Keystone 安装各pre-condition包 安装client包 安装和配置keystone,swift,glance,cinder,neutron,nova,horizon,ceilometer,heat,CA 配置数据库 配置screen 创建个组件使用的账号 初始化和启动horizon 启动swift,glance, 安装images 启动swift,nova_api,neutron,nova,cinder,ceilometer,heat 5. 在浏览器中输入 http://9.*.236.90/ 打开dashboard, 用admin和1111登录 参考: http://docs.openstack.org/developer/devstack/configuration.html 6. 重启机器后重新run OpenStack:执行rejoin_stack.sh screen语法,执行完rejoin_stack.sh后,需要使用screen语法来控制openstack的进程 帮助 ctrl+a+? 查看screen导航 ctrl+a+" 注需要使用shift键 退出screen,有两种方法: 方法1:attach screen ctrl+a+d 方法2:exit screen ctrl+a+K 查看下一个screen ctrl+a+n 查看上一个screen ctrl+a+p 保存screen的日志到文件 ctrl+a+H,再按一次停止保存。 查看screen [root@cheeliang ~]# screen -ls There is a screen on: 2678.stack (Attached) 1 Socket in /var/run/screen/S-root. 重连接Re-attach screen screen -r 2678 本文转自SammyLiu博客园博客,原文链接:http://www.cnblogs.com/sammyliu/p/4136466.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

MongoDB权威指南学习笔记01

章节:第一章 简介 时间:2013-07-18 内容: 丰富的数据模型 面向文档的数据库,非关系型数据库,是为了获得更加方便的扩展性 面向文档的方式可以将文档或者数据内嵌进来,所以用一条记录就可以表示非常复杂的层次关系 MongoDB没有模式,文档的键不会事先定义也不会固定不变 容易扩展 面向文档的数据模型使其可以自动在多台服务器之间分割数据 还可以平衡集群的数据和负载,自动编排文档 丰富的功能 索引:支持通用辅助索引,也提供唯一的、复合的地理空间索引能力 存储Javascript:不必使用存储过程 聚合:支持MapReduce和其它聚合工具 固定集合:集合的大小是有上限的,对某些类型的数据(如日志)特别有用 文件存储:支持用一种容易使用的协议存储大型文件和文件的元数据 某些关系型数据库的功能并不具备,如联接(join)和复杂的多行事务 不牺牲速度 使用MongoDB传输协议作为与服务器交互的主要方式(与之对应的协议需要更多的开销,如HTTP/REST) 对文档进行动态填充,预分配数据文件,用空间换取性能的稳定 默认的存储引擎中使用了内存映射文件,将内存管理工作交给操作系统去处理 动态查询优化器会记住执行查询最高效的方式 简便的管理 让服务器自治来简化数据库管理 本文转自 xxrenzhe11 51CTO博客,原文链接:http://blog.51cto.com/xxrenzhe/1252217,如需转载请自行联系原作者

优秀的个人博客,低调大师

【Android进阶学习】Popupwindow的应用

PopupWindow 是一种阻塞式的弹出窗口,这就意味着在我们退出这个弹出框之前,程序会一直等待。它可以浮动在当前Activity的任何的位置上。 需要注意的是,PopupWindow必须触发某个焦点或者某个事件才会显示出来,不然总会会出现错误。 下面是使用PopupWindow 弹出自定义菜单的例子 当我们点击Menu键的时候,会在当前的Activity最下方弹出一个菜单。 效果图如下: PopupMenuDemo.java packagecom.lingdududu.popupWindow; importandroid.app.Activity; importandroid.content.Context; importandroid.graphics.drawable.BitmapDrawable; importandroid.os.Bundle; importandroid.view.Gravity; importandroid.view.KeyEvent; importandroid.view.LayoutInflater; importandroid.view.Menu; importandroid.view.MenuItem; importandroid.view.View; importandroid.view.ViewGroup; importandroid.widget.BaseAdapter; importandroid.widget.GridView; importandroid.widget.ImageView; importandroid.widget.LinearLayout; importandroid.widget.PopupWindow; importandroid.widget.TextView; importandroid.widget.LinearLayout.LayoutParams; publicclassPopupMenuDemoextendsActivity{ privateint[]resArray=newint[]{ R.drawable.icon_menu_addto,R.drawable.icon_menu_audioinfo, R.drawable.icon_menu_findlrc,R.drawable.icon_menu_scan }; privateString[]title=newString[]{ "添加","信息","搜索","查看" }; privatePopupWindowpw=null; /**Calledwhentheactivityisfirstcreated.*/ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override publicbooleanonCreateOptionsMenu(Menumenu){ menu.add(""); returnsuper.onCreateOptionsMenu(menu); } /** *在此方法中实现自定义菜单栏 */ publicbooleanonMenuOpened(intfeatureId,Menumenu){ if(pw!=null){ if(pw.isShowing()){ //就关闭弹出窗口 pw.dismiss(); } else{ //在指定位置弹出窗口 pw.showAtLocation(findViewById(R.id.tv),Gravity.CENTER,0,300); } } else{ LayoutInflaterinflater=(LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); Viewview=inflater.inflate(R.layout.menu,null); GridViewgrid1=(GridView)view.findViewById(R.id.menuGridChange); grid1.setAdapter(newImageAdapter(this)); //生成PopupWindow对象 pw=newPopupWindow(view,LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT); //在指定位置弹出窗口 pw.showAtLocation(findViewById(R.id.tv),Gravity.CENTER,0,300); } //此处返回false,系统不会执行onCreateOptionsMenu中添加的菜单 returnfalse; } publicbooleanonKeyDown(intkeyCode,KeyEventevent){ if(keyCode==KeyEvent.KEYCODE_BACK){ pw.dismiss(); returnfalse; } returnsuper.onKeyDown(keyCode,event); } @Override publicbooleanonOptionsItemSelected(MenuItemitem){ returnsuper.onOptionsItemSelected(item); } publicclassImageAdapterextendsBaseAdapter{ privateContextcontext; publicImageAdapter(Contextcontext){ this.context=context; } @Override publicintgetCount(){ returnresArray.length; } @Override publicObjectgetItem(intarg0){ returnresArray[arg0]; } @Override publiclonggetItemId(intarg0){ returnarg0; } @Override publicViewgetView(intarg0,Viewarg1,ViewGrouparg2){ LinearLayoutlinear=newLinearLayout(context); LinearLayout.LayoutParamsparams=newLayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT); linear.setOrientation(LinearLayout.VERTICAL); ImageViewiv=newImageView(context); iv.setImageBitmap(((BitmapDrawable)context.getResources().getDrawable(resArray[arg0])).getBitmap()); LinearLayout.LayoutParamsparams2=newLayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT); params2.gravity=Gravity.CENTER; linear.addView(iv,params2); TextViewtv=newTextView(context); tv.setText(title[arg0]); LinearLayout.LayoutParamsparams3=newLayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT); params3.gravity=Gravity.CENTER; linear.addView(tv,params3); returnlinear; } } } main.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/tv" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> </LinearLayout> menu.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/tv" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> </LinearLayout> menu_bg_frame.xml 这个文件是菜单背景的样式文件,在drawable-hdpi文件下面 <?xmlversion="1.0"encoding="UTF-8"?> <shapeandroid:shape="rectangle"xmlns:android="http://schemas.android.com/apk/res/android"> <solidandroid:color="#b4000000"/> <strokeandroid:width="2.0dip"android:color="#b4ffffff"android:dashWidth="3.0dip"android:dashGap="0.0dip"/> <paddingandroid:left="7.0dip"android:top="7.0dip"android:right="7.0dip"android:bottom="7.0dip"/> <cornersandroid:radius="8.0dip"/> </shape> 本文转自 lingdududu 51CTO博客,原文链接: http://blog.51cto.com/liangruijun/739459

优秀的个人博客,低调大师

Android开发学习笔记:浅谈ListView

LisView列表视图是Android开发中非常常用的一种视图组件,它是以垂直列表的方式列出需要显示的列表项。 创建ListView可以用ListView组件,也可以继承ListActivity。在使用过程中最重要的是如何设置ListView显示的内容,也就是怎样设置Adapter。Adapter类型可以分为三种:ArrayAdapter,SimpleCursorAdapter和SimpleAdapter。下面介绍这三种Adapter是如何添加列表视图内容的: 一.ArrayAdapter ArrayAdapter是这三种Adapter最简单的,只能展示一行文字,使用它来添加ListView显示的内容的步骤如下: 1.创建ArrayAdapter 2.调用ListActivity的setListAdapter( )方法来设置显示的内容 下面是具体的例子: MainActivity.java packagecom.android.listview1.avtivity; importandroid.app.ListActivity; importandroid.os.Bundle; importandroid.widget.ArrayAdapter; publicclassMainActivityextendsListActivity{ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); //列表项的数据 String[]strs={"Android","IOS","Mango","MeeGo","Symbian"}; //this,布局文件 //android.R.layout.simple_list_item_1,系统定义的布局文件 //strs,数据来源 ArrayAdapter<String>adapter=newArrayAdapter<String>(this, android.R.layout.simple_list_item_1, strs); //为ListView设置适配器 setListAdapter(adapter); } } 效果图: 二.SimpleCursorAdapter SimpleCursorAdapter从游标得到的数据进行列表显示,并可以把指定的列映射到对应的TextView中。下面是使用它来显示Android中的联系人姓名的步骤: 1.调用getContentResolver( )方法返回ContentResolver( )对象,通过该对象查询得到Cursor对象 2.创建SimpleCursorAdapter对象 3.调用ListActivity的setListAdapter( )方法显示列表项 下面是具体的例子: MainActivity.java packagecom.android.listview2.activity; importandroid.app.ListActivity; importandroid.database.Cursor; importandroid.os.Bundle; importandroid.provider.Contacts.People; importandroid.widget.ListAdapter; importandroid.widget.SimpleCursorAdapter; publicclassMainActivityextendsListActivity{ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); //获得一个指向系统通讯录数据库的Cursor对象获得数据来源 Cursorcur=getContentResolver().query(People.CONTENT_URI,null,null,null,null); startManagingCursor(cur); //实例化列表适配器 ListAdapteradapter=newSimpleCursorAdapter(this, android.R.layout.simple_list_item_1, cur, newString[]{People.NAME},//含数据库的列的String型数组 newint[]{android.R.id.text1});//包含布局文件中对应组件id的int型数组 //为ListView设置适配器 setListAdapter(adapter); } } 在AndroidManifest.xml文件中添加17行的声明 <?xmlversion="1.0"encoding="utf-8"?> <manifestxmlns:android="http://schemas.android.com/apk/res/android" package="com.android.listview2.activity" android:versionCode="1" android:versionName="1.0"> <uses-sdkandroid:minSdkVersion="10"/> <applicationandroid:icon="@drawable/icon"android:label="@string/app_name"> <activityandroid:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <actionandroid:name="android.intent.action.MAIN"/> <categoryandroid:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> <uses-permissionandroid:name="android.permission.READ_CONTACTS"></uses-permission> </manifest> 效果图: 三.SimpleAdapter SimpleAdapter可以定义各种不同的布局,可以添加ImageView(图片),Button(按钮),CheckBox(复选框)等。 下面是添加图片的例子: MainActivity.java packagecom.android.listview3.activity; importjava.util.ArrayList; importjava.util.HashMap; importjava.util.List; importjava.util.Map; importandroid.app.ListActivity; importandroid.os.Bundle; importandroid.widget.SimpleAdapter; publicclassMainActivityextendsListActivity{ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); SimpleAdapteradapter=newSimpleAdapter(this,getData(), R.layout.main,//设置界面布局 newString[]{"title","img"},//列表上的文字信息,图片信息 newint[]{R.id.title,R.id.img});//引用文字资源,图片资源 //布局文件的各组件分别映射到HashMap的各元素上,完成适配 //为ListView设置适配器 setListAdapter(adapter); } privateList<Map<String,Object>>getData(){ //map.put(参数名字,参数值) List<Map<String,Object>>list=newArrayList<Map<String,Object>>(); Map<String,Object>map=newHashMap<String,Object>(); map.put("title","摩托罗拉"); map.put("img",R.drawable.pic1); list.add(map); map=newHashMap<String,Object>(); map.put("title","诺基亚"); map.put("img",R.drawable.pic2); list.add(map); map=newHashMap<String,Object>(); map.put("title","三星"); map.put("img",R.drawable.pic3); list.add(map); returnlist; } } main.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ImageView android:id="@+id/img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="5px" /> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#ffffff" android:textSize="20px" /> </LinearLayout> 效果图: 注:上面的程序很多地方用到泛型编程,有关Java泛型编程的资料请看: http://liangruijun.blog.51cto.com/3061169/636850 http://www.cnblogs.com/panjun-Donet/archive/2008/09/27/1300609.html 本文转自 lingdududu 51CTO博客,原文链接: http://blog.51cto.com/liangruijun/646049

优秀的个人博客,低调大师

Swift UI学习UITableView and protocol use

Models: UserModel.swift Views: UserInfoCell.swift Controllers: RootViewController.swift, DetailViewController.swift AppDelegate.swift: import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary? ) -> Bool { self.window = UIWindow(frame: UIScreen.mainScreen().bounds) // let rootController = RootViewController(style: UITableViewStyle.Plain) let rootNav = UINavigationController(rootViewController: rootController) self.window!.rootViewController = rootNav // self.window!.backgroundColor = UIColor.whiteColor() self.window!.makeKeyAndVisible() return true } } UserModel.swift import Foundation // // @brief The model of user, using to store user datas // @author huangyibiao // class UserModel : NSObject { var userName: String ///< store user's name, optional var userID: Int ///< store user's ID var phone: String? ///< store user's telephone number var email: String? ///< store user's email // designated initializer init(userName: String, userID: Int, phone: String?, email: String?) { self.userName = userName self.userID = userID self.phone = phone self.email = email super.init() } } UserInfoCell.swift: import Foundation import UIKit // // @brief The cell of showing user infos // @author huangyibiao // class UserInfoCell : UITableViewCell { var userNameLabel : UILabel! var phoneLabel : UILabel! var emailLabel : UILabel! init(style: UITableViewCellStyle, reuseIdentifier: String!) { super.init(style: style, reuseIdentifier: reuseIdentifier) userNameLabel = UILabel(frame: CGRectMake(30, 0, 100, 44)) userNameLabel.backgroundColor = UIColor.clearColor() userNameLabel.font = UIFont.systemFontOfSize(14) self.contentView.addSubview(userNameLabel) phoneLabel = UILabel(frame: CGRectMake(120, 0, 200, 20)) phoneLabel.backgroundColor = UIColor.clearColor() phoneLabel.font = UIFont.systemFontOfSize(12) self.contentView.addSubview(phoneLabel) emailLabel = UILabel(frame: CGRectMake(120, 20, 200, 20)) emailLabel.backgroundColor = UIColor.clearColor() emailLabel.font = UIFont.systemFontOfSize(12) self.contentView.addSubview(emailLabel) } func configureCell(userModel: UserModel?) { if let model = userModel { userNameLabel.text = model.userName phoneLabel.text = model.phone emailLabel.text = model.email } } } RootViewController.swift: import Foundation import UIKit // // @brief 作为窗体的rootViewControllor // @author huangyibiao // class RootViewController : UITableViewController, DetailViewControllerDelegate { var dataSource = NSMutableArray() var currentIndexPath: NSIndexPath? override func viewDidLoad() { super.viewDidLoad() for index in 0...12 { let model = UserModel(userName: "name:\(index + 1)", userID: index, phone: "13877747982", email: "632840804@qq.com") dataSource.addObject(model) } self.title = "UITableViewDemo" } override func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int { return dataSource.count } override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { // can't use static? let cellIdentifier: String = "UserInfoCellIdentifier" // may be no value, so use optional var cell: UserInfoCell? = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? UserInfoCell if cell == nil { // no value cell = UserInfoCell(style: UITableViewCellStyle.Default, reuseIdentifier: cellIdentifier) } let model: UserModel? = dataSource[indexPath.row] as? UserModel cell!.configureCell(model) return cell } override func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) { let detail = DetailViewController() detail.userModel = dataSource[indexPath.row] as? UserModel detail.delegate = self currentIndexPath = indexPath self.navigationController.pushViewController(detail, animated: true) } func changeItem(forUserModel userModel: UserModel?) { var index = 0 for index = 0; index < dataSource.count; index++ { let model = dataSource[index] as UserModel if model.userID == userModel?.userID { model.phone = userModel? .phone model.email = userModel?.email tableView.reloadRowsAtIndexPaths([currentIndexPath!], withRowAnimation: UITableViewRowAnimation.Fade) break } } } } DetailViewController.swift: import Foundation import UIKit // this delegate needs a @objc, because @optional is only for objective-c, not for swift @objc protocol DetailViewControllerDelegate : NSObjectProtocol { @optional func changeItem(forUserModel userModel: UserModel?) } class DetailViewController : UIViewController { var userModel: UserModel? var delegate: DetailViewControllerDelegate? override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = UIColor.whiteColor() self.title = userModel? .userName let button = UIButton(frame: CGRectMake(10, 200, 300, 40)) button.setTitle("change", forState:UIControlState.Normal) button.backgroundColor = UIColor.redColor() button.addTarget(self, action: "onChangeButtonClick:", forControlEvents: UIControlEvents.TouchUpInside) self.view.addSubview(button) } func onChangeButtonClick(sender: UIButton!) { if userModel { userModel!.userName = "ChangeName" // changeItem needs to add a ? to the end, before (), because // this function is optional // delegate? 表示可能没有代理。而changeItem? 表示方法可能没有实现,这样写就算没有实现也没有问题 delegate?.changeItem? (forUserModel: userModel) self.navigationController.popViewControllerAnimated(true) } } } 效果图: 版权声明:本文博客原创文章,博客,未经同意,不得转载。 本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/4727952.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android Service学习之本地服务

Service是在一段不定的时间运行在后台,不和用户交互应用组件。每个Service必须在manifest中 通过<service>来声明。可以通过contect.startservice和contect.bindserverice来启动。 Service和其他的应用组件一样,运行在进程的主线程中。这就是说如果service需要很多耗时或者阻塞的操作,需要在其子线程中实现。 service的两种模式(startService()/bindService()不是完全分离的): 本地服务Local Service 用于应用程序内部。 它可以启动并运行,直至有人停止了它或它自己停止。在这种方式下,它以调用Context.startService()启动,而以调用Context.stopService()结束。它可以调用Service.stopSelf() 或 Service.stopSelfResult()来自己停止。不论调用了多少次startService()方法,你只需要调用一次stopService()来停止服务。 用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。 远程服务Remote Service 用于android系统内部的应用程序之间。 它可以通过自己定义并暴露出来的接口进行程序操作。客户端建立一个到服务对象的连接,并通过那个连接来调用服务。连接以调用Context.bindService()方法建立,以调用 Context.unbindService()关闭。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。 可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。 生命周期 Service的生命周期并不像Activity那么复杂,它只继承了onCreate(),onStart(),onDestroy()三个方法,当我们第一次启动Service时,先后调用了onCreate(),onStart()这两个方法,当停止Service时,则执行onDestroy()方法,这里需要注意的是,如果Service已经启动了,当我们再次启动Service时,不会在执行onCreate()方法,而是直接执行onStart()方法。 而启动service,根据onStartCommand的返回值不同,有两个附加的模式: 1. START_STICKY 用于显示启动和停止service。 2. START_NOT_STICKY或START_REDELIVER_INTENT用于有命令需要处理时才运行的模式。 服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可以启动Service,但是它们的使用场合有所不同。 1. 使用startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。 如果打算采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onStart()方法。 如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次创建服务,但会导致多次调用onStart()方法。 采用startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。 2. 使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。 onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用。 采用Context.bindService()方法启动服务时只能调用onUnbind()方法解除调用者与服务解除,服务结束时会调用onDestroy()方法。 看看官方给出的比较流程示意图: 官方文档告诉我们,一个service可以同时start并且bind,在这样的情况,系统会一直保持service的运行状态如果service已经start了或者BIND_AUTO_CREATE标志被设置。如果没有一个条件满足,那么系统将会调用onDestory方法来终止service.所有的清理工作(终止线程,反注册接收器)都在onDestory中完成。 拥有service的进程具有较高的优先级 官方文档告诉我们,Android系统会尽量保持拥有service的进程运行,只要在该service已经被启动(start)或者客户端连接(bindService)到它。当内存不足时,需要保持,拥有service的进程具有较高的优先级。 1. 如果service正在调用onCreate,onStartCommand或者onDestory方法,那么用于当前service的进程则变为前台进程以避免被killed。 2. 如果当前service已经被启动(start),拥有它的进程则比那些用户可见的进程优先级低一些,但是比那些不可见的进程更重要,这就意味着service一般不会被killed. 3. 如果客户端已经连接到service (bindService),那么拥有Service的进程则拥有最高的优先级,可以认为service是可见的。 4. 如果service可以使用startForeground(int, Notification)方法来将service设置为前台状态,那么系统就认为是对用户可见的,并不会在内存不足时killed。 如果有其他的应用组件作为Service,Activity等运行在相同的进程中,那么将会增加该进程的重要性。 本地service 1.不需和Activity交互的本地服务 public classLocalService extendsService{ private static finalString TAG = "LocalService"; @Override publicIBinder onBind(Intent intent) { Log.i(TAG, "onBind"); return null; } @Override public voidonCreate() { Log.i(TAG, "onCreate"); super.onCreate(); } @Override public voidonDestroy() { Log.i(TAG, "onDestroy"); super.onDestroy(); } @Override public voidonStart(Intent intent, intstartId) { Log.i(TAG, "onStart"); super.onStart(intent, startId); } } Activity: public classServiceActivity extendsActivity { @Override protected voidonCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.servicedemo); ((Button) findViewById(R.id.startLocalService)).setOnClickListener( newView.OnClickListener(){ @Override public voidonClick(View view) { // TODO Auto-generated method stub startService(newIntent("com.demo.SERVICE_DEMO")); } }); ((Button) findViewById(R.id.stopLocalService)).setOnClickListener( newView.OnClickListener(){ @Override public voidonClick(View view) { // TODO Auto-generated method stub stopService(newIntent("com.demo.SERVICE_DEMO"));} }); } } 在AndroidManifest.xml添加: < service android:name =".LocalService" > < intent-filter > < action android:name ="com.demo.SERVICE_DEMO" /> < category android:name ="android.intent.category.default" /> </ intent-filter > </ service > 否则启动服务时会提示new Intent找不到"com.demo.SERVICE_DEMO"。 对于这类不需和Activity交互的本地服务,是使用startService/stopService的最好例子。 运行时可以发现第一次startService时,会调用onCreate和onStart,在没有stopService前,无论点击多少次startService,都只会调用onStart。而stopService时调用onDestroy。再次点击stopService,会发现不会进入service的生命周期的,即不会再调用onCreate,onStart和onDestroy。 而onBind在startService/stopService中没有调用。 2.本地服务和Activity交互 对于这种case,官方的sample(APIDemo\app.LocalService)是最好的例子: /** * This is an example of implementing an application service that runs locally * in the same process as the application.The {@link LocalServiceController} * and {@link LocalServiceBinding} classes show how to interact with the * service. * * <p>Notice the use of the {@link NotificationManager} when interesting things * happen in the service.This is generally how background services should * interact with the user, rather than doing something more disruptive such as * calling startActivity(). */ public classLocalService extendsService { privateNotificationManager mNM; /** * Class for clients to access.Because we know this service always * runs in the same process as its clients, we don't need to deal with * IPC. */ publicclassLocalBinderextendsBinder { LocalService getService() { returnLocalService.this; } } @Override public voidonCreate() { mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); // Display a notification about us starting.We put an icon in the status bar. showNotification(); } @Override public intonStartCommand(Intent intent, intflags, intstartId) { Log.i( "LocalService", "Received start id "+ startId + ": "+ intent); // We want this service to continue running until it is explicitly // stopped, so return sticky. returnSTART_STICKY; } @Override public voidonDestroy() { // Cancel the persistent notification. mNM.cancel(R.string.local_service_started); // Tell the user we stopped. Toast.makeText( this, R.string.local_service_stopped, Toast.LENGTH_SHORT).show(); } @Override public IBinder onBind(Intent intent) { return mBinder; } // This is the object that receives interactions from clients.See // RemoteService for a more complete example. privatefinalIBinder mBinder =newLocalBinder(); /** * Show a notification while this service is running. */ private voidshowNotification() { // In this sample, we'll use the same text for the ticker and the expanded notification CharSequence text = getText(R.string.local_service_started); // Set the icon, scrolling text and timestamp Notification notification = newNotification(R.drawable.stat_sample, text, System.currentTimeMillis()); // The PendingIntent to launch our activity if the user selects this notification PendingIntent contentIntent = PendingIntent.getActivity( this, 0, newIntent( this, LocalServiceController. class), 0); // Set the info for the views that show in the notification panel. notification.setLatestEventInfo( this, getText(R.string.local_service_label), text, contentIntent); // Send the notification. // We use a layout id because it is a unique number.We use it later to cancel. mNM.notify(R.string.local_service_started, notification); } } 这里可以发现onBind需要返回一个IBinder对象。也就是说和上一例子LocalService不同的是, 1. 添加了一个public内部类继承Binder,并添加getService方法来返回当前的Service对象; 2. 新建一个IBinder对象——new那个Binder内部类; 3. onBind方法返还那个IBinder对象。 Activity: /** * <p>Example of binding and unbinding to the {@link LocalService}. * This demonstrates the implementation of a service which the client will * bind to, receiving an object through which it can communicate with the service.</p> */ public classLocalServiceBinding extendsActivity { private booleanmIsBound; privateLocalService mBoundService; @Override protected voidonCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.local_service_binding); // Watch for button clicks. Button button = (Button)findViewById(R.id.bind); button.setOnClickListener(mBindListener); button = (Button)findViewById(R.id.unbind); button.setOnClickListener(mUnbindListener); } privateServiceConnection mConnection =newServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service){ // This is called when the connection with the service has been // established, giving us the service object we can use to // interact with the service.Because we have bound to a explicit // service that we know is running in our own process, we can // cast its IBinder to a concrete class and directly access it. mBoundService = ((LocalService.LocalBinder)service).getService(); // Tell the user about this for our demo. Toast.makeText(LocalServiceBinding. this, R.string.local_service_connected, Toast.LENGTH_SHORT).show(); } public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. // Because it is running in our same process, we should never // see this happen. mBoundService = null; Toast.makeText(LocalServiceBinding. this, R.string.local_service_disconnected, Toast.LENGTH_SHORT).show(); } }; privateOnClickListener mBindListener = newOnClickListener() { public voidonClick(View v) { // Establish a connection with the service.We use an explicit // class name because we want a specific service implementation that // we know will be running in our own process (and thus won't be // supporting component replacement by other applications). bindService( newIntent(LocalServiceBinding. this, LocalService. class), mConnection, Context.BIND_AUTO_CREATE); mIsBound = true; } }; privateOnClickListener mUnbindListener = newOnClickListener() { public voidonClick(View v) { if(mIsBound) { // Detach our existing connection. unbindService( mConnection); mIsBound = false; } } }; } 明显看出这里面添加了一个名为ServiceConnection类,并实现了onServiceConnected(从IBinder获取Service对象)和onServiceDisconnected(set Service to null)。 而bindService和unbindService方法都是操作这个ServiceConnection对象的。 AndroidManifest.xml里添加: < service android:name =".app.LocalService" /> < activity android:name =".app.LocalServiceBinding" android:label ="@string/activity_local_service_binding" > < intent-filter > < action android:name ="android.intent.action.MAIN" /> < category android:name ="android.intent.category.SAMPLE_CODE" /> </ intent-filter > </ activity > 这里没什么特别的,因为service没有需要什么特别的action,所以只是声明service而已,而activity和普通的没差别。 运行时,发现调用次序是这样的: bindService: 1.LocalService : onCreate 2.LocalService : onBind 3.Activity: onServiceConnected unbindService: 只是调用onDestroy 可见,onStart是不会被调用的,而onServiceDisconnected没有调用的原因在上面代码的注释有说明。 介绍onStartCommand()需要用到的几个常量 (引自官方文档) START_NOT_STICKY If the system kills the service after onStartCommand() returns, do notrecreate the service, unless there are pending intents to deliver. This is the safest option to avoid running your service when not necessary and when your application can simply restart any unfinished jobs. START_STICKY If the system kills the service after onStartCommand() returns, recreate the service and call onStartCommand(), but do notredeliver the last intent. Instead, the system calls onStartCommand() with a null intent, unless there were pending intents to start the service, in which case, those intents are delivered. This is suitable for media players (or similar services) that are not executing commands, but running indefinitely and waiting for a job. START_REDELIVER_INTENT If the system kills the service after onStartCommand() returns, recreate the service and call onStartCommand() with the last intent that was delivered to the service. Any pending intents are delivered in turn. This is suitable for services that are actively performing a job that should be immediately resumed, such as do wnloading a file. Running a Service in the Foreground 具体内容查看官方文档,主要是使用 startForeground() 和 stopForeground()方法。 本文转自 Icansoft 51CTO博客,原文链接http://blog.51cto.com/android/527314

优秀的个人博客,低调大师

【Android进阶学习】LayoutInflater的应用

LayoutInflater在Android中是“扩展”的意思,作用类似findViewById( ),它在Android开发中的作用是很大的。LayoutInflater经常在BaseAdapter的getView方法中用到,用来获取整个View并返回。 LayoutInflater与findViewById( )的不同点: LayoutInflater是将XML中的Layout转换为View放入.java代码中 findViewById()是找具体xml下的具体组件(如:Button,TextView,ImageView等)。 获得LayoutInflater的三种方法: 第一种: LayoutInflaterinflater=LayoutInflater.from(this); Viewlayout=inflater.inflate(R.layout.main,null); 第二种: LayoutInflaterinflater=getLayoutInflater(); Viewlayout=inflater.inflate(R.layout.main,null); 第三种: LayoutInflaterinflater=(LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE); Viewlayout=inflater.inflate(R.layout.main,null); getSystemService()是Android很重要的一个API,它是Activity的一个方法,根据传入 的NAME来取得对应的Object,然后转换成相应的服务对象。以下介绍系统相应的服务。其中LAYOUT_INFLATER_SERVICE返回的对象是LayoutInflater,作用是取得XML定义的View。 第一个实例: main.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <EditText android:id="@+id/text" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/btn1" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/btn2" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout> MainActivity.java packagecom.lingdududu.test; importandroid.app.Activity; importandroid.graphics.Color; importandroid.os.Bundle; importandroid.view.LayoutInflater; importandroid.view.View; importandroid.widget.Button; importandroid.widget.EditText; publicclassMainActivityextendsActivity{ privateEditTextetx; privateButtonconfirmBtn; privateButtoncancleBtn; /**Calledwhentheactivityisfirstcreated.*/ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); LayoutInflaterinflater=getLayoutInflater(); Viewlayout=inflater.inflate(R.layout.main,null); etx=(EditText)layout.findViewById(R.id.text); etx.setBackgroundColor(Color.WHITE); etx.setHint("请输入你的学号"); confirmBtn=(Button)layout.findViewById(R.id.btn1); confirmBtn.setText("确定"); cancleBtn=(Button)layout.findViewById(R.id.btn2); cancleBtn.setText("取消"); setContentView(layout); } } 效果图: 第二个实例: 下面的一个简单的LayoutInflater应用实例,主布局main.xml里有一个TextView和一个Button,当点击Button,出现 Dialog,而这个Dialog的布局方式是我们在layout目录下定义的dialog.xml文件(里面左右分布,左边 ImageView,右边TextView)。 main.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns: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="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <Button android:id="@+id/btn" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="打开对话框" /> </LinearLayout> dialog.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" > <ImageView android:id="@+id/img" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/dialog_txt" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="测试LayoutInflater" /> </LinearLayout> MainActivity.java packagecom.lingdududu.test; importandroid.app.Activity; importandroid.app.AlertDialog; importandroid.os.Bundle; importandroid.view.LayoutInflater; importandroid.view.View; importandroid.view.View.OnClickListener; importandroid.widget.Button; importandroid.widget.ImageView; importandroid.widget.TextView; publicclassMainActivityextendsActivity{ privateButtonshowBtn; /**Calledwhentheactivityisfirstcreated.*/ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); showBtn=(Button)findViewById(R.id.btn); showBtn.setOnClickListener(newshowDialogListener()); } classshowDialogListenerimplementsOnClickListener{ @Override publicvoidonClick(Viewv){ //TODOAuto-generatedmethodstub showDialog(); } } publicvoidshowDialog(){ AlertDialog.Builderbuilder; AlertDialogdialog; LayoutInflaterinflater=(LayoutInflater)this.getSystemService(LAYOUT_INFLATER_SERVICE); //LayoutInflaterinflater=getLayoutInflater(); //LayoutInflaterinflater=LayoutInflater.from(this); Viewlayout=inflater.inflate(R.layout.dialog,null); TextViewtx=(TextView)layout.findViewById(R.id.dialog_txt); tx.setText("测试LayoutInflater"); ImageViewimg=(ImageView)layout.findViewById(R.id.img); img.setImageResource(R.drawable.icon); builder=newAlertDialog.Builder(this); builder.setView(layout); dialog=builder.create(); dialog.show(); } } 效果图: 本文转自 lingdududu 51CTO博客,原文链接: http://blog.51cto.com/liangruijun/750495

优秀的个人博客,低调大师

Nginx学习笔记(一) Nginx架构

Nginx全程是什么?Nginx ("engine x") 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP代理服务器。 daemon守护线程 nginx在启动后,在unix系统中会以daemon的方式在后台运行,后台进程包含一个master进程和多个worker进程。 当然nginx也是支持多线程的方式的,只是我们主流的方式还是多进程的方式,也是nginx的默认方式。 master进程主要用来管理worker进程,包含:接收来自外界的信号,向各worker进程发送信号,监控worker进程的运行状态,当worker进程退出后(异常情况下),会自动重新启动新的worker进程。 worker进程则是处理基本的网络事件。多个worker进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。 worker进程的个数是可以设置的,一般我们会设置与机器cpu核数一致。更多的worker数,只会导致进程来竞争cpu资源了,从而带来不必要的上下文切换。而且,nginx为了更好的利用多核特性,具有cpu绑定选项,我们可以将某一个进程绑定在某一个核上,这样就不会因为进程的切换带来cache的失效。 惊群现象 每个worker进程都是从master进程fork过来。在master进程里面,先建立好需要listen的socket之后,然后再fork出多个worker进程,这样每个worker进程都可以去accept这个socket(当然不是同一个socket,只是每个进程的这个socket会监控在同一个ip地址与端口,这个在网络协议里面是允许的)。一般来说,当一个连接进来后,所有在accept在这个socket上面的进程,都会收到通知,而只有一个进程可以accept这个连接,其它的则accept失败。 相对于线程,采用进程的优点 进程之间不共享资源,不需要加锁,所以省掉了锁带来的开销。 采用独立的进程,可以让互相之间不会影响,一个进程退出后,其它进程还在工作,服务不会中断,master进程则很快重新启动新的worker进程。 编程上更加容易。 多线程的问题 而多线程在多并发情况下,线程的内存占用大,线程上下文切换造成CPU大量的开销。想想apache的常用工作方式(apache也有异步非阻塞版本,但因其与自带某些模块冲突,所以不常用),每个请求会独占一个工作线程,当并发数上到几千时,就同时有几千的线程在处理请求了。这对操作系统来说,是个不小的挑战,线程带来的内存占用非常大,线程的上下文切换带来的cpu开销很大,自然性能就上不去了,而这些开销完全是没有意义的。 异步非阻塞 异步的概念和同步相对的,也就是不是事件之间不是同时发生的。 非阻塞的概念是和阻塞对应的,阻塞是事件按顺序执行,每一事件都要等待上一事件的完成,而非阻塞是如果事件没有准备好,这个事件可以直接返回,过一段时间再进行处理询问,这期间可以做其他事情。但是,多次询问也会带来额外的开销。 总的来说,Nginx采用异步非阻塞的好处在于: 不需要创建线程,每个请求只占用少量的内存 没有上下文切换,事件处理非常轻量 淘宝tengine团队说测试结果是“24G内存机器上,处理并发请求可达200万”。 本文转自cococo点点博客园博客,原文链接:http://www.cnblogs.com/coder2012/p/3141469.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

学习笔记-4.1用户管理命令

复习: /etc/passwd: 用户名:密码:UID:GID:注释:家目录:默认shell /etc/group: 组名:密码:GID:以此组为其附加组的用户列表 /etc/shadow: 用户名:密码:最近一次修改密码的时间:最短使用期限,最长使用期限: 警告时间:非活动时间:过期时间 useradd [options] USERNAME useradd -u 1000 user1 -u 指定其UID -g GID(基本组) 指定组一定要存在 -G GID,... (附加组) -c "COMMENT"指定注释信息 -d /path/to/directory指定家目录,默认是home下 -s SHELL useradd -s /sbin/nologin user5 su - user5 -m -k 强制复制bash配置文件到家目录 -M 创建用户,不创建家目录 -r 添加一个系统用户 /etc/login.defs /etc/shells:指定了当前系统可用的安全shell 环境变量:PATH HISTSIZE SHELL userdel: userdel [option] USERNAME 不指定选项,不会删除家目录 -r 删除用户的同时,同时删除用户的家目录 id :查看用户的账号属性信息 -u -g -G -n 上面都可用和-n合用 finger USERNAME(user1)查看用户账号相关信息 修改用户账号属性: usermod -u usermod -u 2002 user2 -g (基本组,事先存在的组) -G 附加组,已有附件组,修改了后原有附件组就没有了 -a -G:追加附件组(-a与-G联合使用) -c 注释 -d -m 为用户指定新的家目录,并移动此前新建的文件到新的家目录 -s shell -l 修改用户名 -L:锁定账号 -U:解锁 chsh:修改用户的默认shell chfn:修改用户的注释信息(fn是finger的缩写) 密码管理: passwd [USERNAME] --stdin -l 锁定账号 -u 解锁 -d 删除用户密码(禁止登录) echo "redhat" | passwd --stdin user3 pwch(passwdcheck)检查用户账号完整性 组管理: 创建组:groupadd groupadd -g GID -r 添加为系统组 groupmod -g GID -n GRPNAME groupdel gpasswd:为组设定密码 newgrp 临时切换基本组 exit退出 练习: 1 创建一个用户mandriva ,其ID号2002,基本组为distro(组ID3003),附加组 为linux: # groupadd -g 3003 distro # groupadd linux # useradd -u 2002 -g distro -G linux mandriva 2 创建一个用户fedora,其全名为Fedora Community,默认shell为tcsh # useradd -c "Fedora Community" -s /bin/tcsh/ fedora 3 修改mandriva的ID号为4004,基本组为linux,附加组为distro和Fedora # usermod -u 4004 -g linux -G distro,fedora mandriva 4 给Fedora加密码,并设定其密码最短使用期限为2天,最长为50天 # passwd -n 2 -x 50 fedora 5 将madriva的默认shell改为/bin/bash # usermod -s /bin/bash mandrira 6 添加系统用户hbase,且不允许其登陆系统 #useradd -r -s /sbin/noglogin hbase change(改变密码过期信息的) -d 最近一次的修改时间 -E 过期时间 -r: 非活动时间 -m 最短使用时间 -M 最长使用时间 -w:警告时间 本文转自飞行萌51CTO博客,原文链接: http://blog.51cto.com/8527508/1939822,如需转载请自行联系原作者

优秀的个人博客,低调大师

openstack学习笔记七 swift安装

项目--对象存储--容器 在容器里你创建的即使是一个文件夹,那么体现在硬盘里,也是一个文件,也就是对象object 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [root@h1~(keystone_admin)] #openstackservicelist +----------------------------------+------------+--------------+ |ID|Name|Type| +----------------------------------+------------+--------------+ |30c62c3c0797462a8bd4ff059a71296e|swift|object-store| [root@h1~(keystone_admin)] #keystoneendpoint-list|grep30c62c3c0797462a8bd4ff059a71296e |2408bc6cb5164053b86c0983fd39961a|RegionOne|http: //192 .168.1.201:8080 /v1/AUTH_ %(tenant_id)s|http: //192 .168.1.201:8080 /v1/AUTH_ %(tenant_id)s|http: //192 .168.1.201:8080|30c62c3c0797462a8bd4ff059a71296e| [root@h1~(keystone_admin)] #swiftlist h1 [root@h1~(keystone_admin)] #swiftlisth1 test1/ test1 /k1 .pem [root@h1~(keystone_admin)] #find/srv/node/swiftloopback/-typef-name"*.data" /srv/node/swiftloopback/objects/188901/27f/b87961659e1149b7094bb52b5d60f27f/1467698512 .58656.data ##删除k1后就没有了 /srv/node/swiftloopback/objects/59261/c81/39df7c7803321e4878fdcec1ac469c81/1467698493 .15690.data 映射 :ring(环) 映射到硬盘 容器 在容器里面创建对象 对象 文件就是对象 账户 权限 ring文件 保存到硬盘 account.ring.gz 账户 container.ring.gz 容器 object.ring.gz 对象 保存到硬盘里的目录,这个目录为zone /srv/node/swiftloopback/ 挂载点 必须放在/srv/node/目录下 zone1 zone2 两个相同,备份 packstack方式安装完成后,上传一个文件,只在硬盘里保留一份 对象先映射到 虚拟节点/分区partition 2^n 再映射到zone 目的:减少数据的迁移量 swift服务 1 一致性服务 consisteny server auditor 定期扫描,如果出现问题,就把有问题的文件放隔离区 replicate 从另外的zone复制相同的文件过来,实现数据同步 update 如果replicate失效了,那么等段时间再试 2 代维服务proxy server 接受用户发送过来的请求,比如上传、删除等请求 3 存储服务 容器服务器 container server 对象服务器 object server 账户服务器 acount server 安装软件 1 2 [root@h4~] #yumlistopenstack-swift* [root@h4~] #yum-yinstallopenstack-swift.noarchopenstack-swift-account.noarchopenstack-swift-container.noarchopenstack-swift-object.noarchopenstack-swift-proxy.noarchmemcache*python-swiftclient 任何服务都要向keystone进行注册 1 2 3 [root@h4~(keystone_admin)] #keystoneuser-create--nameswift--passhequan [root@h4~(keystone_admin)] #keystonetenant-create--nameservices [root@h4~(keystone_admin)] #keystoneuser-role-add--userswift--tenantservices--roleadmin 创建服务,指定endpoint 1 2 [root@h4~(keystone_admin)] #keystoneservice-create--nameswift--typeobject-store--description"swift" keystoneendpoint-create--service- id 0995c9a9ed4847da86435bca9a7be8fc--publicurl 'http://192.168.1.204:8080/v1/AUTH_%(tenant_id)s' --internalurl 'http://192.168.1.204:8080/v1/AUTH_%(tenant_id)s' --adminurl 'http://192.168.1.204:8080' 配置swift 准备了2个分区 1 2 3 zone1zone2在 /srv/node 12 /dev/sdb1 /srv/node/zone1 xfsdefaults00 ##挂载 13 /dev/sdb2 /srv/node/zone2 xfsdefaults00 1 [root@h4~(keystone_admin)] #chown-Rswift.swift/srv/node/ 1 2 3 4 5 6 7 8 9 10 [root@h4swift(keystone_admin)] #catswift.conf [swift- hash ] swift_hash_path_suffix=%SWIFT_HASH_PATH_SUFFIX% [root@h1~(keystone_admin)] #find/srv/node/swiftloopback/-typef-name"*.data" /srv/node/swiftloopback/objects/102340/afe/63f12ea37cca17f0227381adcf93eafe/1467982747 .16551.data zone对象类型/分区的编号 /sufix/ 文件名字的 hash /上传文件的时间戳 [root@h1~(keystone_admin)] #date--date=@1467982747.16551 2016年07月08日星期五20:59:07CST 创建ring文件的准备工作 创建模板,设定有几个备份,有多少分区。 1 2 3 [root@h4swift(keystone_admin)] #swift-ring-builderaccount.buildercreate1221 [root@h4swift(keystone_admin)] #swift-ring-builderobject.buildercreate1221 [root@h4swift(keystone_admin)] #swift-ring-buildercontainer.buildercreate1221 指定映射位置 1 2 3 4 5 6 7 8 [root@h4swift] #vimaccount-server.conf#3个都要改ip 6bind_ip=192.168.1.204 [root@h4swift(keystone_admin)] #swift-ring-builderaccount.builderaddz1-192.168.1.204:6202/zone1100 [root@h4swift(keystone_admin)] #swift-ring-builderaccount.builderaddz2-192.168.1.204:6202/zone2100 [root@h4swift(keystone_admin)] #swift-ring-builderobject.builderaddz1-192.168.1.204:6200/zone1100 [root@h4swift(keystone_admin)] #swift-ring-builderobject.builderaddz2-192.168.1.204:6200/zone2100 [root@h4swift(keystone_admin)] #swift-ring-buildercontainer.builderaddz1-192.168.1.204:6201/zone1100 [root@h4swift(keystone_admin)] #swift-ring-buildercontainer.builderaddz2-192.168.1.204:6201/zone2100 创建ring文件 1 2 3 4 5 [root@h4swift(keystone_admin)] #swift-ring-builderaccount.builderrebalance [root@h4swift(keystone_admin)] #swift-ring-builderobject.builderrebalance [root@h4swift(keystone_admin)] #swift-ring-buildercontainer.builderrebalance [root@h4swift(keystone_admin)] #ls*.gz account.ring.gzcontainer.ring.gzobject.ring.gz 启动服务 1 2 3 4 5 6 [root@h4srv(keystone_admin)] #systemctlstartopenstack-swift-accountopenstack-swift-objectopenstack-swift-container [root@h4srv(keystone_admin)] #systemctlis-activeopenstack-swift-accountopenstack-swift-objectopenstack-swift-container active active active [root@h4srv(keystone_admin)] #systemctlenableopenstack-swift-accountopenstack-swift-objectopenstack-swift-container 代维服务proxy server 1 2 3 4 5 6 7 8 9 10 11 [root@h4swift(keystone_admin)] #vimproxy-server.conf 53[filter:authtoken] 54 paste .filter_factory=keystonemiddleware.auth_token:filter_factory 55admin_tenant_name=services 56admin_user=swift 57admin_password=hequan 58 # 59identity_uri=http: //192 .168.1.204:35357/ 60auth_port=35357 61auth_protocol=http 62 #auth_uri=http://192.168.1.204:5000/ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 [root@h4swift(keystone_admin)] #systemctlstartopenstack-swift-proxy.service [root@h4swift(keystone_admin)] #systemctlenableopenstack-swift-proxy.service [root@h4swift(keystone_admin)] #systemctlstartmemcached.service [root@h4swift(keystone_admin)] #systemctlenablememcached.service [root@h4swift(keystone_admin)] #swiftposth1 [root@h4swift(keystone_admin)] #swiftlist h1 [root@h4swift(keystone_admin)] #swiftuploadh1/etc/hosts 任意一个分区挂了,还是可以正常查看 两个都挂了,就看不到了 本文转自 295631788 51CTO博客,原文链接:http://blog.51cto.com/hequan/1812861,如需转载请自行联系原作者

优秀的个人博客,低调大师

python学习笔记文件操作(六)

1、文件操作流程: 打开文件,得到文件句柄并赋值给一个变量 通过句柄对文件进行操作 关闭文件 如下文件: 1 2 3 4 5 6 2017 - 03 - 24 11 : 25 : 06 : 349 - info:[debug][AndroidBootstrap]Sendingcommandtoandroid:{ "cmd" : "shutdown" } 2017 - 03 - 24 11 : 25 : 06 : 355 - info:[debug][AndroidBootstrap]Receivedcommandresult from bootstrap 2017 - 03 - 24 11 : 25 : 06 : 356 - info:[debug][UiAutomator]ShuttingdownUiAutomator 2017 - 03 - 24 11 : 25 : 06 : 357 - info:[debug][UiAutomator]Movingtostate 'stopping' 2017 - 03 - 24 11 : 25 : 06 : 360 - info:[AndroidBootstrap][BOOTSTRAPLOG][debug]Gotdata from client:{ "cmd" : "shutdown" } 2017 - 03 - 24 11 : 25 : 06 : 361 - info:[AndroidBootstrap][BOOTSTRAPLOG][debug]Gotcommandof type SHUTDOWN 操作流程: 1 2 3 f = open ( 'log.txt' , 'r' ) print (f.read()) f.close() 注意: 在win系统中log文件是utf8保存的,打开文件时open函数是通过操作系统打开的文件,而win操作系统默认的是gbk编码,所以直接打开会乱码,需要f=open('hello',encoding='utf8'),hello文件如果是gbk保存的,则直接打开即可。 2、文件打开模式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #======================================================================== # #CharacterMeaning # #------------------------------------------------------------------------ # #'r'openforreading(default) # #'w'openforwriting,truncatingthefilefirst # #'x'createanewfileandopenitforwriting # #'a'openforwriting,appendingtotheendofthefileifitexists # #'b'binarymode # #'t'textmode(default) # #'+'openadiskfileforupdating(readingandwriting) # #'U'universalnewlinemode(deprecated) # #======================================================================== 3、文件操作方法 获取文件内容 1 2 3 4 f = open ( 'log.txt' , 'r' ) data = f.read() print (data) f.close() 输出: 2017-03-24 11:25:06:349 - info: [debug] [AndroidBootstrap] Sending command to android: {"cmd":"shutdown"} 2017-03-24 11:25:06:355 - info: [debug] [AndroidBootstrap] Received command result from bootstrap 2017-03-24 11:25:06:356 - info: [debug] [UiAutomator] Shutting down UiAutomator 2017-03-24 11:25:06:357 - info: [debug] [UiAutomator] Moving to state 'stopping' 2017-03-24 11:25:06:360 - info: [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Got data from client: {"cmd":"shutdown"} 2017-03-24 11:25:06:361 - info: [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Got command of type SHUTDOWN =========================================================================================== 1 2 3 4 f= open ( 'log.txt' , 'r' ) data1=f. read (10) #读取10个字符。(在这里汉字也只占一个单位) print(data1) f.close() 输出: 2017-03-24 readline和readlines =========================================================================================== 1 2 3 f = open ( 'log.txt' , 'r' ) print (f.readlines()) #返回的是一个列表,注意换行符 f.close() 输出: ['2017-03-24 11:25:06:349 - info: [debug] [AndroidBootstrap] Sending command to android: {"cmd":"shutdown"}\n', '2017-03-24 11:25:06:355 - info: [debug] [AndroidBootstrap] Received command result from bootstrap\n', '2017-03-24 11:25:06:356 - info: [debug] [UiAutomator] Shutting down UiAutomator\n', "2017-03-24 11:25:06:357 - info: [debug] [UiAutomator] Moving to state 'stopping'\n", '2017-03-24 11:25:06:360 - info: [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Got data from client: {"cmd":"shutdown"}\n', '2017-03-24 11:25:06:361 - info: [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Got command of type SHUTDOWN'] =========================================================================================== 1 2 3 4 5 f = open ( 'log.txt' , 'r' ) print (f.readline()) #逐行读取 print (f.readline()) print (f.readline(),f.readline(),f.readline()) #逐行读取,每行末尾换行符 f.close() 输出:(注意每行末尾的换行符) 2017-03-24 11:25:06:349 - info: [debug] [AndroidBootstrap] Sending command to android: {"cmd":"shutdown"} 2017-03-24 11:25:06:355 - info: [debug] [AndroidBootstrap] Received command result from bootstrap 2017-03-24 11:25:06:356 - info: [debug] [UiAutomator] Shutting down UiAutomator 2017-03-24 11:25:06:357 - info: [debug] [UiAutomator] Moving to state 'stopping' 2017-03-24 11:25:06:360 - info: [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Got data from client: {"cmd":"shutdown"} =========================================================================================== 1 2 3 4 f = open ( 'log.txt' , 'r' ) for line in f.readlines(): print (line.strip()) f.close() 输出: 2017-03-24 11:25:06:349 - info: [debug] [AndroidBootstrap] Sending command to android: {"cmd":"shutdown"} 2017-03-24 11:25:06:355 - info: [debug] [AndroidBootstrap] Received command result from bootstrap 2017-03-24 11:25:06:356 - info: [debug] [UiAutomator] Shutting down UiAutomator 2017-03-24 11:25:06:357 - info: [debug] [UiAutomator] Moving to state 'stopping' 2017-03-24 11:25:06:360 - info: [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Got data from client: {"cmd":"shutdown"} 2017-03-24 11:25:06:361 - info: [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Got command of type SHUTDOWN =========================================================================================== 1 2 3 4 5 f = open ( 'log.txt' , 'r' ) print (f) for i in f: print (i.strip()) f.close() 输出: <_io.TextIOWrapper name='log.txt' mode='r' encoding='cp936'> 2017-03-24 11:25:06:349 - info: [debug] [AndroidBootstrap] Sending command to android: {"cmd":"shutdown"} 2017-03-24 11:25:06:355 - info: [debug] [AndroidBootstrap] Received command result from bootstrap 2017-03-24 11:25:06:356 - info: [debug] [UiAutomator] Shutting down UiAutomator 2017-03-24 11:25:06:357 - info: [debug] [UiAutomator] Moving to state 'stopping' 2017-03-24 11:25:06:360 - info: [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Got data from client: {"cmd":"shutdown"} 2017-03-24 11:25:06:361 - info: [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Got command of type SHUTDOWN =========================================================================================== 1 2 3 4 5 6 7 8 n = 0 f = open ( 'log.txt' , 'r' ) for i in f: if n = = 3 : i = ' '.join([i.strip(),' this is line 4 ']) print (i.strip()) n + = 1 f.close() 输出: 2017-03-24 11:25:06:349 - info: [debug] [AndroidBootstrap] Sending command to android: {"cmd":"shutdown"} 2017-03-24 11:25:06:355 - info: [debug] [AndroidBootstrap] Received command result from bootstrap 2017-03-24 11:25:06:356 - info: [debug] [UiAutomator] Shutting down UiAutomator 2017-03-24 11:25:06:357 - info: [debug] [UiAutomator] Moving to state 'stopping' this is line 4 2017-03-24 11:25:06:360 - info: [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Got data from client: {"cmd":"shutdown"} 2017-03-24 11:25:06:361 - info: [AndroidBootstrap] [BOOTSTRAP LOG] [debug] Got command of type SHUTDOWN =========================================================================================== tell和seek 1 2 3 4 5 6 f = open ( 'log.txt' , 'r' ) print (f.read( 25 )) print (f.tell()) #取出光标所在位置 print (f.seek( 0 )) #移动光标到指定的位置 print (f.read( 50 )) f.close() 输出: 2017-03-24 11:25:06:349 - 25 0 2017-03-24 11:25:06:349 - info: [debug] [AndroidBo 注意:read后不管是中文字符还是英文字符,都统一算一个单位,read(6),此刻就读了6个中文字符;而seek和tell对于英文字符就是占一个,中文字符占三个,区分与read()的不同. =========================================================================================== flush:同步把数据从缓存移动到磁盘上去 1 2 3 4 5 6 7 8 9 10 11 12 #进度条实例 import sys,time for i in range ( 30 ): sys.stdout.write( "*" ) sys.stdout.flush() time.sleep( 0.1 ) #print的flush import sys,time for i in range ( 30 ): print ( '*' ,end = '',flush = True ) time.sleep( 0.1 ) =========================================================================================== 其他扩展: #truncate():截断数据(不能在r模式下)#在w模式下:先清空,再写,再截断#在a模式下:直接将指定位置后的内容截断 # r+:光标默认在0位置开始写,从0开始覆盖数据# w+:先清空,再写读# a+:光标默认在最后位置 =========================================================================================== with: 为了避免打开文件后忘记关闭,可以通过管理上下文,即: 1 2 with open ( 'log.txt' , 'r' )asf: print (f.readline()) 在Python 2.7 后,with又支持同时对多个文件的上下文进行管理,即:如此方式,当with代码块执行完毕时,内部会自动关闭并释放文件资源。 1 2 3 4 #with同时管理多个文件对象 with open ( 'log1' , 'r' )asf_read, open ( 'log2' , 'w' )asf_write: for line in f_read: f_write.write(line) 本文转自cqtesting51CTO博客,原文链接:http://blog.51cto.com/cqtesting/1959698 ,如需转载请自行联系原作者

优秀的个人博客,低调大师

android学习之-SQLiteOpenHelper的应用

通过这个小例子大致了解了手机数据库的一些功能,见主类 packagecom.android.sucre; importandroid.app.Activity; importandroid.database.Cursor; importandroid.database.sqlite.SQLiteCursor; importandroid.os.Bundle; importandroid.util.Log; importandroid.view.Menu; importandroid.view.MenuItem; importandroid.view.View; importandroid.widget.AdapterView; importandroid.widget.EditText; importandroid.widget.ListView; importandroid.widget.SimpleCursorAdapter; /** *数据库简单应用 *@authorqiaolei * */ publicclassEX05_05_SQLiteextendsActivity{ privateToDoDBmyToDoDB; privateCursormyCursor; privateEditTextmyEditText; privateListViewmyListView; privateint_id; protectedfinalstaticintMENU_ADD=Menu.FIRST; protectedfinalstaticintMENU_EDIT=Menu.FIRST+1; protectedfinalstaticintMENU_DELETE=Menu.FIRST+2; /**Calledwhentheactivityisfirstcreated.*/ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); myEditText=(EditText)findViewById(R.id.myEditText); myListView=(ListView)findViewById(R.id.myListView); myToDoDB=newToDoDB(this); myCursor=myToDoDB.select();//取得database中的数据 //R.layout.list为layout文件夹下的list文件 //R.id.listView指向list文件的ID SimpleCursorAdapteradapter=newSimpleCursorAdapter(this,R.layout.list,myCursor,newString[]{ToDoDB.FIELD_TEXT},newint[]{R.id.listView}); myListView.setAdapter(adapter); myListView.setOnItemClickListener(newAdapterView.OnItemClickListener(){ publicvoidonItemClick(AdapterView<?>arg0,Viewarg1,intarg2, longarg3){ myCursor.moveToPosition(arg2);//将myCursor移到所单击的值,这个值是数据库中的行标是固定不变的 _id=myCursor.getInt(0);//取得第0列字段_id的值,这个值相当于数据库的主键处于自增状态,相对于整个数据库而言,这个值是实际数据库中字段的真实值 Log.d("arg2:_id",arg2+":"+_id); myEditText.setText(myCursor.getString(1));//取得第1列字段的值 } }); myListView.setOnItemSelectedListener(newAdapterView.OnItemSelectedListener(){ publicvoidonItemSelected(AdapterView<?>arg0,Viewarg1, intarg2,longarg3){ SQLiteCursorsc=(SQLiteCursor)arg0.getSelectedItem(); _id=sc.getInt(0); myEditText.setText(sc.getString(1)); } publicvoidonNothingSelected(AdapterView<?>arg0){ } }); } @Override publicbooleanonCreateOptionsMenu(Menumenu){ super.onCreateOptionsMenu(menu); menu.add(Menu.NONE,MENU_ADD,0,R.string.create); menu.add(Menu.NONE,MENU_EDIT,0,R.string.edit); menu.add(Menu.NONE,MENU_DELETE,0,R.string.delete); returntrue; } @Override publicbooleanonOptionsItemSelected(MenuItemitem){ super.onOptionsItemSelected(item); switch(item.getItemId()){ caseMENU_ADD: this.addToDo(); break; caseMENU_EDIT: this.editToDo(); break; caseMENU_DELETE: this.deleteToDo(); break; } returntrue; } privatevoidaddToDo(){ if(!"".equals(myEditText.getText().toString())){ myToDoDB.insert(myEditText.getText().toString()); myCursor.requery(); myListView.invalidateViews(); myEditText.setText(""); _id=0; } } privatevoideditToDo(){ if(!"".equals(myEditText.getText().toString())){ myToDoDB.update(_id,myEditText.getText().toString()); myCursor.requery();//更新游标 myListView.invalidateViews();//更新ListView内容 myEditText.setText(""); _id=0; } } privatevoiddeleteToDo(){ if(_id!=0){ myToDoDB.delete(_id); myCursor.requery(); myListView.invalidateViews(); myEditText.setText(""); _id=0; } } } packagecom.android.sucre; importandroid.content.ContentValues; importandroid.content.Context; importandroid.database.Cursor; importandroid.database.sqlite.SQLiteDatabase; importandroid.database.sqlite.SQLiteDatabase.CursorFactory; importandroid.database.sqlite.SQLiteOpenHelper; /** *创建数据库 *@authorqiaolei * */ publicclassToDoDBextendsSQLiteOpenHelper{ privatefinalstaticStringDATABASE_NAME="todo_db"; privatefinalstaticintDATABASE_VERSION=1; privatefinalstaticStringTABLE_NAME="todo_table"; publicfinalstaticStringFIELD_id="_id"; publicfinalstaticStringFIELD_TEXT="todo_text"; publicToDoDB(Contextcontext){ super(context,DATABASE_NAME,null,DATABASE_VERSION); } @Override publicvoidonCreate(SQLiteDatabasedb){ //创建的表有两列,FIELD_ID为主键自动增长 Stringsql="createtable"+TABLE_NAME+"("+FIELD_id+"integerprimarykeyautoincrement,"+FIELD_TEXT+"text)"; db.execSQL(sql); } @Override publicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion){ Stringsql="droptableifexists"+TABLE_NAME+""; db.execSQL(sql); onCreate(db); } publicCursorselect(){ SQLiteDatabasedb=this.getReadableDatabase(); Cursorcursor=db.query(TABLE_NAME,null,null,null,null,null,null); returncursor; } publiclonginsert(Stringtext){ SQLiteDatabasedb=this.getReadableDatabase(); ContentValuescv=newContentValues(); cv.put(FIELD_TEXT,text); longrow=db.insert(TABLE_NAME,null,cv); returnrow; } publicvoiddelete(intid){ SQLiteDatabasedb=this.getReadableDatabase(); Stringwhere=FIELD_id+"=?"; String[]whereValue={Integer.toString(id)}; db.delete(TABLE_NAME,where,whereValue); } publicvoidupdate(intid,Stringtext){ SQLiteDatabasedb=this.getReadableDatabase(); Stringwhere=FIELD_id+"=?"; String[]whereValue={Integer.toString(id)}; ContentValuescv=newContentValues(); cv.put(FIELD_TEXT,text); db.update(TABLE_NAME,cv,where,whereValue); } } 本文转自sucre03 51CTO博客,原文链接:http://blog.51cto.com/sucre/765101,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android开发学习笔记:浅谈WebView

WebView(网络视图)能加载显示网页,可以将其视为一个浏览器。它使用了WebKit渲染引擎加载显示网页,实现WebView有以下两种不同的方法: 第一种方法的步骤: 1.在要Activity中实例化WebView组件:WebView webView = new WebView(this); 2.调用WebView的loadUrl()方法,设置WevView要显示的网页: 互联网用:webView.loadUrl("http://www.google.com"); 本地文件用:webView.loadUrl("file:///android_asset/XX.html");本地文件存放在:assets文件中 3.调用Activity的setContentView()方法来显示网页视图 4.用WebView点链接看了很多页以后为了让WebView支持回退功能,需要覆盖覆盖Activity类的onKeyDown()方法,如果不做任何处理,点击系统回退剪键,整个浏览器会调用finish()而结束自身,而不是回退到上一页面 5.需要在AndroidManifest.xml文件中添加权限,否则会出现Web page not available错误。<uses-permissionandroid:name="android.permission.INTERNET"/> 下面是具体例子: MainActivity.java packagecom.android.webview.activity; importandroid.app.Activity; importandroid.os.Bundle; importandroid.view.KeyEvent; importandroid.webkit.WebView; publicclassMainActivityextendsActivity{ privateWebViewwebview; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); //实例化WebView对象 webview=newWebView(this); //设置WebView属性,能够执行Javascript脚本 webview.getSettings().setJavaScriptEnabled(true); //加载需要显示的网页 webview.loadUrl("http://www.51cto.com/"); //设置Web视图 setContentView(webview); } @Override //设置回退 //覆盖Activity类的onKeyDown(intkeyCoder,KeyEventevent)方法 publicbooleanonKeyDown(intkeyCode,KeyEventevent){ if((keyCode==KeyEvent.KEYCODE_BACK)&&webview.canGoBack()){ webview.goBack();//goBack()表示返回WebView的上一页面 returntrue; } returnfalse; } 在AndroidManifest.xml文件中的17行添加权限 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.webview.activity" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="10" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-permission android:name="android.permission.INTERNET"/> </manifest> 效果图: 第二种方法的步骤: 1、在布局文件中声明WebView 2、在Activity中实例化WebView 3、调用WebView的loadUrl( )方法,设置WevView要显示的网页 4、为了让WebView能够响应超链接功能,调用setWebViewClient( )方法,设置 WebView视图 5、用WebView点链接看了很多页以后为了让WebView支持回退功能,需要覆盖覆盖Activity类的onKeyDown()方法,如果不做任何处理,点击系统回退剪键,整个浏览器会调用finish()而结束自身,而不是回退到上一页面 6、需要在AndroidManifest.xml文件中添加权限,否则出现Web page not available错误。 <uses-permission android:name="android.permission.INTERNET"/> 下面是具体的例子: MainActivity.java packagecom.android.webview.activity; importandroid.app.Activity; importandroid.os.Bundle; importandroid.view.KeyEvent; importandroid.webkit.WebView; importandroid.webkit.WebViewClient; publicclassMainActivityextendsActivity{ privateWebViewwebview; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); webview=(WebView)findViewById(R.id.webview); //设置WebView属性,能够执行Javascript脚本 webview.getSettings().setJavaScriptEnabled(true); //加载需要显示的网页 webview.loadUrl("http://www.51cto.com/"); //设置Web视图 webview.setWebViewClient(newHelloWebViewClient()); } @Override //设置回退 //覆盖Activity类的onKeyDown(intkeyCoder,KeyEventevent)方法 publicbooleanonKeyDown(intkeyCode,KeyEventevent){ if((keyCode==KeyEvent.KEYCODE_BACK)&&webview.canGoBack()){ webview.goBack();//goBack()表示返回WebView的上一页面 returntrue; } returnfalse; } //Web视图 privateclassHelloWebViewClientextendsWebViewClient{ @Override publicbooleanshouldOverrideUrlLoading(WebViewview,Stringurl){ view.loadUrl(url); returntrue; } } } main.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <WebView android:id="@+id/webview" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout> 在AndroidManifest.xml文件中的17行添加权限 <?xmlversion="1.0"encoding="utf-8"?> <manifestxmlns:android="http://schemas.android.com/apk/res/android" package="com.android.webview.activity" android:versionCode="1" android:versionName="1.0"> <uses-sdkandroid:minSdkVersion="10"/> <applicationandroid:icon="@drawable/icon"android:label="@string/app_name"> <activityandroid:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <actionandroid:name="android.intent.action.MAIN"/> <categoryandroid:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> <uses-permissionandroid:name="android.permission.INTERNET"/> </manifest> 效果图: 本文转自 lingdududu 51CTO博客,原文链接:http://blog.51cto.com/liangruijun/647456

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册