首页 文章 精选 留言 我的

精选列表

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

Objective-C 学习第三天

封装 一、 什么是错误 一般情况下,错误是指源代码不符合语法规范,然后编译报错 后果: 程序无法编译 什么是Bug? 程序可以编译、链接、执行,但是程序执行的结果不是我们预想的。 解决: 通过调试寻找发生Bug的原因. 异常 程序可以编译、链接、执行,当程序在执行的时候,处于某种特定的条件下,程序就会终止。 后果: 程序立即终止运行 如何处理异常 1). 目的: 为了让程序在执行的时候如果发生了异常而不崩溃 2). 语法 @try{ }@catch(NSException *ex){ } 将有可能发生异常的代码放在@try中. 当@try中的代码在执行的时候,如果发生了异常,不会奔溃,而是立即跳到@catch中执行代码。 当@catch的代码执行完毕后,结束@try...@catch往下执行. 如果没有发生异常, 则跳过@catch往下执行. 3). 当@try中的代码在执行的时候发生了异常,@try块发生异常后面的代码不会被执行. @catch中的代码只有在@try的代码发生异常的时候才会被执行,所以@catch中我们一般情况下写处理异常的代码. @catch的参数NSException *ex通过%@打印出ex指向对象的值,可以拿到发生异常的原因 @try...@catch后面还可以跟1个@finally块 ``` @try{ }@catch(NSException *ex){ }@finally{ } ``` @try...@catch并不是万能的, 并不是所有的运行时错误都可以处理的。 类方法 0). 在一个Target中无法访问另外一个Target中的方法. 1). OC中的方法分为两种 a. 对象方法/实例方法 想要调用对象方法就必须要先创建对象,然后调用 b. 类方法 类方法的调用不依赖于对象. 如果要调用类方法,不需要创建对象 2). 类方法声明 a. 对象方法的声明: 对象方法的声明 - 号 - (返回值)方法名; - (void)sayHi; b. 类方法的声明: 类方法声明使用 + 号 + (返回值类型)方法名; 3). 调用 a. 对象方法: 先创建对象再通过对象名来调用 b. 类方法: 不需要创建对象, 直接使用类名来调用 [类名 类方法名]; 4). 分析类方法和对象方法 a. 类方法的特点 a). 节约空间 b). 提高效率 5). 在类方法中不能直接访问属性 因为属性只有在对象创建的时候才会创建在对象之中,而类方法在执行的时候有可能还没有对象。 虽然不能直接访问属性,但是我们可以在类方法中创建一个对象访问这个对象 a. 属性是在对象创建的时候跟随着对象一起创建在对象之中 b. 类第1次在访问时回做类加载 在类方法中不能使用self来调用其他对象方法 [self 方法名];//调用当前类型的方法 在对象方法当中可以调用类方法 [类名 方法名]; 什么时候可以将方法定义为类方法 如果方法不需要直接访问属性,也不需要直接调用其他的对象方法,可以定义为类方法 关于类方法的规范. 1). 如果我们写一个类,要求为这个类提供一个与类名同名的方法,这个方法创建 创建一个纯净的对象返回. 苹果和第三方都遵守这个规范 (Person *)person; 2). 如果希望创建的对象的属性的值由调用者指定,那么这个类方法带参数. 类名WithXXX:... (Person *)personWithName:(NSString *)name andAge:(int)age; 二、 NSString 是1个数据类型,用来保存OC字符串的 其实NSString是Foundation框架中的1个类,作用存储OC字符串.所以OC中的字符串本质上是用NSString对象来存储的. 完整的标准的创建NSString对象的方式 NSString *str = [NSString new]; NSString *str1 = [NSString string]; 这种方式创建的字符串是空字符串 @"" 但是NSString是最常用的1个对象, 所以OC使用了1种更为简单的方式来创建对象,直接使用@来表示1个OC字符串. NSString *str = @"jack"; @"jack" 本质上是一个NSString对象,str是这个对象的地址. NSString最常用的类方法 1). + (instancetype)stringWithUTF8String:(const char *)nullTerminatedCString instancetype作为返回值,代表返回当前这个类的对象 char *str0 = "rost"; NSString *str1 = [NSString stringWithUTF8String:str0]; 2). + (instancetype)stringWithFormat:(NSString *)format, ...使用频率非常高 作用: 拼接1个字符串对象,使用变量或者其他数据拼接成OC字符串 int age = 19; NSString *name = @"小明"; [NSString stringWithFormat: @"大家好,我叫%@, 我今年%d岁.",name,age] 最长用的对象方法 1). length方法, 返回值NSUInteger,计算字符串长度 NSString *str = @"itcast"; NSUInteger len = [str length]; 2). 得到字符串中指定下标的字符 (unichar)characterAtIndex:(NSUInteger)index; 返回值是unichar, 其实就是unsigned short,占据两个字节. 如果要输出unichar变两个的值使用%C NSString *str = @"itcast"; unichar ch = [str characterAtIndex:2]; 3). 判断两个字符串是否相同 a. 判断两个字符串内容是否相同, 不要使用==判断 b. 判断相等的方式 - (BOOL)isEqualToString:(NSString *)aString; 判断两个字符串是否相等应该使用上面的方法来判断. NSString *str1 = @"jack"; NSString *str2 = @"jack"; [str1 isEqualToString: str2]; 4). 判断两个字符串大小 - (NSComparisonResult)compare:(NSString *)string; NSComparisonResult是个枚举, 完全可以使用int来接收返回值. NSString *str1 = @"jack"; NSString *str2 = @"jack"; [str1 compare: str2]; 匿名对象 1). 之前创建对象的做法: Person *p1 = [Person new]; 让1个指针指向1个对象 2). 匿名对象 没有名字的对象, 如果我们创建一个对象,没有用1个指针存储这个对象的地址,也就是没有任何指针指向这个对象,那么这个对象就叫做匿名对象. 3). 如何使用1个匿名对象 [Person new]->_name = @"jack"; [[Person new] sayHi]; 4). 注意点 a. 匿名对象只能使用一次 b. 每次创建匿名对象都是不同的对象 5). 使用情况 a. 某个对象只会被使用一次 b. 如果方法的参数是一次对象, 并且这个对象调用者不会使用 三、 面向对象的三大特征: 封装、继承、多态 封装: a. 函数就是封装的体现 b. 类就是更高级别的封装 好处: ->屏蔽内部的实现, 外界不需要知道内部是如何实现的 ->方便操作 继承: 多态: setter封装 1). 将属性的@public去掉, 一旦写上@public就可以直接访问对象的这个属性. 为类提供1个方法,专门为这个属性赋值,这个方法我们叫做setter。 a. 这个方法一定是1个对象方法 b. 没有返回值 c. 这个方法的名称必须以set开头, 跟上去掉下划线首字母大写的属性名. d. 这个方法一定是有参数的, 参数的类型和属性的类型一致, 参数的名称和属性的名称一致(去掉下划线) e. 在方法的实现中,检测传入的数据是否符合要求 // 声明 @interface Person : NSObject{ int _age; } - (void) setAge(int age); @end // 实现 @implementation Person - (void) setAge(int age){ _age = age; } @end // 调用 Person *p = [Person new]; [p setAge:10]; getter封装 1). 用来取出属性的值 a. 这个方法一定是一个对象方法 b. 这个方法返回值类型和属性的类型一致 c. 这个方法的名称直接属性的名称(去掉下划线) d. 这个方法没有参数 e. 外界想要获取这个值,直接调用方法即可. // 声明 @interface Person : NSObject{ int _age; } - (void) setAge(int age); - (int)age(); @end // 实现 @implementation Person - (void) setAge(int age){ // 可以做验证 _age = age; } - (int)age(){ return _age; } @end // 调用 Person *p = [Person new]; [p setAge:10]; [p age]; 注意 属性的@public一定要去掉 判断参数的值是否符合逻辑 getter/setter方法名极度不规范 什么时候需要封装getter/setter 1). 只要属性需要被外界访问就要回这个属性封装setter和getter, 就算赋值或者取值的时候没有任何逻辑验证 2). 如果属性只在内部访问, 不需要封装getter/setter 只读只写封装 只读封装: 为属性封装的时候,只提供getter属性 只写封装: 为属性封装的时候,只提供setter属性 对象之间的关系 1). 组合关系: 一个类是由其他几个类组合而成的 2). 依赖关系: 一个对象的方法的参数是另外一个类 a. 耦合度: 当一个类修改之后另一个类无法使用,叫高耦合 b. 低耦合:当一个类修改之后另一个类正常使用,叫高耦合 c. 高内聚: 一个对象仅仅只做自己相关的事情 d. 单一职责原则: 一个类只做自己的事情 3). 关联关系: 两个类之间语义级别的一种强依赖关系, 拥有关系 4). 继承关系:

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

Objective-C 学习第四天

一、 Xcode文档的安装 1). Xcode文档提供了很多框架, 框架当中有很多类和函数, 提供的一些数据类型. 2). Xcode文档需要单独安装. a. 在线安装: Xcode-> Preferences...->Downloads->Xcode文档 b. 离线安装: 路径:/Applications/Xcode.app/Contents/Developer/Documentation/DocSets/ 点击Window->Documentation and API Reference. static 关键字 1). C语言中的static a. 修饰局部变量: 把局部变量变成静态变量 b. 修饰全局变量 c. 修饰函数 2). OC中的static a. static不能修饰属性也不能修饰方法 b. 可以修饰方法中的局部变量 如果方法中的局部变量被static修饰, 这个变量就会被变成静态变量.存储在常量区 self关键字 1). 方法的内部可以定义一个与类属性相同的变量, 这个时候如果在方法中访问这个同名的变量, 则访问的是局部变量. 2). self: 自己的. 和Java、C#中的this关键字有点像. 可以在对象方法和类方法中使用. self是1个指针, 在对象方法中self指向当前对象, 在类方法中self指向当前类. 3). self用在对象方法中 a. self在对象方法中, 指向当前对象 b. 可以使用self显示的调用当前对象的属性 c. 可以使用self来调用当前对象的其他对象方法 NSLog(@"self = %p", self); NSLog(@"_name = %s", self->_name); [self hehe]; d. 必须使用self场景 a). 如果在方法当中存在和属性同名的局部变量,如果想要访问同名的局部变量,直接写就可以了,如果想要访问当前对象的同名属性,必须使用self b). 在对象方法中,如果要调用当前对象的对象方法必须使用self e. 选用self场景 如果这个时候想要访问对象的属性, 可以选择性使用. f. 属性要求以下划线开头, 局部变量不要求以下划线开头. 4). 把self用在类方法中 a. 类加载:当类第1次被访问的时候,会将类的代码存储在代码区 b. 在类方法中, self也是一个指针,指向当前类 c. 获取类在代码段中的地址 a). 调试, 获取isa指针 b). 在类方法中查看self值 c). 调用对象的对象方法class d). 调用类的类方法class d. 可以用self调用本类中的其他类方法 5). 对象方法可以声明多次,但只能实现一次. 对象方法和类方法可以重名. 6). 注意 a. 在对象方法中可以通过self访问当前对象成员, 不能使用self调用本类中的类方法 b. 在类方法中, 可以使用self调用当前类中的其他类方法.不能使用self访问对象成员. 继承 1). 继承的目的: 子类想拥有父类中的所有成员 2). 语法 ``` @interface 类名 : 父类 @end ``` 3). 效果: 子类拥有了父类的所有的成员 4). 术语 @interface Student : Person{ } Student类从Person类继承,Student类是Person类的子类, Person类是Student类的父类. 5). 在新创建类模块的时候指定父类, Xcode自动完成 6). 继承是类在继承,而不是对象在继承. 创建的对象与对象之间没有任何关系. 7). 继承的时候不要乱继承. 凡是满足is a关系的类,就可以拥有继承的关系. 8). 如果有1个成员不是所有子类都拥有,那么这个成员就不应该定义在父类之中 二、 继承的特性 1). 单根性: 一个类只能有两个父类 2). 传递性: A类从B类继承,B类从C类集成 NSObject类 是Foundation框架中的类.在这个类中有1个类方法new,这个方法是用来创建对象的,方法的返回值是创建这个对象的指针. 如果我们想要让类具备创建对象的能力,就必须直接或者间接的要从NSObject类继承. 在NSObject类中,有一个属性叫isa指针. NSObject类是OC中所有类的祖宗类. 子类不能存在和父类同名的属性. super关键字 1). 可以用在类方法和对象方法中 2). 在对象方法中可以使用super关键字调用从父类继承过来的方法 3). 在类方法中 super关键字可以调用从父类继承过来的类方法 a. 类方法也能被子类继承, 可以使用子类调用也可以使用父类调用 b. 在子类的类方法中,可以使用super关键字调用父类的类方法 4). super不能访问属性,只能调用父类的对象方法或者类方法 访问修饰符 1). 用来修饰属性,可以限定对象可以在哪一段访问 2). 修饰符 @private: 私有,仅允许本类访问 @protected: 受保护的,允许本类及子类访问 @package: 被@package修饰的属性可以在当前框架中访问 @public: 公共的,可以在任意地方访问 3). 默认属性为@protected 4). 子类可以继承子类的私有属性,只是无法访问 5). 如果父类有一个方法为属性赋值或者取值,子类可以间接的访问这个属性 6). 使用建议 a. @public 无论什么情况下都不要使用,属性不要直接暴露给外界 b. @private 如果属性只想在本类中使用不想在子类中使用,就使用她 c. @protected 本类及子类使用 d. 推荐使用默认的@protected 7). 访问修饰符只能用来修饰属性, 不能用来修饰方法 私有属性和方法 1). @private修饰的属性叫做私有属性,只能在类的内部访问,但是在外界的时候Xcode仍然会提示这个属性,只不过没有权限访问. 2). 在@implementation中写一个大括弧,把属性定义在@implementation中做到真私有,外界无法看到。访问修饰符无效. 将属性定义在@implementation之中和将属性定义在@interface中并标记为@private的区别是提示与不提示,都不能在外界访问. 示例: //实现 @implementation Person{ int num;// 真私有 } @end 3). 私有方法 方法只写实现不写声明即可做到方法私有,只能在本类的其他方法中调用,不能在外界调用 1). 里氏替换原则(LSP):子类可以替换父类的位置,并且功能不受影响 a. 父类指针迫切的需求1个父类对象,而我们给了1个对象完全没有问题,因为子类就是1个父类. b. 因为父类中拥有的成员子类都有,所以不会影响程序的功能 2). 里氏替换原则的变现形式 a. 当1个指针指向1个子类对象的时候 3). 作用: a. 一个指针不仅可以存储本类对象的地址还可以存储子类对象的地址 b. 如果1个指针的类型是NSObject类型的,那么这个指针可以存储任意的OC对象地址. c. 如果一个指针数组是NSObject类型的,那么它可以存任意指针. d. 如果一个方法的参数是一个对象,那么我们可以为这个参数传递本类对象或者子类对象 4). 当一个父类指针指向指向一个子类对象的时候,通过父类指针只能调用这个子类对象当中的成员. 5). 方法的重写 a. 直接在子类的实现中将这个方法重新实现一遍 b. 当父类指针指向1个子类对象的时候.通过父类指针调用的方法,如果子类重写了,那么调用的就是子类的方法. 多态 指的是同一个行为,对于不同的事物具有完全不同的表现形式. description 1). %p 打印的是指针变量的值 %@ 打印的是指针指向的变量 2). 使用%@打印1个对象 输出的格式: <对象所属的类名: 对象的地址> 3). 原理 当使用%@打印1个对象的时候,NSLog的底层实现, 调用传入的对象的description方法, 拿到这个方法的返回值, 将这个字符串输出. 4). description方法是定义在NSObject类之中的. 实现: 返回的字符串格式@"<对象所属类名:对象的地址>" 5). 重写description方法(类似于Java中的toString方法) - (NSString *)description{ return [NSString stringWithFormat:@"姓名"]; } 6). 如果你希望%@打印一个对象的时候,对象的格式我们自己指定

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

Docker学习笔记——制作容器与容器概念

Docker能做些什么? 1.docker能够解决虚拟机能够解决的问题 2.隔离应用依赖 3.创建应用镜像并复制 4.创建容易分发的即启即用的应用 5.docker的想法是创建软件程序可移植的轻量容器 镜像 1.docker的镜像类似虚拟机的快照 2.在现有镜像的基础上创建镜像 容器 1.可以从镜像中创建容器 2.容器和虚拟机一样是隔离的,它也拥有一个唯一ID和唯一供读人的名字,docker允许公开容器的公开端口 3.容器是被来设计运行一个应用的 而不是一台机器 4.容器应该是短暂和一次性的 链接: 1.容器启动时将会被分配一个私有IP,其他容器可以使用这个IP与其进行通讯,因此,容器可以共享一个本地网络 2.docker允许你在创建一个新容器时引用其他现存容器,在你刚创建的容器中被引用的容器会获得一个别名,我们就可以定义 ,这两个容器链接在了一起。 3.比如一个DB容器已经在运行,我们创建web容器的时候引用这个DB容器,给它起一个别名叫做dbapp,那么在这个新建的web容器中,我们可以在任何时候使用主机名dbapp和DB通信 docker的两样法宝 Cgroups 作用: 限制linux进程组的资源占用 为进程组制作PIDS,UTS,IPC,网络和装载命名空间 Cgroup创建一个环境,进程可以在其中运行,并与操作系统的其他进程进行隔开 容器runtime 容器runtime是容器真正运行的地方,runtime需要和操作系统kernel紧密结合,为容器提供运行环境。 比如说,java程序比作一个容器,JVM就是runtime。JVM为java程序提供运行环境。 所以容器只能在runtime里面运行 lxc、runc 和 rkt 是目前主流的三种容器 runtime。lxc 是 Linux 上老牌的容器 runtime。Docker 最初也是用 lxc 作为 runtime。runc 是 Docker 自己开发的容器 runtime,符合 oci 规范,也是现在 Docker 的默认 runtime。rkt 是 CoreOS 开发的容器 runtime,符合 oci 规范,因而能够运行 Docker 的容器。 容器管理工具 除了运行环境,使用者也得需要工具来管理容器。容器管理工具对内与runtime交互,对外为用户提供interface. lxd是lxc对应的容器管理工具;runc的管理工具是docker engine。docker engine 包含后台 deamon 和 cli 两个部分。我们通常提到 Docker,一般就是指的 docker engine。rkt 的管理工具是 rkt cli。 容器定义工具 容器定义工具允许用户定义容器的内容属性,这样容器就能够被保存,共享和重建 docker image 是 docker 容器的模板,runtime 依据 docker image 创建容器。dockerfile 是包含若干命令的文本文件,可以通过这些命令创建出 docker image。ACI (App Container Image) 与 docker image 类似,只不过它是由 CoreOS 开发的 rkt 容器的 image 格式。 仓库Registy 容器是通过image创建的,需要一个仓库统一存放image,这个仓库就叫做Registy 企业可以用 Docker Registry 构建私有的 Registry。Docker Hub(https://hub.docker.com )是 Docker 为公众提供的托管 Registry,上面有很多现成的 image,为 Docker 用户提供了极大的便利。Quay.io(https://quay.io/ )是另一个公共托管 Registry,提供与 Docker Hub 类似的服务。 容器OS 因为容器有runtime,所以几乎所有的linux、MAC OS和windows都可以运行容器 容器 OS 是专门运行容器的操作系统。与常规 OS 相比,容器 OS 通常体积更小,启动更快。因为是为容器定制的 OS,通常它们运行容器的效率会更高。 目前已经存在不少容器 OS,CoreOS、atomic 和 ubuntu core 是其中的杰出代表。 容器平台技术 容器核心技术能够让让容器在单个主机上运行,容器平台技术能够让容器作为集群在分布式环境中运行。容器平台技术如下图: 分为容器编排技术、容器管理平台、基于容器的PaaS。 容器编排引擎 基于容器的应用一般会采用微服务架构。在这中间架构下,应用被划分成不同的组件,并以服务的方式运行在各个容器中,通过API对外提供服务,为了保证服务的高可用,每个组件会运行多个相同的容器。 这些容器会组成集群,集群中的容器会根据业务动态的创建、迁移和销毁。 这样基于微服务架构的系统实际上是一个动态可伸缩的系统。容器编排引擎就排上用场了。 编排(orchestration),通常包括容器管理、调度、集群定义和服务发现。通过容器编排引擎、容器被有机的组合成微服务应用,实现业务需求。 docker swarm 是 Docker 开发的容器编排引擎。kubernetes 是 Google 领导开发的开源容器编排引擎,同时支持 Docker 和 CoreOS 容器。mesos 是一个通用的集群资源调度平台,mesos 与 marathon 一起提供容器编排引擎功能。以上三者是当前主流的容器编排引擎。 容器管理平台 容器管理平台是在容器编排引擎之上的一个更为通用的平台。通常容器管理平台能够支持多个编排引擎,抽象了编排引擎的底层实现细节。 比如:application catalog和一键应用部署 Rancher和Containership是容器管理平台的典型代表 容器支持技术 容器网络 容器使得网络变得复杂,用户需要专门的解决方案来管理容器与容器,容器与其他实体之间的连通性和隔离性。 docker network是docker原生的解决方案。 服务发现 微服务的最大特点是动态变化,当负载增加时,集群会自动创建新的容器;负载减小,多余的容器就会被销毁。容器也会根据主机的资源情况在不同主机上迁移,容器的IP和端口也随之改变。 在这种情况下,必须要让客户端能够知道如何访问容器提供的服务。这就是服务发现的工作。 服务发现会保存集群中所有微服务的最新信息,比如IP和端口,对外提供的API,提供服务和查询等。 比较主流的是etcd,consul,zookeeper。 制作第一个容器 准备这些条件: 1.一个Ubuntu系统 2.这个系统能够联网,最起码ping www.baidu.com是可以的 这些准备条件准备好了,接下来就开始做准备工作。 Docker 分为开源免费的 CE(Community Edition)版本和收费的 EE(Enterprise Edition)版本。下面我们将按照文档,通过以下步骤在 Ubuntu 16.04 上安装 Docker CE 版本。 这里下载的是CE版本。 配置Docker的apt源 打开ubuntu虚拟机,ping 一下百度 OK,可以的,因为制作容器的过程中需要联网,这个条件是必要的。 1.安装包,允许apt命令 HTTPS 访问 Docker 源。执行命令: sodo apt-get install apt-transport-https ca-certificate curl software-properties-common 然后会下载一些东西,等待下载完成即可 2.添加 Docker 官方的 GPGsudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -3.将Docker的源添加到/etc/apt/source.list sodu add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" 4.刷新apt源 sudo apt-get update 5.安装Docker sudo apt-get install docker-ce 这步完成之后,Docker也就安装完成了,是不是很简单,接下来就是如何使用Dokcer的问题了。 下载你的第一个容器: docker run -d -p 80:80 httpd 这个过程是,首先docker发现主机上没有http,然后就会去下载(镜像中已经安装好了 Apache HTTP Server),下载完毕之后再运行运行,将容器的80端口映射到主机的80端口。 接下来检测一下容器是否正常运行,浏览器中输入该主机的IP,我这里是192.168.90.71 OK,web服务器运行成功! Docker的第一个helloworld也就大功告成! 什么是容器? 容器是一个自包含,可移植,轻量级的软件打包技术。是应用程序在任何地方几乎以相同方式运行。开发人员在开发机上创建好容器,无需任何修改就能在虚拟机,云服务器或公有云主机上运行。 容器与虚拟机 容器有两部分组成: 1.应用程序本身 2.应用程序所依赖的环境,库 容器在主机中运行,与操作系统中其他的进程隔离,这一点区别于虚拟机。 传统的虚拟机技术,如:vmvare,他是创建一个完整的虚拟机,为了运行应用程序,部署系统,还需要安装整个操作系统(几十GB), 下图展示了两者的区别: 从右图中可以看见,所有容器都共享一个系统,对于虚拟机来说,都是一个单独的系统。 启动容器不需要启动整个系统,所以容器部署和启动速度更快,开销更小,也更容易迁移。 为什么要使用容器技术? 因为方便。这取决于容器使得软件具备超强的可移植能力。 现如今软件开发的部署相对于以前来说,要复杂很多,开发人员需要使用多种服务构建和组装应用,而且系统还可能会部署到不同的环境中。 而且这个服务都有自己依赖的库和环境,还有可能存在着动态迁移到不同的环境中。 大家做过软件开发的都知道,软件部署是一件很麻烦的事情,那么有没有一种技术使得软件部署很平滑呢? 开发人员受到了集装箱的启发。 以前运送货物,会担心货物类型不同而担心损失,比如运送的食物被其他货物压坏了。后来人们发明了集装箱,标准集装箱可以被高效地装卸、重叠和长途运输。现代化的起重机可以自动在卡车、轮船和火车之间移动集装箱。集装箱被誉为运输业与世界贸易最重要的发明。 Docker 将集装箱思想运用到软件打包上,为代码提供了一个基于容器的标准化运输系统。Docker 可以将任何应用及其依赖打包成一个轻量级、可移植、自包含的容器。容器可以运行在几乎所有的操作系统上。 容器意味着环境隔离和可重复性。开发人员只需为应用创建一次运行环境,然后打包成容器便可在其他机器上运行。另外,容器环境与所在的 Host 环境是隔离的,就像虚拟机一样,但更快更简单。 Docker的核心组件: 1.Docker客户端 - Client 2.Docker服务器 - Docker deamon 3.Docker镜像 - Image 4.仓库 - Registry 5.Docker容器 - Container Docker架构图如下: Docker采用的是C/S架构,客户端向服务器发送请求,服务器负责创建、运行和分发容器。 Docker客户端: Docker客户端的命令如下: Docker服务器: Docker deamon是服务器组件,以Linux后台服务方式运行。 Docker daemon 运行在 Docker host 上,负责创建、运行、监控容器,构建、存储镜像。 默认配置下,Docker daemon 只能响应来自本地 Host 的客户端请求。如果要允许远程客户端请求,需要在配置文件中打开 TCP 监听,步骤如下: 1.编辑配置文件 /etc/systemd/system/multi-user.target.wants/docker.service,在环境变量-H tcp://0.0.0.0,允许来自任意 IP 的客户端连接。 2.重启 Docker daemon。 3.服务器 IP 为 192.168.56.102,客户端在命令行里加上 -H 参数,即可与远程服务器通信 Docker镜像 : 可将Docker镜像看成一个只读模板。一个镜像里可能含有一个系统,或者一个Tomcat。 镜像有多种生成方法: 可以从无到有开始创建镜像 也可以下载并使用别人创建好的现成的镜像 还可以在现有镜像上创建新的镜像 我们可以将镜像的内容和创建步骤描述在一个文本文件中,这个文件被称作 Dockerfile,通过执行docker build <docker-file>命令可以构建出 Docker 镜像。 Docker容器: Docker容器就是Docker运行的环境。对于软件而言,镜像像是生命周期的构建和打包阶段,容器则是启动和运行阶段。 Docker仓库Registry: 镜像有多种生成方法: 可以从无到有开始创建镜像 也可以下载并使用别人创建好的现成的镜像 还可以在现有镜像上创建新的镜像 我们可以将镜像的内容和创建步骤描述在一个文本文件中,这个文件被称作 Dockerfile,通过执行docker build <docker-file>命令可以构建出 Docker 镜像. docker pull 命令是从Registry下载镜像 docker run命令是先下载镜像 然后再启动容器 下面看一个运行实例: Docker 客户端执行docker run命令。 Docker daemon 发现本地没有 httpd 镜像。 daemon 从 Docker Hub 下载镜像。 下载完成,镜像 httpd 被保存到本地。 Docker daemon 启动容器。 docker images 可以看下已经下载到本地的镜像。 dokcer ps 可以查看哪些容器正在运行 镜像的分层结构: 实际上,Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的。比如我们现在构建一个新的镜像,Dockerfile 如下: ① 新镜像不再是从 scratch 开始,而是直接在 Debian base 镜像上构建。② 安装 emacs 编辑器。③ 安装 apache2。④ 容器启动时运行 bash。 构建过程如下图所示: 可以看到,新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。 问什么 Docker 镜像要采用这种分层结构呢? 最大的一个好处就是 -共享资源。 比如:有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享,我们将在后面更深入地讨论这个特性。 这时可能就有人会问了:如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如 /etc 下的文件,这时其他容器的 /etc 是否也会被修改? 答案是不会!修改会被限制在单个容器内。因为容器的Copy-on-Write特性 可写的容器层 当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。 所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。 添加文件在容器中创建文件时,新文件被添加到容器层中。 读取文件 在容器中读取某个文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后打开并读入内存。 修改文件 在容器中修改已存在的文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后修改之。 删除文件 在容器中删除文件时,Docker 也是从上往下依次在镜像层中查找此文件。找到后,会在容器层中记录下此删除操作。 只有当需要修改时才复制一份数据,这种特性被称作 Copy-on-Write。可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改。 这样就解释了我们前面提出的问题:容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享。 如何构建镜像 使用现成镜像的好处除了省去自己做镜像的工作量外,更重要的是可以利用前人的经验。特别是使用那些官方镜像,因为 Docker 的工程师知道如何更好的在容器中运行软件。 当然,某些情况下我们也不得不自己构建镜像,比如: 找不到现成的镜像,比如自己开发的应用程序。 需要在镜像中加入特定的功能,比如官方镜像几乎都不提供 ssh。 所以本节我们将介绍构建镜像的方法。同时分析构建的过程也能够加深我们对前面镜像分层结构的理解。 Docker 提供了两种构建镜像的方法: docker commit 命令 Dockerfile 构建文件 Docker官方推荐使用Dockerfile构建镜像。 镜像缓存 Docker 会缓存已有镜像的镜像层,构建新镜像时,如果某镜像层已经存在,就直接使用,无需重新创建。 Dockerfile 中每一个指令都会创建一个镜像层,上层是依赖于下层的。无论什么时候,只要某一层发生变化,其上面所有层的缓存都会失效。 也就是说,如果我们改变 Dockerfile 指令的执行顺序,或者修改或添加指令,都会使缓存失效。 DockerFile Dockerfile指令说明 指令 说明 用法 FROM 指定base镜像 两种用法: 1.FROM <image> 指定基础image为该image的最后修改的版本 2.FROM <image>:<tag> 指定基础image为该image的一个tag版本。 MAINTAINER 设置镜像的作者,用于将image的制作者相关的信息写入到image中 MAINTAINER<name> RUN 在容器中运行制定的命令, 一般用于装软件 两种格式: 1.RUN <command> (the command is run in a shell - `/bin/sh -c`) 2.RUN ["executable", "param1", "param2" ... ] (exec form) CMD (设置container启动时执行的操作) 三种方式 CMD["executable","param1","param2"] 2.CMD command param1 param2 (as a shell) 第三种方式:当指定了ENTRYPOINT,那么使用下面的格式 CMD ["param1","param2"] (as default parameters to ENTRYPOINT) ENTRYPOINT指定的是一个可执行的脚本或者程序的路径,该指定的脚本或者程序将会以param1和param2作为参数执行。所以如果CMD指令使用上面的形式,那么Dockerfile中必须要有配套的ENTRYPOINT。 ENTRYPOINT 配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。 每个 Dockerfile 中只能有一个 ENTRYPOINT,当指定多个时,只有最后一个起效。 ENTRYPOINT ["executable", "param1", "param2"] (like an exec, the preferred form) ENTRYPOINT command param1 param2 (as a shell) 该指令的使用分为两种情况,一种是独自使用,另一种和CMD指令配合使用。 当独自使用时,如果你还使用了CMD命令且CMD是一个完整的可执行的命令,那么CMD指令和ENTRYPOINT会互相覆盖只有最后一个CMD或者ENTRYPOINT有效。 # CMD指令将不会被执行,只有ENTRYPOINT指令被执行 CMD echo “Hello, World!” ENTRYPOINT ls -l 另一种用法和CMD指令配合使用来指定ENTRYPOINT的默认参数,这时CMD指令不是一个完整的可执行命令,仅仅是参数部分;ENTRYPOINT指令只能使用JSON方式指定执行命令,而不能指定参数。 FROM ubuntu CMD ["-l"] ENTRYPOINT ["/usr/bin/ls"] EXPOSE 设置指令,该指令会将容器中的端口映射成宿主机器中的某个端口。当你需要访问容器的时候,可以不是用容器的IP地址而是使用宿主机器的IP地址和映射后的端口。要完成整个操作需要两个步骤,首先在Dockerfile使用EXPOSE设置需要映射的容器端口,然后在运行容器的时候指定-p选项加上EXPOSE设置的端口,这样EXPOSE设置的端口号会被随机映射成宿主机器中的一个端口号。 EXPOSE <port> [<port>...] ENV 用于设置环境变量 设置了后,后续的RUN命令都可以使用,容器启动后,可以通过docker inspect查看这个环境变量,也可以通过在docker run --env key=value时设置或修改环境变量。 假如你安装了JAVA程序,需要设置JAVA_HOME,那么可以在Dockerfile中这样写: ENV JAVA_HOME /path/to/java/dirent ADD 从src复制文件到容器的dest路径 如果是一个目录,那么会将该目录下的所有文件添加到容器中,不包括目录;如果文件是可识别的压缩格式,则docker会帮忙解压缩(注意压缩格式) ADD<src> <dist> <src>是相对被构建的源目录的相对路径,可以是文件或目录的路径,也可以是一个远程的文件url; <dist>是容器的绝对路径 VOLUMN 设置指令,使容器中的一个目录具有持久化存储数据的功能,该目录可以被容器本身使用,也可以共享给其他容器使用。我们知道容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失。当容器中的应用有持久化数据的需求时可以在Dockerfile中使用该指令。 VOLUME ["<mountpoint>"] 例: FROM unbuntu VOLUMN [“/tmp/data”]运行通过该Dockerfile生成image的容器,/tmp/data目录中的数据在容器关闭后,里面的数据还存在。 WORKDIR 可以多次切换(相当于cd命令),对RUN,CMD,ENTRYPOINT生效。 例:# 在 /p1/p2 下执行 vim a.txt WORKDIR /p1 WORKDIR p2 RUN vim a.txt 个人博客网站 http://www.janti.cn

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

Docker容器学习梳理--手动制作系统镜像

docker官方和个人发布的镜像由于版本等各种原因,漏洞较多,已统计Docker Hub超过30%的官方镜像包含高危漏洞。此外,由于网络等原因也会造成docker pull下载镜像的速度很慢。基于这种情况,我们可以手动定制docker系统镜像。 以下记录了在centos7上做docker镜像的操作记录: 1)镜像制作脚本:mkimage-yum.sh 1 2 3 4 5 下载脚本地址:https: //pan .baidu.com /s/1geTSQCN 提取密码:qsss 或者直接wget https: //raw .githubusercontent.com /docker/docker/master/contrib/mkimage-yum .sh 2)执行脚本 1 2 [root@docker~] #chmod755mkimage-yum.sh [root@docker~] #./mkimage-yum.sh-y/etc/yum.confcentos7 3)脚本执行成功后,检查docker本地镜像 1 2 3 4 [root@docker~] #dockerimages REPOSITORYTAGIMAGEIDCREATEDSIZE centos77.4.1708dfb0a7b344e821secondsago271MB centoslatestff426288ea903weeksago207MB 如上已经发现了自己制定的镜像centos7 4)使用制定的镜像启动容器 1 2 3 [root@docker~] #dockerrun-i-tcentos7:7.4.1708/bin/bash [root@ec39943f795a/] #cat/etc/redhat-release CentOSLinuxrelease7.4.1708(Core) 提醒:制定的镜像和官方的镜像差不多干净。 本文转自 dengaosky 51CTO博客,原文链接:http://blog.51cto.com/dengaosky/2067350,如需转载请自行联系原作者

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

[Hadoop In Action]学习笔记-Hadoop中的Streaming

Hadoop支持非java预言来编写程序,这就会用到Streaming的通用API。 Hadoop Streaming使用流与程序进行交互。从STDIN输入数据,输出到STDOUT。数据必须为文本,而且每一行被视为一条记录。 用Streaming处理键-值 默认情况下,Streaming使用制表符分离记录中的键与值。当没有制表符时,整个记录被视为键,而值为空白文本。 Streaming API把reducer输出的每一行用制表符分开,并将键值对送入默认的TextOutputFormat中,即在结果被写入文件之前,默认的重新插入一个制表符 本文转自 virusswb 51CTO博客,原文链接:http://blog.51cto.com/virusswb/838607,如需转载请自行联系原作者

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

openstack学习笔记八 glance安装配置

镜像 安装过系统的虚拟硬盘 管理是用glance来完成。 镜像的状态: active 镜像已经上传完成,并且是可用的 saving 正在被上传,还没有完成 killed 上传出错 queued 并没有真的上传完成,但是被标记有这个镜像 安装glance 在 keystone注册 glance所需要的账户 创建glance服务 指定glance服务的endpoint 安装 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [root@h4~] #yum-yinstallopenstack-glance.noarch [root@h4~] #openstack-db--init--serviceglance--password123456-rootpw123456 [root@h4~(keystone_admin)] #keystoneuser-create--nameglance--pass123456 [root@h4~(keystone_admin)] #keystoneuser-role-add--userglance--tenantservices--roleadmin [root@h4~(keystone_admin)] #keystoneservice-create--nameglance--typeimage--description"glancejingxiang" [root@h4~(keystone_admin)] #keystoneendpoint-create--service-id3d0969b633044029a895da1ca2855464--publicurl'http://192.168.1.204:9292'--internalurl'http://192.168.1.204:9292'--adminurl'http://192.168.1.204:9292' +-------------+----------------------------------+ |Property|Value| +-------------+----------------------------------+ |adminurl|http: //192 .168.1.204:9292| | id |e0f7718b18444f71a43762ca3336ef06| |internalurl|http: //192 .168.1.204:9292| |publicurl|http: //192 .168.1.204:9292| |region|regionOne| |service_id|3d0969b633044029a895da1ca2855464| +-------------+----------------------------------+ 修改配置文件 1 2 3 4 5 6 7 8 9 10 11 12 13 [root@h4glance(keystone_admin)] #systemctllist-unit-files|grepglanc openstack-glance-api.servicedisabled接受用户的请求 openstack-glance-registry.servicedisabled和数据库进行交互 openstack-glance-scrubber.servicedisabled和其他接口进行交互 [root@h4glance(keystone_admin)] #ls glance-api.confglance-registry.confmetadefsschema-image.json glance-cache.confglance-scrubber.confpolicy.json [root@h4glance(keystone_admin)] #cd/usr/share/glance/模板 [root@h4glance(keystone_admin)] #ls glance-api-dist.confglance-registry-dist.conf glance-api-dist- paste .iniglance-registry-dist- paste .ini glance-cache-dist.confglance-scrubber-dist.conf [root@h4glance(keystone_admin)] #cpglance-api-dist.conf/etc/glance/glance-api.conf##拷贝模板 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 [root@h4glance(keystone_admin)] #vimglance-api.conf [DEFAULT] debug=False verbose=True use_stderr=False log_file= /var/log/glance/api .log filesystem_store_datadir= /var/lib/glance/images/ scrubber_datadir= /var/lib/glance/scrubber image_cache_dir= /var/lib/glance/image-cache/ rabbit_host=192.168.1.204 rabbit_port=5672 rabbit_hosts=$rabbit_host:$rabbit_port rabbit_use_ssl= false rabbit_userid=guest rabbit_password=guest rabbit_login_method=AMQPLAIN [database] connection=mysql: //glance :123456@192.168.1.204 /glance [keystone_authtoken] admin_tenant_name=services admin_user=glance admin_password=123456 auth_host=192.168.1.204 auth_port=35357 auth_protocol=http auth_uri=http: //192 .168.1.204:5000/ [paste_deploy] config_file= /usr/share/glance/glance-api-dist-paste .ini flavor=keystone 1 2 3 [root@h4glance] #chownroot.glanceglance-api.conf [root@h4glance] #systemctlstartopenstack-glance-api.serviceopenstack-glance-registry.serviceopenstack-glance-scrubber.service [root@h4glance] #systemctlenableopenstack-glance-api.serviceopenstack-glance-registry.serviceopenstack-glance-scrubber.service 管理 1 2 3 4 5 6 7 8 9 10 11 [root@h4~(keystone_admin)] #glanceimage-list +----+------+ |ID|Name| +----+------+ +----+------+ [root@h4~(keystone_admin)] #glancehelpimage-create ##########################先上传一个镜像再创建 [root@h4~(keystone_admin)] #glanceimage-create--namehequan--filehequan.img--disk-formatqcow2--visibilitypublice--container-formatbare##创建 [root@h4~(keystone_admin)] #glanceimage-create--namehequan--os-distrohttp://mirrors.163.com/centos/7.2.1511/isos/x86_64/CentOS-7-x86_64-Minimal-1511.iso--disk-formatiso--container-formatbare filesystem_store_datadir= /var/lib/glance/images/ ###镜像保存的位置 #default_store=file 修改镜像存储位置 swift 做后端存储 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 6 #filesystem_store_datadir=/var/lib/glance/images/##先禁用 [glance_store] default_store=swift默认为 file 改为swift stores= file ,http默认不用动 swift_store_auth_version=2默认版本为2 stores=glance.store.swift.Store,glance.store.filesystem.Store此项一定要加上,不然无法上传 swift_store_auth_address=http: //192 .168.1.204:5000 /v2 .0/controller的keystone认证 swift_store_user=service:swift使用swift用户 swift_store_key=hequan密码 swift_store_container=glance将要被创建的容器 swift_store_create_container_on_put=True上传开 swift_store_large_object_size=5120最大5G限制,但与glance结合后限制无效 swift_store_large_object_chunk_size=200最大200个容器 swift_enable_snet=False [root@h4glance(keystone_admin)] #systemctlrestartopenstack-glance-api.serviceopenstack-glance-registry.serviceopenstack-glance-scrubber.service ceph 共享存储 安装epel仓库 1 2 3 4 5 6 7 8 9 10 11 12 rpm-vihhttp: //mirrors .sohu.com /fedora-epel/7/x86_64/e/epel-release-7-2 .noarch.rpm 添加yumceph仓库 vim /etc/yum .repos.d /ceph .repo [ceph] name=Cephnoarchpackages baseurl=http: //mirrors .163.com /ceph/rpm-hammer/el7/x86_64/ enabled=1 gpgcheck=1 type =rpm-md gpgkey=http: //mirrors .163.com /ceph/keys/release .asc 安装ceph-deploy,ceph(ceph所有节点都安装,ceph-deploy只需admin节点安装) yum-yupdate&&yum-y install --releasehammercephceph-deploy 1 生成相关的MOD信息 监控服务器 h5 1 2 3 [root@h5xx] #ceph-deploynewh5 [root@h5xx] #ls ceph.confceph-deploy-ceph.logceph.mon.keyring 2 要根据自己的情况修改配置文件ceph.conf 1 2 osd_pool_default_size=2 ##几个节点组成,默认是3 osd_pool_defaults_min_size=1 ##最小值是1 3 生成key 当客户端要链接到ceph服务器,需要用户名和密码 1 2 3 4 5 [root@h5xx] #ceph-deploymoncreate-initial [root@h5myceph] #ls ceph.bootstrap-mds.keyringceph.client.admin.keyringceph.mon.keyring ceph.bootstrap-osd.keyringceph.conf ceph.bootstrap-rgw.keyringceph.log 4 开始准备配置OSD 1 2 3 4 mkdir path1path2 [root@h5xx] #ceph-deployosdprepareh5:/path1h6:/path2 [root@h5xx] #ceph-deployosdactivateh5:/path1h6:/path2##激活 [ceph_deploy.osd][DEBUG]Hosth5isnowready for osduse. 5 把key复制到各个节点上去 1 2 [root@h5ceph] #ceph-deployadminh5h6 [root@h5ceph] #cephhealth##健康性检查 6 生成元数据 1 2 3 4 [root@h5ceph] #ceph-deploymdscreateh5 [root@h5ceph] #radoslspools [root@h5ceph] #radosmkpoolglance [root@h5ceph] #radosrmpoolglanceglance--yes-i-really-really-mean-it##删除 glance配置成ceph的客户端 安装ceph 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 [root@h4ceph(keystone_admin)] #ls rbdmap [root@h5myceph] #ceph-deployadminh4 [root@h4ceph(keystone_admin)] #ls ceph.client.admin.keyringceph.confrbdmaptmp6BxOoY vimglance-api.conf [glance_store] default_store=rbd stores=rbd rbd_store_pool=glance rbd_store_user=admin rbd_store_ceph_conf= /etc/ceph/ceph .conf rbd_store_chunk_size=8 systemctlrestartopenstack-glance-api.serviceopenstack-glance-registry.serviceopenstack-glance-scrubber.service -rw-------1rootroot637月2116:43ceph.client.admin.keyring setfacl-mu:glance:r--ceph.client.admin.keyring ##设置权限能读 制作镜像 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 yum-ygroupinstall "ServerwithGUI" yum install virt-managerpython-virtinstqemu-kvm-toolsqemu-kvmlibvirt KVM 创建存储卷centos.qcow2 基本安装 配置网卡删除MAC 安装基本组件openssh-clients cloud-init ##云包 [root@h4~] #vim/etc/default/grub GRUB_CMDLINE_LINUX= "net.ifnames=0biosdevname=0console=tty0console=ttyS0,115200n8rhgbquiet" ##指定串口的参数 [root@h4~] #grub2-mkconfig-o/boot/grub2/grub.cfg 封装 [root@h5~] #yumwhatprovides*/virt-sysprep [root@h5~] #yum-yinstalllibguestfs-bash-completion-1.28.1-1.55.el7.centos.noarch [root@h4~] #virt-sysprep-dcentos [root@h4~] #cd/openstack-image/ [root@h4openstack-image] #qemu-imginfocentos.qcow2 qemu-imgconver-c-oqcow2centos.qcow2newcentos.qcow2 ###3压缩命令 本文转自 295631788 51CTO博客,原文链接:http://blog.51cto.com/hequan/1828592,如需转载请自行联系原作者

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

Android开发学习笔记:Spinner和AutoCompleteTextView浅析

一.Spinner的简介与创建 1.Spinner的简介 Spinner(下拉列表)是一个每次只能选择所有项中一项的控件,相当于Html中的下拉列表框。它的继承关系如下: java.lang.Object ↳ android.view.View ↳ android.view.ViewGroup ↳ android.widget.AdapterView<T extends android.widget.Adapter> ↳ android.widget.AbsSpinner ↳ android.widget.Spinner Spinner常用的XML属性: 属性名称 描述 android:prompt 该提示在下拉列表对话框显示时显示。(译者注:对话框的标题: 2.创建使用Spinner的步骤如下: ①需要在布局中定时Spinner组件,然后向Spinner添加需要选择的数据 ②设置事件监听器setOnItemSelectedListener( )并实现onItemSelected( ) 3.Spinner添加数据的两种方法: ①在Java代码中载入列表数据 具体的例子如下: MainActivity.java packagecom.android.spinner; importandroid.app.Activity; importandroid.os.Bundle; importandroid.view.View; importandroid.widget.AdapterView; importandroid.widget.ArrayAdapter; importandroid.widget.Spinner; importandroid.widget.TextView; publicclassMainActivityextendsActivity{ privatestaticfinalString[]province={"广东","广西","湖南","河南","福建"}; privateTextViewtext; privateSpinnerspinner; privateArrayAdapter<String>adapter; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); text=(TextView)findViewById(R.id.text); spinner=(Spinner)findViewById(R.id.spinner); //将Spinner里面的可选择内容通过ArrayAdapter连接起来 adapter=newArrayAdapter<String>(this,android.R.layout.simple_spinner_item,province); //设置Spinner的样式 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); //为对话框设置标题 //也可在XMl文件中通过“android:prompt”设置 spinner.setPrompt("你来自哪个省"); //为Spinner设置适配器 spinner.setAdapter(adapter); //添加Spinner事件监听 spinner.setOnItemSelectedListener(newSpinner.OnItemSelectedListener(){ @Override publicvoidonItemSelected(AdapterView<?>arg0,Viewarg1, intarg2,longarg3){ //TODOAuto-generatedmethodstub text.setText("你所在的城市是:"+province[arg2]); //设置显示当前选择的项 arg0.setVisibility(View.VISIBLE); } @Override publicvoidonNothingSelected(AdapterView<?>arg0){ //TODOAuto-generatedmethodstub } }); } } main.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:padding="10dip" android:layout_width="fill_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/text" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="10dip" android:text="@string/planet_prompt" /> <Spinner android:id="@+id/spinner" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout> strings.xml <?xmlversion="1.0"encoding="utf-8"?> <resources> <stringname="planet_prompt">你来自的省份是:</string> <stringname="app_name">测试Spinner</string> </resources> 效果图: ②在XML文件中定义列表的数据 具体的例子如下: MainActivity.java packagecom.android.spinner; importandroid.app.Activity; importandroid.os.Bundle; importandroid.view.View; importandroid.widget.AdapterView; importandroid.widget.AdapterView.OnItemSelectedListener; importandroid.widget.ArrayAdapter; importandroid.widget.Spinner; importandroid.widget.Toast; publicclassMainActivityextendsActivity{ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); Spinnerspinner=(Spinner)findViewById(R.id.spinner); ArrayAdapter<CharSequence>adapter=ArrayAdapter.createFromResource( this,R.array.province, android.R.layout.simple_spinner_item); //调用setDropDownViewResource方法,以XML的方式定义下拉菜单要显示的样式 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); //为spinner设置适配器 spinner.setAdapter(adapter); spinner.setOnItemSelectedListener(newMyOnItemSelectedListener()); } publicclassMyOnItemSelectedListenerimplementsOnItemSelectedListener{ publicvoidonItemSelected(AdapterView<?>parent,Viewview,intpos,longid){ Toast.makeText(parent.getContext(),"你来自的省份是:"+ parent.getItemAtPosition(pos).toString(),Toast.LENGTH_LONG).show(); } publicvoidonNothingSelected(AdapterView<?>parent){ //TODOAuto-generatedmethodstub } } } main.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:padding="10dip" android:layout_width="fill_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/text" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="10dip" android:text="@string/planet_prompt" /> <Spinner android:id="@+id/spinner" android:layout_width="fill_parent" android:layout_height="wrap_content" android:prompt="@string/planet_prompt" /> </LinearLayout> strings.xml <?xmlversion="1.0"encoding="utf-8"?> <resources> <stringname="planet_prompt">你来自的省份是</string> <stringname="app_name">测试Spinner</string> <string-arrayname="province"> <item>广东</item> <item>广西</item> <item>湖南</item> <item>河南</item> <item>福建</item> </string-array> </resources> 效果图: 二.AutoCompleteTextView简介 我们平常上网的时候经常会用到Google或百度,在输入框中输入类似”51CTO“,和51CTO相关的信息就会被列出来,供用户选择,非常方便。这种效果在Android中是用AutoCompleteTextView实现的。在AutoCompleteTextView中,主要是设置想显示资源的适配器(Adapter)。 AutoCompleteTextView有三个重要的方法clearListSelection():清除选中的列表项、dismissDropDown():如果存在关闭下拉菜单、getAdapter():获取适配器。 具体的例子如下: MainActivity.java packagecom.android.autocomplete; importandroid.app.Activity; importandroid.os.Bundle; importandroid.widget.ArrayAdapter; importandroid.widget.AutoCompleteTextView; publicclassMainActivityextendsActivity{ privateAutoCompleteTextViewatv; //创建字符串数组 privatestaticfinalString[]strs={"an","and","android","abc","abcdef"}; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); atv=(AutoCompleteTextView)findViewById(R.id.AutoCompleteTextView1); //创建适配器 ArrayAdapter<String>adapter=newArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line,strs); //为AutoCompleteTextView设置适配器 atv.setAdapter(adapter); } } 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="wrap_content" android:layout_height="wrap_content" android:text="自动完成文本框" /> <AutoCompleteTextView android:id="@+id/AutoCompleteTextView1" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout> 效果图: 本文转自 lingdududu 51CTO博客,原文链接:http://blog.51cto.com/liangruijun/652801

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

Android开发学习笔记:手机震动控制浅析

Android系统中Vibrator对象负责对手机震动的处理,具体的实现方法: 1.获取振动器Vibrator的实例: Vibratorvibrator=(Vibrator)getSystemService(VIBRATOR_SERVICE); getSystemService(VIBRATOR_SERVICE):获得一个震动的服务 2.调用vibrate方法来产生震动: 只向vibrate()传递一个参数,这个参数用来指定振动的毫秒数 //震动5秒 vibrator.vibrate(5000); 向vibrate()方法传递多个参数 //等待1秒,震动2秒,等待1秒,震动3秒 long[]pattern={1000,2000,1000,3000}; //-1表示不重复,如果不是-1,比如改成1,表示从前面这个long数组的下标为1的元素开始重复. vibrator.vibrate(pattern,-1); 3.取消震动 vibrator.cancel(); 4.在AndroidManifest.xml文件添加权限 <uses-permissionandroid:name="android.permission.VIBRATE"/> 下面的实例包含了产生震动的两个方法 VibratorDemoActivity.java packagecom.lingdududu.test; importandroid.app.Activity; importandroid.os.Bundle; importandroid.os.Vibrator; importandroid.view.MotionEvent; /* *@authorlingdududu *当程序开始运行结束时,手机等待1秒就开始震动2秒,再等待1秒,开始震动3秒 *当我们点击手机屏幕,触发onTouchEvent事件,手机就开始震动1秒 */ publicclassVibratorDemoActivityextendsActivity{ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); Vibratorvibrator=(Vibrator)getSystemService(VIBRATOR_SERVICE); long[]pattern={1000,2000,1000,3000};//OFF/ON/OFF/ON...... vibrator.vibrate(pattern,-1); } @Override publicbooleanonTouchEvent(MotionEventevent){ if(event.getAction()==MotionEvent.ACTION_MOVE){ Vibratorvibrator=(Vibrator)getSystemService(VIBRATOR_SERVICE); vibrator.vibrate(1000); } returnsuper.onTouchEvent(event); } } 注:记得在AndroidManifest.xml文件添加权限,还有程序要在真机上运行才能有震动的效果,模拟器上不支持震动的。 PS:我正在参加IT博客大赛,欢迎大家来投我一票的 http://blog.51cto.com/contest2011/3061169 本文转自 lingdududu 51CTO博客,原文链接:http://blog.51cto.com/liangruijun/724042

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

Android开发学习笔记:Notification和NotificationManager浅析

NotificationManager 获取NotificationManager String service = Context.NOTIFICATION_SERVICE; NotificationManager mNotificationManager =(NotificationManager)getSystemService(service); Notification //实例化Notification Notificationnotification=newNotification(); 3.设置Notification的属性 //设置显示图标,该图标会在状态栏显示 inticon=notification.icon=R.drawable.happy; //设置显示提示信息,该信息也在状态栏显示 StringtickerText="测试Notification"; //显示时间 longwhen=System.currentTimeMillis();notification.icon=icon; notification.tickerText=tickerText; notification.when=when; //也可以这样设置 Notificationnotification_2=newNotification(icon,tickerText,when) 调用setLatestEventInfo()方法在视图中设置图标和时间。 //实例化Intent Intentintent=newIntent(MainActivity.this,MainActivity.class); //获得PendingIntent PendingIntentpIntent=PendingIntent.getActivity(MainActivity.this,0,intent,0); //设置事件信息 notification.setLatestEventInfo(MainActivity.this,"Title","Content",pIntent); 4.发出通知 //Notification标示ID privatestaticfinalintID=1; //发出通知 mNotificationManager.notify(ID,n); 下面是具体的例子,在这个例子里定义了一个MainActivity发出广播通知,定义一个MyReceiver类继承Broadcasts接受通知,当接收完通知之后,启动一个SecondActivity,在SecondActivity类中通过Notification和NotificationManager来可视化显示广播通知。具体的步骤如下: MainActivity.java packagecom.android.notification; importandroid.app.Activity; importandroid.content.Intent; importandroid.os.Bundle; importandroid.view.View; importandroid.view.View.OnClickListener; importandroid.widget.Button; publicclassMainActivityextendsActivity{ //声明Button privateButtonbtn; //定义BroadcastReceiveraction privatestaticfinalStringMY_ACTION="com.android.notification.MY_ACTION"; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); //设置当前布局视图 setContentView(R.layout.main); //实例化Button btn=(Button)findViewById(R.id.Button1); //添加事件监听器 btn.setOnClickListener(listener); } //创建事件监听器 privateOnClickListenerlistener=newOnClickListener(){ @Override publicvoidonClick(Viewv){ //实例化Intent Intentintent=newIntent(); //设置Intentaction属性 intent.setAction(MY_ACTION); //发起广播 sendBroadcast(intent); } }; } MyReceiver.java packagecom.android.notification; importandroid.content.BroadcastReceiver; importandroid.content.Context; importandroid.content.Intent; publicclassMyReceiverextendsBroadcastReceiver{ @Override publicvoidonReceive(Contextcontext,Intentintent){ //实例化Intent Intenti=newIntent(); //在新的任务中启动Activity i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //设置Intent启动的组件名称 i.setClass(context,SecondActivity.class); //启动Activity显示通知 context.startActivity(i); } } SecondActivity.java packagecom.android.notification; importandroid.app.Activity; importandroid.app.Notification; importandroid.app.NotificationManager; importandroid.app.PendingIntent; importandroid.content.Intent; importandroid.os.Bundle; importandroid.view.View; importandroid.view.View.OnClickListener; importandroid.widget.Button; publicclassSecondActivityextendsActivity{ //声明按钮 privateButtoncancelBtn; //声明Notification privateNotificationnotification; //声明NotificationManager privateNotificationManagermNotification; //Notification标示ID privatestaticfinalintID=1; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.second); //实例化按钮 cancelBtn=(Button)findViewById(R.id.cancelButton2); //获得NotificationManager实例 Stringservice=NOTIFICATION_SERVICE; mNotification=(NotificationManager)getSystemService(service); //实例化Notification notification=newNotification(); //设置显示图标,该图标会在状态栏显示 inticon=notification.icon=android.R.drawable.stat_notify_chat; //设置显示提示信息,该信息也会在状态栏显示 StringtickerText="TestNotification"; //显示时间 longwhen=System.currentTimeMillis(); notification.icon=icon; notification.tickerText=tickerText; notification.when=when; //实例化Intent Intentintent=newIntent(this,MainActivity.class); //获得PendingIntent PendingIntentpi=PendingIntent.getActivity(this,0,intent,0); //设置事件信息 notification.setLatestEventInfo(this,"消息","HelloAndroid",pi); //发出通知 mNotification.notify(ID,notification); //为按钮添加监听器 cancelBtn.setOnClickListener(cancelListener); } //取消通知监听器 privateOnClickListenercancelListener=newOnClickListener(){ @Override publicvoidonClick(Viewv){ //取消通知 mNotification.cancel(ID); } }; } 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" > <Button android:text="发出广播通知" android:id="@+id/Button1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> second.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:text="显示通知界面" android:id="@+id/TextView1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:text="取消通知" android:id="@+id/cancelButton2" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> 在AndroidManifest.xml文件中16~21加入对receiver,SecondActivity的声明 <?xmlversion="1.0"encoding="utf-8"?> <manifestxmlns:android="http://schemas.android.com/apk/res/android" package="com.android.notification" 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> <receiverandroid:name="MyReceiver"> <intent-filter> <actionandroid:name="com.android.notification.MY_ACTION"/> </intent-filter> </receiver> <activityandroid:name="SecondActivity"/> </application> </manifest> 效果图: Notification丰富的提示方式: 声音提醒 ·使用默认声音 notification.defaults |= Notification.DEFAULT_SOUND; ·使用自定义声音 notification.sound = Uri.parse("file:///sdcard/notification/ringer.mp3"); ·注:如果定义了默认声音,那么自定义声音将被覆盖 振动提醒 ·使用默认振动 notification.defaults |= Notification.DEFAULT_VIBRATE; ·使用自定义振动 long[] vibrate = {0,100,200,300};notification.vibrate = vibrate; ·注:如果定义了默认振动,那么自定义振动将被覆盖 灯光闪烁提醒 ·使用默认闪烁 notification.defaults |= Notification.DEFAULT_LIGHTS; ·使用自定义闪烁 notification.ledARGB = 0xff00ff00;// LED灯的颜色,绿灯notification.ledOnMS = 300;// LED灯显示的毫秒数,300毫秒notification.ledOffMS = 1000;// LED灯关闭的毫秒数,1000毫秒notification.flags |= Notification.FLAG_SHOW_LIGHTS; // 必须加上这个标志 更多特性 可以通过 Notification 的相关字段或标志(flags)为提醒设置更多的特性。 ·FLAG_AUTO_CANCEL标志:当提醒被用户点击之后会自动被取消(cancel); ·FLAG_INSISTENT标志:在用户响应之前会一直重复提醒音; ·FLAG_ONGOING_EVENT标志:Add this to theflagsfield to group the notification under the "Ongoing" title in the Notifications window. ·FLAG_NO_CLEAR标志:当在提醒栏中点击“清除提醒”按钮时,该提醒将不会被清除; ·number字段:This value indicates the current number of events represented by the notification. The appropriate number is overlaid on top of the status bar icon. If you intend to use this field, then you must start with "1" when the Notification is first created. (If you change the value from zero to anything greater during an update, the number is not shown.) ·iconLevel字段:This value indicates the current level of aLevelListDrawablethat isused for the notification icon. You can animate the icon in the status bar by changingthis value to correlate with the drawable's defined in a LevelListDrawable. ·contentView字段:To define your own layout for the expanded message, instantiate a RemoteViews object and pass it to thecontentViewfield of your Notification. Pass the PendingIntent to thecontentIntentfield. 本文转自 lingdududu 51CTO博客,原文链接: http://blog.51cto.com/liangruijun/657502

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

Android开发学习笔记:TextView的属性详解

android:autoLink :设置是否当文本为URL链接/email/电话号码/map时,文本显示为可点击的链接。可选值(none/web /email/phone/map/all) android:autoText :如果设置,将自动执行输入值的拼写纠正。此处无效果,在显示输入法并输入的时候起作用。 android:bufferType : 指定getText()方式取得的文本类别。选项editable 类似于StringBuilder :可追加字符,也就是说getText后可调用append方法设置文本内容。spannable :则可在给定的字符区域使用样式,参见这里1、这里2。 android:capitalize :设置英文字母大写类型。此处无效果,需要弹出输入法才能看得到,参见EditView此属性说明。 android:cursorVisible:设定光标为显示/隐藏,默认显示。 android:digits:设置允许输入哪些字符。如“1234567890.+-*/% ()” android:drawableBottom:在text的下方输出一个drawable,如图片。如果指定一个颜色的话会把text的背景设为该颜色,并且同时和background使用时覆盖后者。 android:drawableLeft:在text的左边输出一个drawable,如图片。 android:drawablePadding:设置text与drawable(图片)的间隔,与drawableLeft、 drawableRight、drawableTop、drawableBottom一起使用,可设置为负数,单独使用没有效果。 android:drawableRight:在text的右边输出一个drawable。 android:drawableTop:在text的正上方输出一个drawable。 android:editable:设置是否可编辑。 android:editorExtras:设置文本的额外的输入数据。 android:ellipsize:设置当文字过长时,该控件该如何显示。有如下值设置:”start”—?省略号显示在开头;”end” ——省略号显示在结尾;”middle”—-省略号显示在中间;”marquee” ——以跑马灯的方式显示(动画横向移动) android:freezesText:设置保存文本的内容以及光标的位置。 android:gravity:设置文本位置,如设置成“center”,文本将居中显示。 android:hintText:为空时显示的文字提示信息,可通过textColorHint设置提示信息的颜色。此属性在 EditView中使用,但是这里也可以用。 android:imeOptions:附加功能,设置右下角IME动作与编辑框相关的动作,如actionDone右下角将显示一个“完成”,而不设置默认是一个回车符号。这个在EditView中再详细说明,此处无用。 android:imeActionId:设置IME动作ID。 android:imeActionLabel:设置IME动作标签。 android:includeFontPadding:设置文本是否包含顶部和底部额外空白,默认为true。 android:inputMethod:为文本指定输入法,需要完全限定名(完整的包名)。例如:com.google.android.inputmethod.pinyin,但是这里报错找不到。 android:inputType:设置文本的类型,用于帮助输入法显示合适的键盘类型。在EditView中再详细说明,这里无效果。 android:linksClickable:设置链接是否点击连接,即使设置了autoLink。 android:marqueeRepeatLimit:在ellipsize指定marquee的情况下,设置重复滚动的次数,当设置为 marquee_forever时表示无限次。 android:ems:设置TextView的宽度为N个字符的宽度。这里测试为一个汉字字符宽度 android:maxEms:设置TextView的宽度为最长为N个字符的宽度。与ems同时使用时覆盖ems选项。 android:minEms:设置TextView的宽度为最短为N个字符的宽度。与ems同时使用时覆盖ems选项。 android:maxLength:限制显示的文本长度,超出部分不显示。 android:lines:设置文本的行数,设置两行就显示两行,即使第二行没有数据。 android:maxLines:设置文本的最大显示行数,与width或者layout_width结合使用,超出部分自动换行,超出行数将不显示。 android:minLines:设置文本的最小行数,与lines类似。 android:lineSpacingExtra:设置行间距。 android:lineSpacingMultiplier:设置行间距的倍数。如”1.2” android:numeric:如果被设置,该TextView有一个数字输入法。此处无用,设置后唯一效果是TextView有点击效果,此属性在EdtiView将详细说明。 android:password:以小点”.”显示文本 android:phoneNumber:设置为电话号码的输入方式。 android:privateImeOptions:设置输入法选项,此处无用,在EditText将进一步讨论。 android:scrollHorizontally:设置文本超出TextView的宽度的情况下,是否出现横拉条。 android:selectAllOnFocus:如果文本是可选择的,让他获取焦点而不是将光标移动为文本的开始位置或者末尾位置。 TextView中设置后无效果。 android:shadowColor:指定文本阴影的颜色,需要与shadowRadius一起使用。 android:shadowDx:设置阴影横向坐标开始位置。 android:shadowDy:设置阴影纵向坐标开始位置。 android:shadowRadius:设置阴影的半径。设置为0.1就变成字体的颜色了,一般设置为3.0的效果比较好。 android:singleLine:设置单行显示。如果和layout_width一起使用,当文本不能全部显示时,后面用“…”来表示。如android:text="test_ singleLine " android:singleLine="true" android:layout_width="20dp"将只显示“t…”。如果不设置singleLine或者设置为false,文本将自动换行 android:text:设置显示文本. android:textAppearance:设置文字外观。如 “?android:attr/textAppearanceLargeInverse”这里引用的是系统自带的一个外观,?表示系统是否有这种外观,否则使用默认的外观。可设置的值如下:textAppearanceButton/textAppearanceInverse/textAppearanceLarge/textAppearanceLargeInverse/textAppearanceMedium/textAppearanceMediumInverse/textAppearanceSmall/textAppearanceSmallInverse android:textColor:设置文本颜色 android:textColorHighlight:被选中文字的底色,默认为蓝色 android:textColorHint:设置提示信息文字的颜色,默认为灰色。与hint一起使用。 android:textColorLink:文字链接的颜色. android:textScaleX:设置文字之间间隔,默认为1.0f。 android:textSize:设置文字大小,推荐度量单位”sp”,如”15sp” android:textStyle:设置字形[bold(粗体) 0, italic(斜体) 1, bolditalic(又粗又斜) 2] 可以设置一个或多个,用“|”隔开 android:typeface:设置文本字体,必须是以下常量值之一:normal 0, sans 1, serif 2, monospace(等宽字体) 3] android:height:设置文本区域的高度,支持度量单位:px(像素)/dp/sp/in/mm(毫米) android:maxHeight:设置文本区域的最大高度 android:minHeight:设置文本区域的最小高度 android:width:设置文本区域的宽度,支持度量单位:px(像素)/dp/sp/in/mm(毫米),与layout_width 的区别看这里。 android:maxWidth:设置文本区域的最大宽度 android:minWidth:设置文本区域的最小宽度 附件:Android中的长度单位详解 Android中的长度单位详解(dp、sp、px、in、pt、mm)有很多人不太理解dp、sp 和px 的区别:现在这里介绍一下dp 和sp。dp 也就是dip。这个和sp 基本类似。如果设置表示长度、高度等属性时可以使用dp 或sp。但如果设置字体,需要使用sp。dp 是与密度无关,sp 除了与密度无关外,还与scale 无关。如果屏幕密度为160,这时dp 和sp 和px 是一样的。1dp=1sp=1px,但如果使用px 作单位,如果屏幕大小不变(假设还是3.2 寸),而屏幕密度变成了320。那么原来TextView 的宽度设成160px,在密度为320 的3.2 寸屏幕里看要比在密度为160 的3.2 寸屏幕上看短了一半。但如果设置成160dp 或160sp 的话。系统会自动将width 属性值设置成320px 的。也就是160 * 320 / 160。其中320 / 160 可称为密度比例因子。也就是说,如果使用dp 和sp,系统会根据屏幕密度的变化自动进行转换。 其他单位的含义 px:表示屏幕实际的象素。例如,320*480 的屏幕在横向有320个象素,在纵向有480 个象素。 in:表示英寸,是屏幕的物理尺寸。每英寸等于2.54 厘米。例如,形容手机屏幕大小,经常说,3.2(英)寸、3.5(英)寸、4(英)寸就是指这个单位。这些尺寸是屏幕的对角线长度。如果手机的屏幕是3.2 英寸,表示手机的屏幕(可视区域)对角线长度是3.2*2.54 = 8.128 厘米。读者可以去量一量自己的手机屏幕,看和实际的尺寸是否一致。 mm:表示毫米,是屏幕的物理尺寸。 pt:表示一个点,是屏幕的物理尺寸。大小为1 英寸的1/72。 本文转自 lingdududu 51CTO博客,原文链接:http://blog.51cto.com/liangruijun/627123

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

Android UI学习 - GridView和ImageView的使用

GridView: A view that shows items in two-dimensional scrolling grid. The items in the grid come from the ListAdapterassociated with this view. 简单说GridView就是我们资源管理器平常见到的一个个文件的icon显示方式。 上面提及到了GridView的Item是来自ListAdapter的所以一般在Activity的onCreate使用GridView的代码 @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.grid_2); GridViewg=(GridView)findViewById(R.id.myGrid); g.setAdapter(newImageAdapter(this)); } 而ImageAdapter一般是extends BaseAdapter。BaseAdapter是implements ListAdapter SpinnerAdapter但很多时候自定义的Adapter都是override ListAdapter的父类Adapter接口里面的方法 int getCount() 获取当前Adapter的Items数目 Object getItem(int position) 获取相应position的Item long getItemId(int position) 获取相应position的Item在List中的row id View getView(int position, View convertView, ViewGroup parent) 获取在指定position所要显示的data的View 这些方法函数和swing的差不多都是基于MVC。大概原理过程是这样的程序需要显示GridView那么要把data一个一个地显示出来是通过一个for循环首先call Adapter.getCount()得到有多少个data然后position++地getItemgetView得到要显示的view,这样子逐一地显示出来 下面是官方sample里面的Photo Grid的例子本人省略了某些代码 publicclassImageAdapterextendsBaseAdapter{ publicImageAdapter(Contextc){ mContext=c; } publicintgetCount(){ returnmThumbIds.length; } publicObjectgetItem(intposition){ returnposition; } publiclonggetItemId(intposition){ returnposition; } publicViewgetView(intposition,ViewconvertView,ViewGroupparent){ ImageViewimageView; if(convertView==null){ imageView=newImageView(mContext); imageView.setLayoutParams(newGridView.LayoutParams(45,45));//设置ImageView宽高 imageView.setAdjustViewBounds(false); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); imageView.setPadding(8,8,8,8); }else{ imageView=(ImageView)convertView; } imageView.setImageResource(mThumbIds[position]); returnimageView; } privateContextmContext; privateInteger[]mThumbIds={ R.drawable.sample_thumb_0,R.drawable.sample_thumb_1, R.drawable.sample_thumb_2,R.drawable.sample_thumb_3, R.drawable.sample_thumb_4,R.drawable.sample_thumb_5, R.drawable.sample_thumb_6,R.drawable.sample_thumb_7 }; } 留意getView里面的代码要判断convertView是否为null以便重用减少对象的创建减少内存占用。 XML布局文件内容原来就只是指明GridView <?xmlversion="1.0"encoding="utf-8"?> <GridViewxmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/myGrid" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="10dp" android:verticalSpacing="10dp" android:horizontalSpacing="10dp" android:numColumns="auto_fit" android:columnWidth="60dp" android:stretchMode="columnWidth" android:gravity="center" /> 可以看到getView和ImageView是重点影响图片的显示效果。而且发现列数是不确定的取决于每个ImageView的宽度和屏幕的宽度。接下来看看ImageView。 ImageViewDisplays an arbitrary image, such as an icon. The ImageView class can load images from various sources (such as resources or content providers), takes care of computing its measurement from the image so that it can be used in any layout manager, and provides various display options such as scaling and tinting。 ImageView就是用来显示Imageicon的。 这里我们重点理解ImageView的属性android:scaleType即ImageView.setScaleType(ImageView.ScaleType)。android:scaleType是控制图片如何resized/moved来匹对ImageView的size。ImageView.ScaleType /android:scaleType值的意义区别 CENTER /center按图片的原来size居中显示当图片长/宽超过View的长/宽则截取图片的居中部分显示 CENTER_CROP /centerCrop按比例扩大图片的size居中显示使得图片长(宽)等于或大于View的长(宽) CENTER_INSIDE /centerInside将图片的内容完整居中显示通过按比例缩小或原来的size使得图片长/宽等于或小于View的长/宽 FIT_CENTER / fitCenter把图片按比例扩大/缩小到View的宽度居中显示 FIT_END /fitEnd 把图片按比例扩大/缩小到View的宽度显示在View的下部分位置 FIT_START /fitStart 把图片按比例扩大/缩小到View的宽度显示在View的上部分位置 FIT_XY /fitXY把图片 不按比例扩大/缩小到View的大小显示 MATRIX / matrix用矩阵来绘制 一开始我不明白MATRIX矩阵网上搜索后发现原来MATRIX矩阵可以动态缩小放大图片来显示这里不展开深入的了解只是贴出相关语句缩小图片 //获得Bitmap的高和宽 intbmpWidth=bmp.getWidth(); intbmpHeight=bmp.getHeight(); //设置缩小比例 doublescale=0.8; //计算出这次要缩小的比例 scaleWidth=(float)(scaleWidth*scale); scaleHeight=(float)(scaleHeight*scale); //产生resize后的Bitmap对象 Matrixmatrix=newMatrix(); matrix.postScale(scaleWidth,scaleHeight); BitmapresizeBmp=Bitmap.createBitmap(bmp,0,0,bmpWidth,bmpHeight,matrix,true); 应用ImageView的例子很多看看上次FrameLayout里面的 <ImageView android:id="@+id/image" android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="center" android:src="@drawable/candle" /> ** 要注意一点我发现Drawable文件夹里面的图片命名是不能大写的。 本文转自 Icansoft 51CTO博客原文链接http://blog.51cto.com/android/316255

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

Android学习笔记(三)基础知识(2)

交互对话框 使用Android SDK中,具有交互功能的对话框是AlertDialog窗口。 package com.example.test8; import android.os.Bundle; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.support.v4.app.NavUtils; public class MainActivity extends Activity { private Button bt; int n=0; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bt=(Button)findViewById(R.id.button1); bt.setOnClickListener(new Button.OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub n++; String str=Integer.toString(n); bt.setText("点击次数:"+n); new AlertDialog.Builder(MainActivity.this) .setTitle("提示") .setMessage("对话框") .setPositiveButton("确定",new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub } } ) .show(); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } } 拖放相片特效 在Android中,拖动图片的特效可以通过Android.content.Context,Android,widget.BaseAdapter和Android.widget.imageView等来实现。 在下面的列子中,context可以像画布一样,随时可以被处理覆盖。Context是作为Android.content子类。通过widget.BaseAdapter作为容器来存放Gallery所需要的图片。 这里是通过使用Gallery实现的相片拖拽功能,具体代码如下: package com.example.test9; import android.os.Bundle; import android.app.Activity; import android.content.Context; import android.graphics.Color; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.Gallery; import android.widget.ImageView; import android.widget.TextView; import android.support.v4.app.NavUtils; public class MainActivity extends Activity { private TextView textview; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textview = (TextView)findViewById(R.id.textView1); textview.setText("特效演示"); textview.setTextColor(Color.BLUE); Gallery gallery=(Gallery)findViewById(R.id.gallery1); gallery.setAdapter(new ImageAdapter(this)); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } public class ImageAdapter extends BaseAdapter{ private Context myContext; private int[] myImageID={android.R.drawable.btn_minus, android.R.drawable.btn_radio, android.R.drawable.ic_lock_idle_low_battery, android.R.drawable.ic_menu_camera }; public ImageAdapter(Context c){ this.myContext=c; } public int getCount() { // TODO Auto-generated method stub return this.myImageID.length; } public Object getItem(int position) { // TODO Auto-generated method stub return position; } public long getItemId(int position) { // TODO Auto-generated method stub return position; } public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub ImageView i=new ImageView(this.myContext); i.setImageResource(this.myImageID[position]); i.setScaleType(ImageView.ScaleType.FIT_XY); i.setLayoutParams(new Gallery.LayoutParams(120,120)); return i; } } } 设置about关于信息 创建一个onCreateOptionsMenu(Menu menu)类函数,用于添加Menu菜单项,再利用onOptionItemSelected选择菜单项 package com.example.test10; import android.os.Bundle; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.view.Menu; import android.view.MenuItem; import android.support.v4.app.NavUtils; public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0,0,0,"关于"); menu.add(0,1,1,"退出"); return super.onCreateOptionsMenu(menu); } public boolean onOptionsItemSelected(MenuItem item){ super.onOptionsItemSelected(item); switch(item.getItemId()){ case 0: openOptionsDialog(); break; case 1: finish(); } return true; } private void openOptionsDialog(){ new AlertDialog.Builder(this) .setTitle("关于") .setMessage("***") .setPositiveButton("OK",new OnClickListener() { public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub } }) .show(); } } 程序加载中状态框 程序加载中的提示,此功能是通过Progress Dialog类来运行,此类在Android.app.ProgressDialog类里。但是,我们需要注意使用dismiss()函数来关闭取得焦点的对话框,否则程序将陷入死循环,也不能在线程里更改CONTEXT或parent view的任何状态。 package com.example.test11; import android.os.Bundle; import android.app.Activity; import android.app.ProgressDialog; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.support.v4.app.NavUtils; public class MainActivity extends Activity { private TextView text; private Button bt; public ProgressDialog myDialog=null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); text=(TextView)findViewById(R.id.textView1); bt=(Button)findViewById(R.id.button1); bt.setOnClickListener(myShowProgressBar); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } Button.OnClickListener myShowProgressBar=new Button.OnClickListener() { public void onClick(View v) { // TODO Auto-generated method stub final CharSequence strDialogTile="请等待"; final CharSequence strDialogBody="程序正在运行"; myDialog=ProgressDialog.show(MainActivity.this,strDialogTile,strDialogBody,true); text.setText(strDialogBody); new Thread(){ public void run(){ try{ text.setText("start"); sleep(3000); text.setText("end"); }catch (Exception e) { // TODO: handle exception e.printStackTrace(); } finally{ myDialog.dismiss(); } } }.start(); } }; } 本文转自cococo点点博客园博客,原文链接:http://www.cnblogs.com/coder2012/archive/2013/05/16/3076677.html,如需转载请自行联系原作者

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

Storm概念学习系列之storm简介

storm简介 Storm 是 Twitter 开源的、分布式的、容错的实时计算系统,遵循 Eclipse Public License1.0。 Storm 通过简单的 API 使开发者可以可靠地处理无界持续的流数据,进行实时计算。 Twitter Storm 是使用 Clojure(发音同 closure)语言实现的。 Clojure 是 Lisp 语言的一种现代方言。类似于 Lisp, Clojure 支持一种功能性编程风格,但 Clojure 还引入了一些特性来简化多线程编程(一种对创建 Storm 很有用的特性)。 Clojure 是一种基于虚拟机(VM)的语言,在 Java 虚拟机上运行。尽管 Storm 是使用 Clojure 语言开发的,但是仍然可以在 Storm 中使用几乎任何语言编写应用程序,所需的只是一个连接到 Storm 架构的适配器。已存在针对Scala、 JRuby、 Perl 和 PHP 的适配器,但是还有支持流式传输到 Storm 拓扑结构中的结构化查询语言适配器——可以通过标准输入、标准输出以 JSON 格式协议与 Storm 通信。 Storm 可以方便地在一个计算机集群中编写与扩展复杂的实时计算,Storm 之于实时处理,就好比 Hadoop 之于批处理。Storm 保证每个消息都会得到处理,而且它很快——在一个小集群中,每秒可以处理数以百万计的消息。 Storm 的处理速度非常惊人:经测试,每个节点每秒可以处理 100 万个数据元组 Clojure的维基百科:https://zh.wikipedia.org/wiki/Clojure Clojure的百度百科:http://baike.baidu.com/link?url=2ODx328uV6zJESQOVT3DFObTCkj6JJPzH-Iv0uJ_uYtZ3nRDGHU0jg6u-ItutvFRhduMFU2LHt9WM0AnP4oHua 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/5989244.html,如需转载请自行联系原作者

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

Storm概念学习系列之Task任务

每一个Spout/Bolt的线程称为一个Task。 Task任务 Task是运行Spout或Bolt的单元,每一个Spout/Bolt的线程称为一个Task。在Storm 0.8及之后的版本中,Task不再与物理线程对应,同一个Spout/Bolt的Task可能会共享一个物理线程,该线程称为Executor。 实际的数据处理由Task完成,在Topology的生命周期中,每个组件的Task数量不会变化,而Executor的数量却不一定。在一般情况下,线程数小于等于Task数量。默认Task的数量等于Executor线程数量,即一个Executor线程只运行一个Task。Executor线程在执行期间会调用该Task的nextTuple或execute方法。 每个Spout或Bolt都是通过集群中的许多任务来执行的。每个任务相当于一个执行线程,可以通过TopologyBuilder的setSpout方法和setBolt方法为每个Spout或Bolt设置并行数,即任务数。 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/5989729.html,如需转载请自行联系原作者

资源下载

更多资源
优质分享App

优质分享App

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

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

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

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册