首页 文章 精选 留言 我的

精选列表

搜索[笔记工具],共10000篇文章
优秀的个人博客,低调大师

Docker学习笔记-- 如何使用Dockerfile构建镜像

Dockerfile是一种被Docker程序解释的脚本,Dockerfile由一条一条的指令组成,每条指令对应Linux下面的一条命令。Docker程序将这些Dockerfile指令翻译真正的Linux命令。Dockerfile有自己书写格式和支持的命令,Docker程序解决这些命令间的依赖关系,类似于Makefile。Docker程序将读取Dockerfile,根据指令生成定制的image。相比image这种黑盒子,Dockerfile这种显而易见的脚本更容易被使用者接受,它明确的表明image是怎么产生的。有了Dockerfile,当我们需要定制自己额外的需求时,只需在Dockerfile上添加或者修改指令,重新生成image即可,省去了敲命令的麻烦。 1. Dockerfile的书写规则及指令使用方法 Dockerfile的指令是忽略大小写的,建议使用大写,使用 # 作为注释,每一行只支持一条指令,每条指令可以携带多个参数。 Dockerfile的指令根据作用可以分为两种,构建指令和设置指令。构建指令用于构建image,其指定的操作不会在运行image的容器上执行;设置指令用于设置image的属性,其指定的操作将在运行image的容器中执行。 (1)FROM(指定基础image) 构建指令,必须指定且需要在Dockerfile其他指令的前面。后续的指令都依赖于该指令指定的image。FROM指令指定的基础image可以是官方远程仓库中的,也可以位于本地仓库。该指令有两种格式: FROM<image> 指定基础image为该image的最后修改的版本。或者 FROM<image>:<tag> 指定基础image为该image的一个tag版本 (2)MAINTAINER(用来指定镜像创建者信息) 构建指令,用于将image的制作者相关的信息写入到image中。当我们对该image执行docker inspect命令时,输出中有相应的字段记录该信息。格式: MAINTAINER<name> (3)RUN(安装软件用) 构建指令,RUN可以运行任何被基础image支持的命令。如基础image选择了ubuntu,那么软件管理部分只能使用ubuntu的命令。该指令有两种格式: RUN<command>(thecommandisruninashell-`/bin/sh-c`) RUN["executable","param1","param2"...](execform) (4)CMD(设置container启动时执行的操作) 设置指令,用于container启动时指定的操作。该操作可以是执行自定义脚本,也可以是执行系统命令。该指令只能在文件中存在一次,如果有多个,则只执行最后一条。该指令有三种格式: CMD["executable","param1","param2"](likeanexec,thisisthepreferredform) CMDcommandparam1param2(asashell) 当Dockerfile指定了ENTRYPOINT,那么使用下面的格式: CMD["param1","param2"](asdefaultparameterstoENTRYPOINT) ENTRYPOINT指定的是一个可执行的脚本或者程序的路径,该指定的脚本或者程序将会以param1和param2作为参数执行。所以如果CMD指令使用上面的形式,那么Dockerfile中必须要有配套的ENTRYPOINT。 (5)ENTRYPOINT(设置container启动时执行的操作) 设置指令,指定容器启动时执行的命令,可以多次设置,但是只有最后一个有效。两种格式: ENTRYPOINT["executable","param1","param2"](likeanexec,thepreferredform) ENTRYPOINTcommandparam1param2(asashell) 该指令的使用分为两种情况,一种是独自使用,另一种和CMD指令配合使用。当独自使用时,如果你还使用了CMD命令且CMD是一个完整的可执行的命令,那么CMD指令和ENTRYPOINT会互相覆盖只有最后一个CMD或者ENTRYPOINT有效。 #CMD指令将不会被执行,只有ENTRYPOINT指令被执行 CMDecho“Hello,World!” ENTRYPOINTls-l 另一种用法和CMD指令配合使用来指定ENTRYPOINT的默认参数,这时CMD指令不是一个完整的可执行命令,仅仅是参数部分;ENTRYPOINT指令只能使用JSON方式指定执行命令,而不能指定参数。 FROMubuntu CMD["-l"] ENTRYPOINT["/usr/bin/ls"] (6)USER(设置container容器的用户) 设置指令,设置启动容器的用户,默认是root用户。 #指定memcached的运行用户 ENTRYPOINT["memcached"] USERdaemon 或 ENTRYPOINT["memcached","-u","daemon"] (7)EXPOSE(指定容器需要映射到宿主机器的端口) 设置指令,该指令会将容器中的端口映射成宿主机器中的某个端口。当你需要访问容器的时候,可以不是用容器的IP地址而是使用宿主机器的IP地址和映射后的端口。要完成整个操作需要两个步骤,首先在Dockerfile使用EXPOSE设置需要映射的容器端口,然后在运行容器的时候指定-p选项加上EXPOSE设置的端口,这样EXPOSE设置的端口号会被随机映射成宿主机器中的一个端口号。也可以指定需要映射到宿主机器的那个端口,这时要确保宿主机器上的端口号没有被使用。EXPOSE指令可以一次设置多个端口号,相应的运行容器的时候,可以配套的多次使用-p选项。格式: EXPOSE<port>[<port>...] #映射一个端口 EXPOSEport1 #相应的运行容器使用的命令 dockerrun-pport1image #映射多个端口 EXPOSEport1port2port3 #相应的运行容器使用的命令 dockerrun-pport1-pport2-pport3image #还可以指定需要映射到宿主机器上的某个端口号 dockerrun-phost_port1:port1-phost_port2:port2-phost_port3:port3image 端口映射是docker比较重要的一个功能,原因在于我们每次运行容器的时候容器的IP地址不能指定而是在桥接网卡的地址范围内随机生成的。宿主机器的IP地址是固定的,我们可以将容器的端口的映射到宿主机器上的一个端口,免去每次访问容器中的某个服务时都要查看容器的IP的地址。对于一个运行的容器,可以使用docker port加上容器中需要映射的端口和容器的ID来查看该端口号在宿主机器上的映射端口。 (8)ENV(用于设置环境变量) 构建指令,在image中设置一个环境变量。格式: ENV<key><value> 设置了后,后续的RUN命令都可以使用,container启动后,可以通过docker inspect查看这个环境变量,也可以通过在docker run --env key=value时设置或修改环境变量。假如你安装了JAVA程序,需要设置JAVA_HOME,那么可以在Dockerfile中这样写:ENV JAVA_HOME /path/to/java/dirent (9)ADD(从src复制文件到container的dest路径) 构建指令,所有拷贝到container中的文件和文件夹权限为0755,uid和gid为0;如果是一个目录,那么会将该目录下的所有文件添加到container中,不包括目录;如果文件是可识别的压缩格式,则docker会帮忙解压缩(注意压缩格式);如果<src>是文件且<dest>中不使用斜杠结束,则会将<dest>视为文件,<src>的内容会写入<dest>;如果<src>是文件且<dest>中使用斜杠结束,则会<src>文件拷贝到<dest>目录下。格式: ADD<src><dest> <src> 是相对被构建的源目录的相对路径,可以是文件或目录的路径,也可以是一个远程的文件url;<dest> 是container中的绝对路径 (10)VOLUME(指定挂载点)) 设置指令,使容器中的一个目录具有持久化存储数据的功能,该目录可以被容器本身使用,也可以共享给其他容器使用。我们知道容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失。当容器中的应用有持久化数据的需求时可以在Dockerfile中使用该指令。格式: VOLUME["<mountpoint>"] FROMbase VOLUME["/tmp/data"] 运行通过该Dockerfile生成image的容器,/tmp/data目录中的数据在容器关闭后,里面的数据还存在。例如另一个容器也有持久化数据的需求,且想使用上面容器共享的/tmp/data目录,那么可以运行下面的命令启动一个容器: dockerrun-t-i-rm-volumes-fromcontainer1image2bash container1为第一个容器的ID,image2为第二个容器运行image的名字。 (11)WORKDIR(切换目录) 设置指令,可以多次切换(相当于cd命令),对RUN,CMD,ENTRYPOINT生效。格式: WORKDIR/path/to/workdir #在/p1/p2下执行vima.txt WORKDIR/p1WORKDIRp2RUNvima.txt (12)ONBUILD(在子镜像中执行) ONBUILD<Dockerfile关键字> ONBUILD 指定的命令在构建镜像时并不执行,而是在它的子镜像中执行。详细资料可参考https://www.dockboard.org/docker-quicktip-3-onbuild 2. 创建Dockerfile,构建jdk+tomcat环境 Dockerfile文件 #Pullbaseimage FROMubuntu:13.10 MAINTAINERzingwang"zing.jian.wang@gmail.com" #updatesource RUNecho"debhttp://archive.ubuntu.com/ubuntuprecisemainuniverse">/etc/apt/sources.list RUNapt-getupdate #Installcurl RUNapt-get-yinstallcurl #InstallJDK7 RUNcd/tmp&&curl-L'http://download.oracle.com/otn-pub/java/jdk/7u65-b17/jdk-7u65-linux-x64.tar.gz'-H'Cookie:oraclelicense=accept-securebackup-cookie;gpw_e24=Dockerfile'|tar-xz RUNmkdir-p/usr/lib/jvm RUNmv/tmp/jdk1.7.0_65//usr/lib/jvm/java-7-oracle/ #SetOracleJDK7asdefaultJava RUNupdate-alternatives--install/usr/bin/javajava/usr/lib/jvm/java-7-oracle/bin/java300 RUNupdate-alternatives--install/usr/bin/javacjavac/usr/lib/jvm/java-7-oracle/bin/javac300 ENVJAVA_HOME/usr/lib/jvm/java-7-oracle/ #Installtomcat7 RUNcd/tmp&&curl-L'http://archive.apache.org/dist/tomcat/tomcat-7/v7.0.8/bin/apache-tomcat-7.0.8.tar.gz'|tar-xz RUNmv/tmp/apache-tomcat-7.0.8//opt/tomcat7/ ENVCATALINA_HOME/opt/tomcat7 ENVPATH$PATH:$CATALINA_HOME/bin ADDtomcat7.sh/etc/init.d/tomcat7 RUNchmod755/etc/init.d/tomcat7 #Exposeports. EXPOSE8080 #Definedefaultcommand. ENTRYPOINTservicetomcat7start&&tail-f/opt/tomcat7/logs/catalina.out tomcat7.sh exportJAVA_HOME=/usr/lib/jvm/java-7-oracle/ exportTOMCAT_HOME=/opt/tomcat7 case$1in start) sh$TOMCAT_HOME/bin/startup.sh ;; stop) sh$TOMCAT_HOME/bin/shutdown.sh ;; restart) sh$TOMCAT_HOME/bin/shutdown.sh sh$TOMCAT_HOME/bin/startup.sh ;; esac exit0 我已经把这些文件上传到了Githubhttps://github.com/agileshell/dockerfile-jdk-tomcat.git 3. 构建镜像 脚本写好了,需要转换成镜像: dockerbuild-tzingdocker/jdk-tomcat. dockerrun-d-p8090:8080zingdocker/jdk-tomcat 默认情况下,tomcat会占用8080端口,刚才在启动container的时候,指定了 -p 8090:8080,映射到宿主机端口就是8090。 http://<host>:8090host为主机IP 参考 Docker - Reference - Dockerfilehttp://docs.docker.com/reference/builder/http://www.blogjava.net/yongboy/archive/2013/12/16/407643.html一些例子http://dockerfile.github.io/https://github.com/Toub/toub-docker-tomcat8-java8-auto-deployhttps://github.com/eugeneware/docker-wordpress-nginxhttps://github.com/gemnasium/rails-meets-docker 本文转自 Mr_sheng 51CTO博客,原文链接:http://blog.51cto.com/sf1314/1979301

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

Kotlin学习笔记 (一) 基本语法

Eclipse下安装: eclipse安装kotlin 如果用Help->Eclipse marketplace安装不成功的话,可以用Help->Install new software Android studio只要安装3.0版本就可以: Android studio下载 kotlin github源代码 kotlin官网和在线执行代码 个人觉得学习kotlin语法的话,用eclipse可能比较方便点,直接写直接运行。 1. package 1 2 package my.demo import java.util.* 2. 函数定义 fun函数有两个Int参数和一个Int返回值 1 2 3 funsum(a:Int,b:Int):Int{ return a+b } 函数表达式和返回值 1 funsum(a:Int,b:Int)=a+b Unit 函数无返回值 1 2 3 funsum(a:Int,b:Int):Unit{ println( "a:${a},b:${b}" ) } 无返回值函数 1 2 3 funsum1(a:Int,b:Int){ println( "aa:${a},bb:${b}" ) } 3. 局部变量 不可变局部变量(val) 1 2 vala:Int= 1 //immediateassignment valb= 2 //`Int`typeisinferred 可变局部变量 1 2 varx= 5 x+= 1 4. 注释 // 和 /**/ 5. String 模板 1 2 3 4 5 vara= 1 vals1= "ais${a}" a= 2 vals2= "${s1.replace(" is "," was ")},butnowis${a}" 6. 条件表达式 1 2 3 4 5 6 7 funmaxOf(a:Int,b:Int):Int{ if (a>b){ return a } else { return b } } 使用if表达式 1 funmaxOf(a:Int,b:Int)= if (a>b)a else b 7. 使用可为null的值和null检查 一个引用必须被明确标记为可能为null 1 2 3 4 funmaxOf(a:Int,b:Int):Int?{ println( "a:${a}" ) return null } 8. 类型检查和动态转换 1 2 3 4 5 6 7 fungetStringLength(obj:Any):Int?{ if (objisString){ return obj.length } return null } 9. 循环 1 2 3 4 5 6 7 8 9 10 11 12 13 valitems=listOf( "a" , "b" , "c" , "e" ) for (zzinitems){ println(zz) } //或者 valitems=listOf( "a" , "b" , "c" , "e" , "f" ) for (idxinitems.indices){ println(items.get(idx)) println( "value:${items[idx]}" ) } 10. while 循环 1 2 3 4 5 6 7 8 valitems=listOf( "a" , "b" , "c" , "e" , "f" ) varind= 0 while (ind<items.size){ println( "value:${items[ind]}" ) ind++; } 11. when 表达式 1 2 3 4 5 6 fundescrbe(obj:Any):String= when(obj){ 1 -> "one" "Hello" -> "greeting" else -> "elsedefault" } 12. 范围 检查一个数字是否在一个范围时可以使用in 1 2 3 4 5 6 7 8 valx= 10 valy= 8 if (xin 1 ..y+ 1 ){ println( "xin..." ) } else { println( "notin" ) } 检查一个数字不在一个范围 1 2 3 4 5 if (x!in 1 ..y+ 1 ){ println( "bnotin" ) } else { println( "bxin" ) } 迭代一个范围 1 2 3 for (xin 1 .. 5 ){ println(x) } 级数遍历一个范围 1 2 3 for (xin 1 .. 5 step 2 ){ println(x) } 13. 使用集合 遍历 1 2 3 4 varlists=listOf( "a" , "b" , "c" ) for (eleinlists){ println(ele) } 使用in检查某个元素是否在某个集合 1 2 3 4 when{ "a" inlists->println( "ainlist" ) "b" inlists->println( "binlist" ) } 使用lambda语法过滤集合 1 2 3 4 5 6 varlists=listOf( "acake" , "apple" , "orange" ) lists.filter{x->x.startsWith( "a" )} .sortedBy{it} .map{x->x.toUpperCase()} .forEach{println(it)} 本文转自rongwei84n 51CTO博客,原文链接:http://blog.51cto.com/483181/1931412,如需转载请自行联系原作者

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

Intent进阶 和 Intent-filter 学习笔记

1,Intent的基础用法 Intent是android中各activity之间通信的一个很重要的类,一般我们是这么使用的 //创建一个intent Intentintent=newIntent(); //压值进intent中 //intent是基于一种基于Map的数据结构 //传我们的基本数据类型的可以之间key,value方式传值 intent.putExtra("hello","Helloworld"); //但是,传一个对象的时要注意,该对象要实现序列化窗口才可以传值 //putExtra(Stringname,Serializablevalue) Demodemo=newDemo(); intent.putExtra("Demo",demo); //然后,我们把这个intent传到另外一个activity intent.setClass(xxx.this,zzz.class); startActivity(intent); //------- //目标activity //获取传过来的intentIntentintent=getIntent(); //从Intent中获取值 Stringhello=intent.getStringExtra("Demo"); Demodemo=(Demo)intent.getSerializable("Demo"); 以上代码就是最基础的Intent的用法 2,深入Intent的构造和Intent-filter的基础入门 首先我们看下Intent的构造方法 Intent() //Createanemptyintent. Intent(Intento) //Copyconstructor. Intent(Stringaction) //Createanintentwithagivenaction. Intent(Stringaction,Uriuri) //Createanintentwithagivenactionandforagivendataurl. Intent(ContextpackageContext,Class<?>cls) //Createanintentforaspecificcomponent. Intent(Stringaction,Uriuri,ContextpackageContext,Class<?>cls) //Createanintentforaspecificcomponentwithaspecifiedactionanddata. 出这些构造方法中我们,可以看出,新建一个Intent其实可以设置很多东西,这里我说说componentName,action,category,data componentName componentName 直译的话就是组件的名字的意思,如果我们写的一个类当作成一个组件,那么这个componentName就是用来封装我们写的这些类的位置. //创建一个component的对象 ComponentNamecomponentName=newComponentName(Context.this,xxx.class); Intentintent=newIntent(); Intent.setComponent(componentName); startActivity(intent); //---------- //在xxxactivity中 ComponentNamecomp=getIntent().getComponent(); StringpackageName=comp.getPackName(); StringclassName=comp.getClassName(); 其实细心的同学可以发现,其实跟setClass(),没什么区别吗,而且,还比setClass()麻烦,其实,setClass()是封装了这个功能而已,最实现还是要用到这个类. Action,category,data简单入门 我感觉,学intent 和 intent-filter把action,category,data搞清楚才算真正的掌握了intent的用法. Action 如果学过Structs2的同学应该不会陌生,所谓的action就是发送一个特定的请求,然后,由一个符合这个请求的activity响应 官方文档中是这么说action的: The action largely determines how the rest of the intent is structured — particularly thedataandextrasfields — much as a method name determines a set of arguments and a return value. For this reason, it's a good idea to use action names that are as specific as possible, and to couple them tightly to the other fields of the intent. In other words, instead of defining an action in isolation, define an entire protocol for the Intent objects your components can handle. 我简要说下我理解的大义,有错欢迎指出 action 在很大一部分程度上决定你的intent 是如何构建的,特别是还有data,和 额外的一些字段,还有更多的是如何决定方法名,设置数组和返回的参数.由于这个原因,这是一个很好的方法去尽可能的具体的使用action,用action把这些字段紧密的联系在一起.另外,灵活定义你的action,然后把它定义在一个文档中为你的intent对象的组建能够正常处理 渣翻译…可能比谷歌翻译还有烂…有错欢迎指出!!!!!!!!!!!!! category 要使一个action能够正常运行,category是必不可少的,关于category详细介绍请看开发者文档中的intent and intent-filter 这里说下注意的细节和使用. 首先,这句话是很重要的..取之于官方文档 Therefore, activities that are willing to receive implicit intents must include "android.intent.category.DEFAULT" in their intent filters. 这句话,告诉我们在intent-filter(可以用xml创建也可以用代码创建,这里主要讲xml的创建),必须添加一个android.intent.category.DEFAULT,至于,不添加会发生什么事…我花了半个小时的排错告诉我是无法运行的 //在我们要运行的activity中添加 <activityandroid:name=".SecondActivity"android:label="second"><intent-filter> <actionandroid:name="kg.tom.TEST"/> <categoryandroid:name=" android.intent.category.DEFAULT"/> </intent-filter> </activity> //firstActivity //在创建好的一个监听器里面方法中写上 Intentintent=newIntent(); intent.setAction("kg.tom.TEST"); //利用action来运行相应的activitystartActivity(intent); 注意:每个intent只能设置一个action,但是,可以设置多个category,这里的组合问题,自己好好想想吧. data 因为就是一些参数的介绍,看官方文档就好了,我是这样理解这个DATA,例如,我们一个Mp3播放器,当我们在任务管理器中点击一个MP3文件,MP3这个文件就是一个data,就会触发我们,在intent-filter匹配这个Mp3,<data />的activity运行.. 本文转自 liam2199 博客,原文链接:http://blog.51cto.com/youxilua/772705 如需转载请自行联系原作者

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

Hadoop基础入门学习笔记(基本概念)

一、数据块(blck) HDFS(Hadp Distributed File System)默认的最基本的存储单位是64M的数据块。 和普通文件系统相同的是,HDFS中的文件是被分成64M一块的数据块存储的。 不同于普通文件系统的是,HDFS中,如果一个文件小于一个数据块的大小,并不占用整个数据块存储空间。 二、元数据节点(Namende)和数据节点(datande) 元数据节点用来管理文件系统的命名空间 其将所有的文件和文件夹的元数据保存在一个文件系统树中。 这些信息也会在硬盘上保存成以下文件:命名空间镜像(namespace image)及修改日志(edit lg) 其还保存了一个文件包括哪些数据块,分布在哪些数据节点上。然而这些信息并不存储在硬盘上,而是在系统启动的时候从数据节点收集而成的。 数据节点是文件系统中真正存储数据的地方。 客户端(client)或者元数据信息(namende)可以向数据节点请求写入或者读出数据块。 其周期性的向元数据节点回报其存储的数据块信息。 从元数据节点(secndary namende) 从元数据节点并不是元数据节点出现问题时候的备用节点,它和元数据节点负责不同的事情。 其主要功能就是周期性将元数据节点的命名空间镜像文件和修改日志合并,以防日志文件过大。这点在下面会详细叙述。 合并过后的命名空间镜像文件也在从元数据节点保存了一份,以防元数据节点失败的时候,可以恢复。 1、 元数据节点文件夹结构 VERSIN文件是java prperties文件,保存了HDFS的版本号。 layutVersin是一个负整数,保存了HDFS的持续化在硬盘上的数据结构的格式版本号。 namespaceID是文件系统的唯一标识符,是在文件系统初次格式化时生成的。 cTime此处为0 strageType表示此文件夹中保存的是元数据节点的数据结构。 1 2 3 4 namespaceID=1232737062 cTime=0 strageType=NAME_NDE layutVersin=-18 2、文件系统命名空间映像文件及修改日志 当文件系统客户端(client)进行写操作时,首先把它记录在修改日志中(edit lg) 元数据节点在内存中保存了文件系统的元数据信息。在记录了修改日志后,元数据节点则修改内存中的数据结构。 每次的写操作成功之前,修改日志都会同步(sync)到文件系统。 fsimage文件,也即命名空间映像文件,是内存中的元数据在硬盘上的checkpint,它是一种序列化的格式,并不能够在硬盘上直接修改。 同数据的机制相似,当元数据节点失败时,则最新checkpint的元数据信息从fsimage加载到内存中,然后逐一重新执行修改日志中的操作。 从元数据节点就是用来帮助元数据节点将内存中的元数据信息checkpint到硬盘上的 checkpint的过程如下: 从元数据节点通知元数据节点生成新的日志文件,以后的日志都写到新的日志文件中。 从元数据节点用http get从元数据节点获得fsimage文件及旧的日志文件。 从元数据节点将fsimage文件加载到内存中,并执行日志文件中的操作,然后生成新的fsimage文件。 从元数据节点将新的fsimage文件用http pst传回元数据节点 元数据节点可以将旧的fsimage文件及旧的日志文件,换为新的fsimage文件和新的日志文件(第一步生成的),然后更新fstime文件,写入此次checkpint的时间。 这样元数据节点中的fsimage文件保存了最新的checkpint的元数据信息,日志文件也重新开始,不会变的很大了。 3、从元数据节点的目录结构 4、数据节点的目录结构 数据节点的VERSION文件格式如下: 1 2 3 4 5 namespaceID=1232737062 storageID=DS-1640411682-127.0.1.1-50010-1254997319480 cTime=0 storageType=DATA_NODE layoutVersion=-18 blk_<id>保存的是HDFS的数据块,其中保存了具体的二进制数据。 blk_<id>.meta保存的是数据块的属性信息:版本信息,类型信息,和checksum 当一个目录中的数据块到达一定数量的时候,则创建子文件夹来保存数据块及数据块属性信息。 本文转自南非蚂蚁51CTO博客,原文链接:http://blog.51cto.com/ixdba/1428278 ,如需转载请自行联系原作者

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

mysql性能优化学习笔记-存储引擎

mysql体系架构 客户端(java、php、python等) mysql服务层(连接管理器、查询解析器、查询优化器、查询缓存) mysql存储引擎(innodb、myisam等) 存储引擎针对表而言的,不针对库 mysql存储引擎 mysql存储引擎之MyISAM 5.5前默认的存储引擎、临时表(查询、排序时由查询优化器生成的表)、系统表 特性: 并发性与锁级别(表级锁), 表损坏修复,检查check table tablename,修复repair table tablename 此外也可以通过myisamchk对表进行修复,但是必须注意的是使用该命令进行修复时需要将mysql服务停止后进行。否则有可能对数据表造成更大的损坏。 myisam支持全文索引 myisam表支持数据压缩,可以使用myisampack命令进行压缩,如:myasimpack -b -f tablename.MYI。对已经压缩后的表不能进行写操作,因此要慎重操作。 限制: 5.0前,单表文件最大支持4G。如存储大表需要修改MAX_Rows和AVG_ROW_LENGTH;5.0后默认支持256TB 使用场景 非事务型应用 只读类应用 空间类应用 mysql存储引擎之Innodb MySQL5.5及以后版本默认存储引擎 Innodb使用表空间进行数据存储 由innodb_file_per_table参数的值进行控制,如果为ON,则独立表空间(tablename.ibd)。如果为OFF,则会存储到系统共享表空间ibdataX。 如何选择系统表空间和独立表空间 系统表空间无法简单的收缩文件大小 独立表空间可以通过optimize table命令收缩系统文件 系统表空间会产生IO瓶颈 独立表空间可以同时向多个文件刷新数据 建议对Innodb使用独立的表空间。5.6后已经是默认方式。 如何将系统表空间转换为独立表空间 1、使用mysqldump导出所有表数据 2、停止Mysql服务,修改参数,并删除Innodb相关文件。如果是主从架构可以先处理从库再处理主库。 3、重启Mysql服务,重建Innodb系统表空间 4、重新导入数据 Innodb存储引擎的特性 Innodb数据字典信息 Innodb的特性 事务性存储引擎 完全支持事务的ACID特性, Redo Log(重做日志,已提交事务,实现事务的持久性)和Undo Log(未提交事务进行回滚) Innodb支持行级锁 支持更多的写并发 行级锁由存储引擎层实现的。 什么是锁? 管理资源的并发访问 实现事务的隔离性 锁的类型 共享锁(读锁) 独占锁(写锁),排他性 锁的粒度 行级锁、页级锁、表级锁 表级锁 行级锁 阻塞和死锁 什么是阻塞,不同锁之间的兼容性,不同锁之间需要等待锁响应。 什么是死锁,两个或两个以上,互相占用资源而互相等待。一般情况下系统会自动处理。 Innodb状态检查 shown engine innodb status 使用场景 Innodb适用于大多数OLTP应用 mysql存储引擎之CSV 文件存储特点:csv文件作为存储引擎。数据以文件方式存储在文件中。 特点 以csv格式进行数据存储 所有的列定义不能是NULL 不支持索引(不适用于大表及在线系统) 可以直接对数据文件进行编辑 使用场景 适用于数据交换的中间表 mysql存储引擎之Archive 特点 以zlib对表数据进行压缩,磁盘I/O更少 存储在ARZ为后缀的文件中 存储特点: 只支持insert和select操作,支持行级锁 只允许在自增ID列上添加索引 使用场景 日志和数据采集类应用 mysql存储引擎之Memory 特点 也成为Heap存储引擎,所有数据保存在内存中。一旦mysql重启,则数据会丢失,表结构会保存。 功能特点: 支持hash索引(等值查询)和btree(范围查询)索引,默认为hash索引 所有字段固定长度为char(10) 不支持blog和text等大字段 使用表级锁,因此性能也不一定会很高。 表最大大小由参数max_heap_table_size参数决定 容易混淆的概念 临时表,系统使用的临时表;create temporary table建立的表。 使用场景 用于查找或映射表,如邮编和地区的对应表。 保存数据的中间表 混存周期性聚合数据的结果表 mysql存储引擎之Federated 特点 提供了远程访问mysql服务器上表的方法 本地不存储数据,数据全部存储在远程服务器上 本地会保存远程数据库表结构和远程连接的信息 如何使用 由于可以通过其他方式替代,因而默认是禁止的。但可以在启动时通过federated参数 mysql://user_name[:password]@host_name[:port]/dbname/tablename 使用场景 偶尔的统计分析和手工查询 如何选择存储引擎 参考条件 事务 备份,热备 崩溃恢复 存储引擎的特性 尽量不要同时混合使用多种存储引擎 本文转自秋楓博客园博客,原文链接:http://www.cnblogs.com/rwxwsblog/p/5785848.html,如需转载请自行联系原作者

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

Android开发学习笔记:Gallery和GridView浅析

一.Gallery的简介 Gallery(画廊)是一个锁定中心条目并且拥有水平滚动列表的视图,一般用来浏览图片,并且可以响应事件显示信息。Gallery还可以和ImageSwitcher组件结合使用来实现一个通过缩略图来浏览图片的效果。 Gallery常用的XML属性 属性名称 描述 android:animationDuration 设置布局变化时动画的转换所需的时间(毫秒级)。仅在动画开始时计时。该值必须是整数,比如:100。 android:gravity 指定在对象的X和Y轴上如何放置内容。指定一下常量中的一个或多个(使用 “|”分割) Constant Value Description top 0x30 紧靠容器顶端,不改变其大小 bottom 0x50 紧靠容器底部,不改变其大小 left 0x03 紧靠容器左侧,不改变其大小 right 0x05 紧靠容器右侧,不改变其大小 center_vertical 0x10 垂直居中,不改变其大小 fill_vertical 0x70 垂直方向上拉伸至充满容器 center_horizontal 0x01 水平居中,不改变其大小 Fill_horizontal 0x07 水平方向上拉伸使其充满容器 center 0x11 居中对齐,不改变其大小 fill 0x77 在水平和垂直方向上拉伸,使其充满容器 clip_vertical 0x80 垂直剪切(当对象边缘超出容器的时候,将上下边缘超出的部分剪切掉) clip_horizontal 0x08 水平剪切(当对象边缘超出容器的时候,将左右边缘超出的部分剪切掉) android:spacing 图片之间的间距 android:unselectedAlpha 设置未选中的条目的透明度(Alpha)。该值必须是float类型,比如:“1.2”。 首先介绍Gallery单独使用的例子: MainActivity.java packagecom.android.gallerydemo; importandroid.app.Activity; importandroid.content.Context; importandroid.os.Bundle; importandroid.view.View; importandroid.view.ViewGroup; importandroid.widget.AdapterView; importandroid.widget.AdapterView.OnItemClickListener; importandroid.widget.BaseAdapter; importandroid.widget.Gallery; importandroid.widget.ImageView; importandroid.widget.Toast; publicclassMainActivityextendsActivity{ privateGallerygallery; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); gallery=(Gallery)findViewById(R.id.gallery); //设置图片适配器 gallery.setAdapter(newImageAdapter(this)); //设置监听器 gallery.setOnItemClickListener(newOnItemClickListener(){ @Override publicvoidonItemClick(AdapterView<?>parent,Viewv,intposition,longid){ Toast.makeText(MainActivity.this,"点击了第"+(position+1)+"张图片",Toast.LENGTH_LONG).show(); } }); } } classImageAdapterextendsBaseAdapter{ //声明Context privateContextcontext; //图片源数组 privateInteger[]imageInteger={ R.drawable.pic1, R.drawable.pic2, R.drawable.pic3, R.drawable.pic4, R.drawable.pic5, R.drawable.pic6, R.drawable.pic7 }; //声明ImageAdapter publicImageAdapter(Contextc){ context=c; } @Override //获取图片的个数 publicintgetCount(){ returnimageInteger.length; } @Override //获取图片在库中的位置 publicObjectgetItem(intposition){ returnposition; } @Override //获取图片在库中的位置 publiclonggetItemId(intposition){ //TODOAuto-generatedmethodstub returnposition; } @Override publicViewgetView(intposition,ViewconvertView,ViewGroupparent){ ImageViewimageView=newImageView(context); //给ImageView设置资源 imageView.setImageResource(imageInteger[position]); //设置比例类型 imageView.setScaleType(ImageView.ScaleType.FIT_XY); //设置布局图片128x192显示 imageView.setLayoutParams(newGallery.LayoutParams(128,192)); returnimageView; } } main.xml <?xmlversion="1.0"encoding="utf-8"?> <Galleryxmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/gallery" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:background="?android:galleryItemBackground" /> 效果图: Gallery和ImageSwitcher组件结合使用的例子: MainActivity.java packagecom.android.gallerytest; importandroid.app.Activity; importandroid.content.Context; importandroid.os.Bundle; importandroid.view.View; importandroid.view.ViewGroup; importandroid.view.Window; importandroid.view.animation.AnimationUtils; importandroid.widget.AdapterView; importandroid.widget.BaseAdapter; importandroid.widget.Gallery; importandroid.widget.ImageSwitcher; importandroid.widget.ImageView; importandroid.widget.AdapterView.OnItemSelectedListener; importandroid.widget.Gallery.LayoutParams; importandroid.widget.ViewSwitcher.ViewFactory; publicclassMainActivityextendsActivityimplementsOnItemSelectedListener, ViewFactory{ privateImageSwitchermSwitcher; //大图片对应的缩略图源数组 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}; //大图片源数组 privateInteger[]mImageIds={R.drawable.sample_0,R.drawable.sample_1, R.drawable.sample_2,R.drawable.sample_3,R.drawable.sample_4, R.drawable.sample_5,R.drawable.sample_6,R.drawable.sample_7}; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); //设置窗口无标题 requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.main); mSwitcher=(ImageSwitcher)findViewById(R.id.switcher); //注意在使用一个ImageSwitcher之前, //一定要调用setFactory方法,要不setImageResource这个方法会报空指针异常。 mSwitcher.setFactory(this); //设置动画效果 mSwitcher.setInAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_in)); mSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_out)); Galleryg=(Gallery)findViewById(R.id.gallery); //添加OnItemSelectedListener监听器 g.setAdapter(newImageAdapter(this)); g.setOnItemSelectedListener(this); } //创建内部类ImageAdapter publicclassImageAdapterextendsBaseAdapter{ publicImageAdapter(Contextc){ mContext=c; } publicintgetCount(){ returnmThumbIds.length; } publicObjectgetItem(intposition){ returnposition; } publiclonggetItemId(intposition){ returnposition; } publicViewgetView(intposition,ViewconvertView,ViewGroupparent){ ImageViewi=newImageView(mContext); i.setImageResource(mThumbIds[position]); //设置边界对齐 i.setAdjustViewBounds(true); //设置布局参数 i.setLayoutParams(newGallery.LayoutParams( LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT)); //设置背景资源 i.setBackgroundResource(R.drawable.picture_frame); returni; } privateContextmContext; } @Override //实现onItemSelected()方法,更换图片 publicvoidonItemSelected(AdapterView<?>adapter,Viewv,intposition, longid){ //设置图片资源 mSwitcher.setImageResource(mImageIds[position]); } @Override publicvoidonNothingSelected(AdapterView<?>arg0){ } @Override //实现makeView()方法,为ImageView设置布局格式 publicViewmakeView(){ ImageViewi=newImageView(this); //设置背景颜色 i.setBackgroundColor(0xFF000000); //设置比例类型 i.setScaleType(ImageView.ScaleType.FIT_CENTER); //设置布局参数 i.setLayoutParams(newImageSwitcher.LayoutParams( LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT)); returni; } } main.xml <?xmlversion="1.0"encoding="utf-8"?> <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ImageSwitcher android:id="@+id/switcher" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" /> <Gallery android:id="@+id/gallery" android:background="#55000000" android:layout_width="fill_parent" android:layout_height="60dp" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:gravity="center_vertical" android:spacing="16dp" /> </RelativeLayout> 效果图: 二.GridView的简介 GridView(网格视图)是按照行列的方式来显示内容的,一般用于显示图片,图片等内容,比如实现九宫格图,用GridView是首选,也是最简单的。主要用于设置Adapter。 GridView常用的XML属性: 属性名称 描述 android:columnWidth 设置列的宽度。 android:gravity 设置此组件中的内容在组件中的位置。可选的值有:top、bottom、left、right、center_vertical、fill_vertical、center_horizontal、fill_horizontal、center、fill、clip_vertical可以多选,用“|”分开。 android:horizontalSpacing 两列之间的间距。 android:numColumns 设置列数。 android:stretchMode 缩放模式。 android:verticalSpacing 两行之间的间距。 下面有三个例子,第一个是只显示图片的,第二个是显示图片文字的(这里的图片是Android系统自带的图片),第三个是显示自定义的图片文字。前面两个例子的实现都不是很难,第三个例子的实现有些复杂,学习GridView的时候,就想着能不能自定义自己喜欢的图片加上文字,在网上找些资料,一般都是第二个例子的形式的,最后在视频学习上找到了能实现自定义自己的图片的例子。自己就照着例子去学习,修改成了第三个例子。 第一个例子: MainActivity.java package com.android.gridview.activity; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.GridView; import android.widget.ImageView; import android.widget.Toast; public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); GridView gv = (GridView)findViewById(R.id.GridView1); //为GridView设置适配器 gv.setAdapter(new MyAdapter(this)); //注册监听事件 gv.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View v, int position, long id) { Toast.makeText(MainActivity.this, "pic" + position, Toast.LENGTH_SHORT).show(); } }); } } //自定义适配器 class MyAdapter extends BaseAdapter{ //上下文对象 private Context context; //图片数组 private Integer[] imgs = { R.drawable.pic0, R.drawable.pic1, R.drawable.pic2, R.drawable.pic3, R.drawable.pic4, R.drawable.pic5, R.drawable.pic6, R.drawable.pic7, R.drawable.pic8, R.drawable.pic0, R.drawable.pic1, R.drawable.pic2, R.drawable.pic3, R.drawable.pic4, R.drawable.pic5, R.drawable.pic6, R.drawable.pic7, R.drawable.pic8, }; MyAdapter(Context context){ this.context = context; } public int getCount() { return imgs.length; } public Object getItem(int item) { return item; } public long getItemId(int id) { return id; } //创建View方法 public View getView(int position, View convertView, ViewGroup parent) { ImageView imageView; if (convertView == null) { imageView = new ImageView(context); imageView.setLayoutParams(new GridView.LayoutParams(75, 75));//设置ImageView对象布局 imageView.setAdjustViewBounds(false);//设置边界对齐 imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);//设置刻度的类型 imageView.setPadding(8, 8, 8, 8);//设置间距 } else { imageView = (ImageView) convertView; } imageView.setImageResource(imgs[position]);//为ImageView设置图片资源 return imageView; } } main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <GridView android:id="@+id/GridView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:columnWidth="90dp" android:numColumns="3" android:verticalSpacing="10dp" android:horizontalSpacing="10dp" android:stretchMode="columnWidth" android:gravity="center" /> </LinearLayout> 效果图: 第二个例子: MainActivity.java package com.android.gridview2.activity; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import android.app.Activity; import android.os.Bundle; import android.widget.GridView; import android.widget.SimpleAdapter; public class MainActivity extends Activity { private GridView gv; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.gridview); //准备要添加的数据条目 List<Map<String, Object>> items = new ArrayList<Map<String,Object>>(); for (int i = 0; i < 9; i++) { Map<String, Object> item = new HashMap<String, Object>(); item.put("imageItem", R.drawable.icon);//添加图像资源的ID item.put("textItem", "icon" + i);//按序号添加ItemText items.add(item); } //实例化一个适配器 SimpleAdapter adapter = new SimpleAdapter(this, items, R.layout.grid_item, new String[]{"imageItem", "textItem"}, new int[]{R.id.image_item, R.id.text_item}); //获得GridView实例 gv = (GridView)findViewById(R.id.mygridview); //为GridView设置适配器 gv.setAdapter(adapter); } } gridview.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" > <GridView android:id="@+id/mygridview" android:numColumns="3" android:gravity="center_horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:stretchMode="columnWidth" /> </LinearLayout> grid_item.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/RelativeLayout1" android:layout_width="wrap_content" android:layout_height="fill_parent" android:paddingBottom="6dip" > <ImageView android:id="@+id/image_item" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" /> <TextView android:id="@+id/text_item" android:layout_below="@+id/image_item" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_centerHorizontal="true" /> </RelativeLayout> 效果图: 第三个例子: MainActivity.java package com.android.gridview3; import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.GridView; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import android.widget.AdapterView.OnItemClickListener; public class MainActivity extends Activity { private GridView gridView; //图片的文字标题 private String[] titles = new String[] { "pic1", "pic2", "pic3", "pic4", "pic5", "pic6", "pic7", "pic8", "pic9"}; //图片ID数组 private int[] images = new int[]{ R.drawable.pic1, R.drawable.pic2, R.drawable.pic3, R.drawable.pic4, R.drawable.pic5, R.drawable.pic6, R.drawable.pic7, R.drawable.pic8,R.drawable.pic9 }; @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); gridView = (GridView) findViewById(R.id.gridview); PictureAdapter adapter = new PictureAdapter(titles, images, this); gridView.setAdapter(adapter); gridView.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View v, int position, long id) { Toast.makeText(MainActivity.this, "pic" + (position+1), Toast.LENGTH_SHORT).show(); } }); } } //自定义适配器 class PictureAdapter extends BaseAdapter{ private LayoutInflater inflater; private List<Picture> pictures; public PictureAdapter(String[] titles, int[] images, Context context) { super(); pictures = new ArrayList<Picture>(); inflater = LayoutInflater.from(context); for (int i = 0; i < images.length; i++) { Picture picture = new Picture(titles[i], images[i]); pictures.add(picture); } } @Override public int getCount() { if (null != pictures) { return pictures.size(); } else { return 0; } } @Override public Object getItem(int position) { return pictures.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder; if (convertView == null) { convertView = inflater.inflate(R.layout.picture_item, null); viewHolder = new ViewHolder(); viewHolder.title = (TextView) convertView.findViewById(R.id.title); viewHolder.image = (ImageView) convertView.findViewById(R.id.image); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.title.setText(pictures.get(position).getTitle()); viewHolder.image.setImageResource(pictures.get(position).getImageId()); return convertView; } } class ViewHolder { public TextView title; public ImageView image; } class Picture { private String title; private int imageId; public Picture() { super(); } public Picture(String title, int imageId) { super(); this.title = title; this.imageId = imageId; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public int getImageId() { return imageId; } public void setImageId(int imageId) { this.imageId = imageId; } } main.xml <?xml version="1.0" encoding="utf-8"?> <GridView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/gridview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:columnWidth="90dp" android:numColumns="auto_fit" android:verticalSpacing="10dp" android:horizontalSpacing="10dp" android:stretchMode="columnWidth" android:gravity="center" /> picture_item.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/root" android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" > <ImageView android:id="@+id/image" android:layout_width="100dp" android:layout_height="150dp" android:layout_gravity="center" android:scaleType="fitXY" android:padding="4dp" /> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:gravity="center_horizontal" /> </LinearLayout> 效果图: 本文转自 lingdududu 51CTO博客,原文链接:http://blog.51cto.com/liangruijun/647355

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

Android开发学习笔记:RadioButton和CheckBox浅析

一.RadioButton单选按钮 RadioButton(单选按钮)在Android开发中应用的非常广泛,比如一些选择项的时候,会用到单选按钮。它是一种单个圆形单选框双状态的按钮,可以选择或不选择。在RadioButton没有被选中时,用户能够按下或点击来选中它。但是,与复选框相反,用户一旦选中就不能够取消选中。 实现RadioButton由两部分组成,也就是RadioButton和RadioGroup配合使用.RadioGroup是单选组合框,可以容纳多个RadioButton的容器.在没有RadioGroup的情况下,RadioButton可以全部都选中;当多个RadioButton被RadioGroup包含的情况下,RadioButton只可以选择一个。并用setOnCheckedChangeListener来对单选按钮进行监听 下面的具体的例子: MainActivity.java packagecom.android.radiobutton; importandroid.app.Activity; importandroid.os.Bundle; importandroid.widget.RadioGroup; importandroid.widget.Toast; publicclassMainActivityextendsActivity{ //声明RadioGroup RadioGroupraGroup1,raGroup2; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); //通过findViewById获得RadioGroup对象 raGroup1=(RadioGroup)findViewById(R.id.radioGroup1); //添加事件监听器 raGroup1.setOnCheckedChangeListener(newRadioGroup.OnCheckedChangeListener(){ @Override publicvoidonCheckedChanged(RadioGroupgroup,intcheckedId){ //TODOAuto-generatedmethodstub if(checkedId==R.id.radioBtn1){ Toast.makeText(MainActivity.this,"你来自广东省",Toast.LENGTH_LONG).show(); } elseif(checkedId==R.id.radioBtn2){ Toast.makeText(MainActivity.this,"你来自广西省",Toast.LENGTH_LONG).show(); } else{ Toast.makeText(MainActivity.this,"你来自湖南省",Toast.LENGTH_LONG).show(); } } }); raGroup2=(RadioGroup)findViewById(R.id.radioGroup2); raGroup2.setOnCheckedChangeListener(newRadioGroup.OnCheckedChangeListener(){ @Override publicvoidonCheckedChanged(RadioGroupgroup,intcheckedId){ //TODOAuto-generatedmethodstub if(checkedId==R.id.radioBtn4){ Toast.makeText(MainActivity.this,"你的性别是男",Toast.LENGTH_LONG).show(); } else{ Toast.makeText(MainActivity.this,"你的性别是女",Toast.LENGTH_LONG).show(); } } }); } } 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/hello1" /> <RadioGroup android:id="@+id/radioGroup1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > <RadioButton android:id="@+id/radioBtn1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/radioBtn1" /> <RadioButton android:id="@+id/radioBtn2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/radioBtn2" /> <RadioButton android:id="@+id/radioBtn3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/radioBtn3" /> </RadioGroup> <!--在两个RadioGroup之间画条横线--> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#ffffff" /> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello2" /> <RadioGroup android:id="@+id/radioGroup2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > <RadioButton android:id="@+id/radioBtn4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/radioBtn4" android:textColor="#ffffff" /> <RadioButton android:id="@+id/radioBtn5" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/radioBtn5" /> </RadioGroup> </LinearLayout> strings.xml <?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello1">你来自哪个省</string> <string name="hello2">你的性别是</string> <string name="app_name">单选按钮测试</string> <string name="radioBtn1">广东</string> <string name="radioBtn2">广西</string> <string name="radioBtn3">湖南</string> <string name="radioBtn4">男</string> <string name="radioBtn5">女</string> </resources> 效果图: RadioButton的另一种效果: 要实现上面的效果,只要在main.xml布局文件中的<RadioButton/>加入android:button="@null" android:drawableRight="@android:drawable/btn_radio"即可,代码如下所示: <?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/hello1" /> <RadioGroup android:id="@+id/radioGroup1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > <RadioButton android:id="@+id/radioBtn1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/radioBtn1" android:button="@null" android:drawableRight="@android:drawable/btn_radio" /> <RadioButton android:id="@+id/radioBtn2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/radioBtn2" android:button="@null" android:drawableRight="@android:drawable/btn_radio" /> <RadioButton android:id="@+id/radioBtn3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/radioBtn3" android:button="@null" android:drawableRight="@android:drawable/btn_radio" /> </RadioGroup> <!--在两个RadioGroup之间画条横线--> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#ffffff" /> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello2" /> <RadioGroup android:id="@+id/radioGroup2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > <RadioButton android:id="@+id/radioBtn4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/radioBtn4" android:textColor="#ffffff" android:button="@null" android:drawableRight="@android:drawable/btn_radio" /> <RadioButton android:id="@+id/radioBtn5" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/radioBtn5" android:button="@null" android:drawableRight="@android:drawable/btn_radio" /> </RadioGroup> </LinearLayout> 二.CheckBox复选按钮 CheckBox复选按钮是一种有双状态按钮的特殊类型,可以选中或者不选中。可以现在布局文件中定义多选按钮,然后对每一个多选按钮进行事件监setOnCheckedChangeListener,通过isChecked来判断选项是否被选中 下面是具体的例子: MainActivity.java packagecom.android.checkbox; importandroid.app.Activity; importandroid.os.Bundle; importandroid.widget.CheckBox; importandroid.widget.CompoundButton; importandroid.widget.Toast; importandroid.widget.CompoundButton.OnCheckedChangeListener; publicclassMainActivityextendsActivity{ //声明复选按钮 privateCheckBoxcBox1; privateCheckBoxcBox2; privateCheckBoxcBox3; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); //通过findViewById获得CheckBox对象 cBox1=(CheckBox)findViewById(R.id.checkbox1); cBox2=(CheckBox)findViewById(R.id.checkbox2); cBox3=(CheckBox)findViewById(R.id.checkbox3); //注册事件监听器 cBox1.setOnCheckedChangeListener(listener); cBox2.setOnCheckedChangeListener(listener); cBox3.setOnCheckedChangeListener(listener); } //响应事件 privateOnCheckedChangeListenerlistener=newOnCheckedChangeListener(){ @Override publicvoidonCheckedChanged(CompoundButtonbuttonView,booleanisChecked) { //cBox1被选中 if(buttonView.getId()==R.id.checkbox1){ if(isChecked){ Toast.makeText(MainActivity.this,"你喜欢足球",Toast.LENGTH_LONG).show(); } } //cBox2被选中 elseif(buttonView.getId()==R.id.checkbox2){ if(isChecked){ Toast.makeText(MainActivity.this,"你喜欢篮球",Toast.LENGTH_LONG).show(); } } //cBox3被选中 elseif(buttonView.getId()==R.id.checkbox3){ if(isChecked){ Toast.makeText(MainActivity.this,"你喜欢排球",Toast.LENGTH_LONG).show(); } } } }; } main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" android:textSize="20sp" android:textStyle="bold" android:textColor="#FFFFFF" /> <CheckBox android:id="@+id/checkbox1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/football" android:textSize="16sp" /> <CheckBox android:id="@+id/checkbox2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/basketball" android:textSize="16sp" /> <CheckBox android:id="@+id/checkbox3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/volleyball" android:textSize="16sp" /> </LinearLayout> strings.xml <?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">你喜欢的运动是</string> <string name="app_name">复选按钮测试</string> <string name="football">足球</string> <string name="basketball">篮球</string> <string name="volleyball">排球</string> </resources> 效果图: 三.总结 RadioButton和CheckBox的区别: 1、单个RadioButton在选中后,通过点击无法变为未选中单个CheckBox在选中后,通过点击可以变为未选中 2、一组RadioButton,只能同时选中一个一组CheckBox,能同时选中多个 3、RadioButton在大部分UI框架中默认都以圆形表示CheckBox在大部分UI框架中默认都以矩形表示 RadioButton和RadioGroup的关系: 1、RadioButton表示单个圆形单选框,而RadioGroup是可以容纳多个RadioButton的容器 2、每个RadioGroup中的RadioButton同时只能有一个被选中 3、不同的RadioGroup中的RadioButton互不相干,即如果组A中有一个选中了,组B中依然可以有一个被选中 4、一般情况下,一个RadioGroup中至少有2个RadioButton 5、一般情况下,一个RadioGroup中的RadioButton默认会有一个被选中,并建议您将它放在RadioGroup中的起始位置 本文转自 lingdududu 51CTO博客,原文链接:http://blog.51cto.com/liangruijun/652042

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

Android学习笔记--Activity的生命周期

MicrosoftInternetExplorer402DocumentNotSpecified7.8Normal0 参考文档:安装目录/docs/index.html Activity的生命周期函数 onCreate(Activity被第一个创建时),onReStart,onStart(Activity可视的时候),onDestroy,onPause(Activity暂停状态),onResume(Activity可被获得焦点的时候),onStop(Activity不可见的时候) 启动一个新的Activity会依次调用onCreate,onStart,onResume 调用另外一个Activity会依次调用onPause(第一个),onCreate(第二个),onStart(第二个),onResume(第二个),onStop(第一个) 调用返回按钮Activty会依次调用onPause(第二个),onReStart(第一个),onStart(第一个),onResume(第一个),onStop(第二个),onDestory(第二个) onDestory()被调用的时机1.明确调用finish方法2.系统自适应释放 Task基本概念(栈中的所有Activity)栈压栈,弹栈(后进先出原则) Task运行过程,当应用程序启动之后,运行第一个Activity被压入栈中(显示会时栈中最顶部的Activity) 3.模态化窗体(对话框) 在AndroidManifest.xml文件中<Activityandroid:name=".MofityActivity" android:label="MofityActivity" android:theme="@anroid:style/Theme.Dialog" /> 可被杀死的方法onStop,onPause,onDestory 本文转自My_King1 51CTO博客,原文链接:http://blog.51cto.com/apprentice/1360576,如需转载请自行联系原作者

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

Android学习笔记--工程创建及目录结构

MicrosoftInternetExplorer402DocumentNotSpecified7.8Normal0 一,新建project New->androidproject->projectname->buildtarget(开发的版本选择)->apllcationname->packagename->createactivity(显示界面)->minsdkversion(最低兼容sdk版本) 二,android程序的目录结构 Src==>编写的源文件 Gen==>引用程序的资源文件(不要修改) Android==>源文件jar文件 Assets==>放置任何文件 Res==>此处放置会在gen中生成相应ID Drawable放置图片分为多个分辨率图片hdpi,ldpi,mdpi高中低 Layout布局方式 Values adnroidManifest.xml全局配置文件 本文转自My_King1 51CTO博客,原文链接:http://blog.51cto.com/apprentice/1360580,如需转载请自行联系原作者

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

Android进阶笔记:AIDL内部实现详解 (一)

AIDL内部实现详解 (一) AIDL的作用是实现跨进程通讯使用方法也非常的简单,他的设计模式是典型的C/S架构。使用AIDL只要在Client端和Server端的项目根目录下面创建一个aidl的文件夹,在aidl文件夹的下面用java代码编写一个后缀名为.aidl的接口文件然后重新编译一下就会在gen目录下生成相对应的java文件。这里主要研究aidl的运作流程以及原理。 aidl结构 首先我在Server端去实现了一个aidl的接口文件代码如下: //IMyAidl.aidl interface IMyAidl { int add(int arg1, int aarg2); } 重新编译(rebuild)就会在generated目录下面生成相应的IMyAidl.java的文件代码如下: public interface IMyAidl extends android.os.IInterface { /** * Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.coder_f.aidlserver.IMyAidl { private static final java.lang.String DESCRIPTOR = "com.coder_f.aidlserver.IMyAidl"; /** * Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.coder_f.aidlserver.IMyAidl interface, * generating a proxy if needed. */ public static com.coder_f.aidlserver.IMyAidl asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.coder_f.aidlserver.IMyAidl))) { return ((com.coder_f.aidlserver.IMyAidl) iin); } return new com.coder_f.aidlserver.IMyAidl.Stub.Proxy(obj); } @Override public android.os.IBinder asBinder() { return this; } @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_add: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); int _arg1; _arg1 = data.readInt(); int _result = this.add(_arg0, _arg1); reply.writeNoException(); reply.writeInt(_result); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.coder_f.aidlserver.IMyAidl { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } @Override public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } @Override public int add(int arg1, int arg2) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(arg1); _data.writeInt(arg2); mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); } public int add(int arg1, int arg2) throws android.os.RemoteException; } 主要就是根据aidl文件自动生成了stub的内部类,这个内部类不仅继承了Binder还继承了父类。这里继承父类主要是为了能够获得回调add接口方法,stub类并没有去真正的实现add方法。 stub类结构很清楚里面只有3个方法加上1个内部类分别是: asInterface 根据传入的binder来判断当前是否是跨进程,如果跨进程则返回一个Proxy对象,如果不是跨进程则直接返回当前接口实现类(想当是调用本地接口); asBinder 返回当前binder对象,继承IInterface必须实现的方法(满足内部跨进程) onTransact Binder的方法当client端的Binder对象调用了transact方法时此方法会被回调 Proxy类 一个代理类,主要作用是配置Binder对象的transact方法(这个方法继承自IBinder)需要的参数以及调用transact方法。Proxy类也继承了我们自己定义的aidl接口,主要为了保证接口中的方法都有相对应transact去调用真正的server端方法(应为继承了接口,如果不是抽象类那就必须得去实现这些方法吧)。 这里还有一个特别的参数就是TRANSACTION_add这么一个常量,他是由一个常量+0构成的,这个常量其实就是0,这个常量主要来标记方法的如果有多个方法: //当前只有一个方法所以是+0,当更多的方法时每个方法都会对应一个数字。例如有两个时那就会如下 static final int TRANSACTION_xxx = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_yyy = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); ... 这些方法(类)现在有一个印象就可以,后面会详细的分析。 以上是一个aidl的完整结构,当然真正要使用还需要去有一个类来继承stub类并且实现最初aidl文件中定义的所有接口(注意stub类是一个抽象类,它继承了aidl的接口但却没有真正的去实现它,这里需要我们来实现)。当然这个java类也需要在client端实现一遍(也就是自动生成一遍)。 aidl流程 要分析aidl流程所以我先创建了一个Service(MyService),在里面创建了一个内部类MyAidlImpl来继承IMyAidl.Stub并且实现我们最初定义在aidl文件中一直未被实现的add方法。在Service的onBind方法中返回这个内部类的实例(因为Stub是继承了Binder类所以MyAidlImpl的实例也会是Binder类型),具体代码如下: Server端:MyService.java //MyService.java public class MyService extends Service { private MyAidlImpl myAidlImpl; public MyService() { } @Override public void onCreate() { super.onCreate(); myAidlImpl = new MyAidlImpl(); } @Override public IBinder onBind(Intent intent) { return myAidlImpl; } } class MyAidlImpl extends IMyAidl.Stub { @Override public int add(int arg1, int arg2) throws RemoteException { return arg1 + arg2; } } 接口的实现方法很简单,就是把传进来的两个参数加一下再返回回去。现在这个Service就相当于是一个Server端,来远程处理一些任务(这里就是arg1 + arg2)并且返回结果。 至于Client端代码就是最普通的一个Activity里面去绑定刚刚实现的Service,这里我为了保证是跨进程我重新创建了一个项目。(也可以在当前项目里面来做,只要在manifest文件中把Service的android:process设置为“:remote”就可以了,这样Service就不会和activity运行在一个进程中) Client端:MainActivity.java public class MainActivity extends AppCompatActivity { private static final String TAG = "AIDLClient"; private ServiceConnection serviceConnection; private IMyAidl myAidl; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); serviceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { myAidl = IMyAidl.Stub.asInterface(service); try { Log.d(TAG, "onServiceConnected: data from server = " + myAidl.add(123, 456)); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { myAidl = null; } }; bindService(new Intent("com.coder_f.aidlserver.MyService"), serviceConnection, BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); unbindService(serviceConnection); } } 根据上面代码我们现在看一下,首先是Client端来bindService,这里绑定成功以后就会返回一个Binder对象,这个对象就是Server端onBind的时候返回的,是MyAidlImpl的实例,通过IMyAidl.Stub.asInterface(service)方法来获得一个Proxy类的对象(这里考虑的是跨进程调用的情况所以返回的是proxy对象),然后我们调用了proxy对象里面的add方法,那我们就跟着去看一下根据aidl自动生成的java类中proxy的add方法里面具体是什么逻辑。 private static class Proxy implements com.coder_f.aidlserver.IMyAidl { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } @Override public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } @Override public int add(int arg1, int arg2) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(arg1); _data.writeInt(arg2); mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } } 这里的remote就是asInterfa方法中传入的Binder对象,通过这个Binder对象,接着调用了add方法。这里来仔细看看这个add方法的逻辑,总共就三步。 创建了两个Parcel对象(跨进程只能传递Parcel以及Binder类型的对象)_data用来存放参数,_reply用来存放返回值。这里传入的DESCRIPTOR是一个包名。这个DESCRIPTOR也起到标识的作用,只有transact和onTransact方法中parcel对象的一致时才能成功调用。这也是为什么我们要求Server端和Client端aidl存放目录结构一致的原因,不一致的话这个自动生成DESCRIPTOR也会不一样; 调用了Binder的transact方法,这个方法其实就是跨进程调用的核心,他的第一个参数是一个int值,用来告诉Server端(onTransact方法)我要调用的具体是哪个方法,这里Stub.TRANSACTION_add标志的就是add方法,第二个和第三个之前已经说了分别是参数和返回值,第四个是个标志位,当0的时候代表有返回值,当1的时候则代表没有返回值(此时就算你的方法真的有返回值_reply中也不会有结果) 读取_reply中返回的结果。 这里要注意的是当调用transact方法时当前线程会被挂起。此时如果这个方法运行在主线程时,而server端又因为各种原因或者方法本身就是耗时的导致不能及时返回结果就会使得ui线程卡住。而我上面Client端方法中myAidl.add(123,456)是放在了onServiceConnected方法里面,而onServiceConnected方法其实是运行在主线程的(具体可以看我之前bindservice流程分析文章中最后面的说明) 这里调用Binder的transact方法以后经过一系列的流程(这里具体什么流程没有仔细研究过,涉及到jni底层native的binder方法)最后会回调到Server端的onTransact方法。 好了那我们就看看自动给我们生成的java文件中onTransact方法的逻辑代码如下。 @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_add: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); int _arg1; _arg1 = data.readInt(); int _result = this.add(_arg0, _arg1); reply.writeNoException(); reply.writeInt(_result); return true; } } return super.onTransact(code, data, reply, flags); } 这里的onTransact方法的参数其实和transact方法的参数是一一对应的,第一个就是标志方法的code默认会有有一个INTERFACE_TRANSACTION用来验证之前说的DESCRIPTOR,另外一个就是TRANSACTION_add,这里我们接口中只有一个所以总共onTransact方法中只对这一个方法处理。 这个add方法和proxy类中add方法的结构很类似,就是从_data中取出(proxy.add是创建写入)参数调用真正add方法(在service中实现的add方法)然后把结果写入到reply(proxy.add是创建读取)中。注意这个方法有一个返回值,如果返回false则Client端会调用失败。 上面就是aidl的一整套流程。 总结: aidl其实就是利用Binder来实现跨进程调用。而这个系统根据.aidl文件生成的java文件就是对binder的transact方法进行封装。 onTransact方法是提供给server端用的,transact方法(内部类proxy封装了transact方法)和asInterface方法是给client端用的。系统自动生成不知道你要把哪个当做server端哪个当做client端所以就都生成了。 DESCRIPTION是根据aidl文件位置(包名)来生成的,DESCRIPTION是binder的唯一标识,这也解释了为什么要保证client端和server端.adil文件的包结构一样; aidl的transact的调用会导致当前线程挂起,因此如果Server端的方法耗时最好另起线程来调用transact方法; aidl通过Parcel来传递参数和返回值,因为binder只支持Binder对象和parcel对象的跨进程调用; Binder,IBinder,IInterface三个的关系。Binder是继承自IBinder对象的,IBinder是远程对象的基本接口。另外IBinder的主要API是transact(),与它对应另一方法是Binder.onTransact(),而IInterface主要为aidl服务,里面就一个方法——asBinder,用来获得当前binder对象(方便系统内部调用)。 最后说白了aidl的核心就是client调用binder的transact方法,server通过binder的onTransact方法了来执行相应的方法并返回。 本文转自 一点点征服 博客园博客,原文链接:http://www.cnblogs.com/ldq2016/p/8418908.html ,如需转载请自行联系原作者

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

【swift学习笔记】六.访facebook登录页面

代码最下边有下载地址。 做这个demo的主要心得就是自适应所有的屏幕,要先布局大的框架,再一步一步设置小的细节。 看一下效果 再看一下自动适应所有屏幕的效果: keyboard打开时整个frame上移一个keyboard的高度 override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. // btn loginBtn.layer.cornerRadius = 3 // text userText.delegate = self passwordText.delegate = self NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil) } func keyboardWillShow(notification: NSNotification) { if isMovied { return } isMovied = true if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() { UIView.animateWithDuration(0.25, animations: { self.view.frame.origin.y -= keyboardSize.height } ) } } func keyboardWillHide(notification: NSNotification) { isMovied = false if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() { UIView.animateWithDuration(0.25, animations: { self.view.frame.origin.y += keyboardSize.height }) } } 别的就没有什么技术点了,大家有时间下载代码看一下吧。 源代码:FaceBookLoginView.zip 本文转自lpxxn博客园博客,原文链接:http://www.cnblogs.com/li-peng/p/5584236.html,如需转载请自行联系原作者

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

Redis自学笔记 --Hash、List、Set类型简述

Hash类型 hset key field value 设置hash field为指定值,如果key不存在,则先创建。 hget key field 获取指定的hash field。 hmget key filed1....fieldN 获取全部指定的hash filed。 hmset key filed1 value1 ... filedN valueN 同时设置hash的多个field。 hincrby key field integer 将指定的hash filed加上给定值。 hexists key field 测试指定field是否存在。 hdel key field 删除指定的hash field。 hlen key 返回指定hash的field数量。 hkeys key 返回hash的所有field。 hvals key 返回hash的所有value。 hgetall 返回hash的所有filed和value。 List类型 lpush key string 在key对应list的头部添加字符串元素,返回1表示成功,0表示key存在且不是list类型。 rpush key string 在尾部添加。 llen key 返回key对应list的长度,key不存在返回0,如果key对应类型不是list返回错误。 lrange key start end 返回指定区间内的元素,下标从0开始,负值表示从后面计算,-1表示倒数第一个元素 ,key不存在返回空列表。 ltrim key start end 截取list,保留指定区间内元素,成功返回1,key不存在返回错误。 lset key index value 设置list中指定下标的元素值,成功返回1,key或者下标不存在返回错误。 lrem key count value 从key对应list中删除count个和value相同的元素。count为0时候删除全部。 lpop key 从list的头部删除元素,并返回删除元素。如果key对应list不存在或者是空返回nil,如果key对应值不是list返回错误。 rpop 从尾部删除。 blpop key1...keyN timeout 从左到右扫描返回对第一个非空list进行lpop操作并返回,比如blpop list1 list2 list3,如果list不存在list2,list3都是非空则对list2做lpop并返回从list2中删除的元素。如果所有的list都是空或不存在,则会阻塞timeout秒,timeout为0表示一直阻塞。如果超时发生,则返回nil。 rpoplpush srckey destkey 从srckey对应list的尾部移除元素并添加到destkey对应list的头部,最后返回被移除的元素值,整个操作是原子的.如果srckey是空或者不存在返回nil。 Set类型 sadd key member 添加一个string元素到,key对应的set集合中,成功返回1,如果元素以及在集合中返回0,key对应的set不存在返回错误。 srem key member 从key对应set中移除给定元素,成功返回1,如果member在集合中不存在或者key不存在返回0,如果key对应的不是set类型的值返回错误。 spop key 删除并返回key对应set中随机的一个元素,如果set是空或者key不存在返回nil。 srandmember key 同spop,随机取set中的一个元素,但是不删除元素smove srckey dstkey member 从srckey对应set中移除member并添加到dstkey对应set中,整个操作是原子的。成功返回1,如果member在srckey中不存在返回0,如果key不是set类型返回错误。 scard key 返回set的元素个数,如果set是空或者key不存在返回0。 sismember key member 判断member是否在set中,存在返回1,0表示不存在或者key不存在。 sinter key1 key2...keyN 返回所有给定key的交集。 sunion key1 key2...keyN 返回所有给定key的并集。 sunionstore dstkey key1...keyN 同sunion,并同时保存并集到dstkey下。 sdiff key1 key2...keyN 返回所有给定key的差集。 sdiffstore dstkey key1...keyN 同sdiff,并同时保存差集到dstkey下。 smembers key 返回key对应set的所有元素,结果是无序的。 本文转自我爱物联网博客园博客,原文链接:http://www.cnblogs.com/yydcdut/p/3601425.html,如需转载请自行联系原作者

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

Redis自学笔记–Zset类型及管理简述

Zset类型 ZADD key score member 添加指定成员到有序集合中,如果目标存在则更新score(分值,排序用)。 ZREM key member 从有序集合删除指定成员。 ZINCRBY key increment member 如果成员存在则将其增加_increment_,否则将设置一个score为_increment_的成员。 ZRANGE key start end 返回升序排序后的指定范围的成员。 ZREVRANGE key start end 返回降序排序后的指定范围的成员。 ZRANGEBYSCORE key min max 返回所有符合score >= min和score <= max的成员 ZCARD key 返回有序集合的元素数量。 ZSCORE key element 返回指定成员的SCORE值 ZREMRANGEBYSCORE key min max 删除符合 score >= min 和 score <= max 条件的所有成员。 排序 SORT key BY pattern LIMIT start end GET pattern ASC|DESC ALPHA 按照指定模式排序集合或List。 SORT mylist DESC 降序。 SORT mylist LIMIT 0 10 从序号0开始,取10条。 SORT mylist LIMIT 0 10 ALPHA DESC 按首字符排序。 SORT mylist BY xxx STORE resultkey 将返回的结果存放于resultkey序列(List)。 持久控制 SAVE 同步保存数据到磁盘。 BGSAVE 异步保存数据到磁盘。 LASTSAVE 返回上次成功保存到磁盘的Unix时间戳。 SHUTDOWN 同步保存到服务器并关闭 Redis 服务器(SAVE+QUIT)。 BGREWRITEAOF 当日志文件过长时重写日志文件。 本文转自我爱物联网博客园博客,原文链接:http://www.cnblogs.com/yydcdut/p/3607423.html,如需转载请自行联系原作者

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

《我们应当怎样做需求分析》阅读笔记

原文链接(转载请注明出处):如何做好需求分析 这学期的《软件需求与分析》课可以说是软件工程专业比较重要的一门课。如何做好软件需求分析就等同于如何做好一个项目。客户对需求一改再改,如果我们只是一味的去抱怨,而不去思考客户对需求更改的原因是什么,不了解业务,那我们做出来的产品肯定得不到客户的认可。 通过阅读我们应当怎样做需求分析这一系列的文章,我总结出来做好软件需求分析需求从这几方面入手。首先是做需求调研,就是采集需求这个阶段,在这个阶段其实是一个反复循环的过程:需求捕获——需求整理——需求验证——再需求捕获......;在每一次做完需求调研后就要做一次需求分析,并且等到下一次去做需求调研时,我们应该首先将上一次的需求分析结果与客户进行确认。然而在每次的需求分析阶段其实也是一个比较复杂的分析过程,我们需求画大量的UML图(例如用例图),对角色功能进行分析,对业务流程进行分析等。最后我们还需要做好需求确认工作,写好需求规格说明书然后评审签字确认。 经过阅读与思考,我认为以下内容我们需要掌握的: 许多需求分析工作都是从需求调研开始的,需求调研工作既是一份技术活更是一份体力活。它要求我们具有一种理解能力,设计能力,更要求我们具有一种与人交往与沟通的能力。 (1)开研讨会捕获需求 我们需求获得客户的需求,必须要了解业务,要想了解业务,一是可以学习相关的知识,最有效的方法就是开业务研讨会,需求研讨会等,在会上我们不但可以更好的和客户交流整个流程,还可以讨论一些比较细节的地方。但是在组织研讨会的同时必须注意两点:有效抑制个性化差异,分模块组织专项研讨会。 (2)学会需求捕获 整个需求分析过程是一个迭代的过程,在需求捕获这个阶段,往往不是考验我们的专业知识,而是涉及人际交往,沟通理解等方面。如果学会了如何捕获客户的需求,那我们的项目成功的概率就会得到质的飞跃。在学会捕获需求之前我们要清楚的认识到软件需求不仅仅是客户嘴里说出来的。还有两类需求需要我们自己去发现:一是客户嘴里没有说的需求,二是客户压根没有想到的需求。知道这些后如果我们不能更好的处理与客户交流的方式,那一切都是百搭,在与客户讨论需求过程中,态度决定一切,既不能让自己处于被动状态,对客户提出的所有需求都记下来然后不加分析地给开发人员;也不能盲目主动,不分析客户的需求,按照自己的想法来,最后交付的时候客户说这不是自己想要的软件。最明智的做法是先跟客户谈业务,先谈论业务流程,在此阶段我们还要多问为什么,这样可以让我们深入地了解这些领域的知识,站在客户的角度去思考问题,进而能够深入理解客户为什么要提出他们的那些业务需求。 (3)功能角色分析 当我们经过一番忙碌,将需求中的第一手资料从调研现场捕获回来后我们就要对需求进行行之有效的分析,而这种分析首先应当从功能角色分析开始,所谓的功能角色分析就是从一个外部用户的视角分析整个软件系统能够提供的功能,以及这些功能到底提供给那些角色使用。而对一个系统进行功能和角色方面的梳理和分析,可以采用画用例图的方法。运用这种方法对业务需求进行分析、抽象、整理、提炼进而形成用例模型。 我们在画用例图的过程中不能以一个开发者的角色来绘制,许多描述信息也绝不能按照开发者的思维和习惯去写,而是要贴近客户,因为用例图的视角是用户。所以描述信息应该迎合用户平时的习惯用语。 (4)业务流程分析 做好角色分析后,最重要的一步就是要做好业务流程分析。文章作者在这一章中用了许多例子来说明问题,在分析ERP对企业流程改进的例子中,作者分析出来的思路是清除低效环节、简化业务瓶颈、整合可用资源,以及将繁琐任务自动化。计算机信息化管理并不是万能的,它并不能代替现实世界中的所有工作。因此我们进行业务流程分析,就是要分析业务流程中哪些是需要信息化管理的,而哪些则不需要。另外,业务流程分析的另一个重要的分析内容就是流程差异化分析。不同的领导有不同的思路,不同的单位有不同的情况。因此,我们在进行流程分析的时候,常常面临流程差异化的问题。 (5)业务领域分析 在需求分析工作中,最后一项分析工作就是业务领域分析啦。业务领域分析,就是对需求分析中涉及到的业务实体,以及它们相互之间关联关系的分析。什么叫业务领域,就是客户所在的知识领域,譬如财务人员所在的是财务领域,税务人员所在的是税务领域。不同的知识领域拥有各自不同的领域知识,需求分析人员就应该通过客户中的领域专家去学习这些知识、掌握这些要点,并最终体现在我们的需求分析中。我们进行业务领域分析,就是通过与用户进行交流,掌握领域知识,然后绘制成业务领域模型,去指导我们软件开发的过程。其中,我们可以通过两种分析方法一步步进行分析:原文分析法与领域驱动设计。 (6)挖掘非功能需求 需求分析人员最容易忽略的部分就是非功能需求。非功能需求更加靠近的是技术,是设计,是实现,是架构师关注的内容,是需求人员最不擅长的方面,这也是非功能需求为什么常常被忽略的重要原因。正因为如此,架构师应当尽早参与到项目中,参与到需求分析中,尽早分析需求的技术可行性,尽早考虑性能、安全性、可靠性等非功能需求,尽早开始架构设计。 非功能需求可以简单归纳为“URPS+”,即可用性(Usability)、可靠性(Reliability)、性能(Performance)、可支持性(Supportability)以及其它(+)。,将我们分析出来的功能中所潜在的、特殊的非功能需求挖掘出来,提前进行分析设计,对于可行性不高的应及时与客户商讨,才能有效地避免日后存在的这些方面的风险。 (7)做好需求列表 需求列表,又称之为需求跟踪表,是最原始的、用户对业务需求的描述。它不掺杂任何需求分析人员对业务需求的分析与设计,而是以简短扼要的语句,以业务人员的口吻表述的,今后要开发的这个系统应当提供给他们的各项功能。 首先,需求列表不掺杂我们对业务需求的任何分析与设计,这是需求列表的核心,也是它存在的意义。其次,需求列表应当是站在业务人员的视角,对业务需求的简明扼要的描述。在需求列表中应当剔除那些客户对系统设计的内容。最后,需求列表也不是一步到位的,而是经过由粗到细逐渐整理形成的。 (8)写好需求规格说明书 我们之所以要编写自己的需求规格说明书,就是要本着实事求是、切实可行的态度,去描述用户的业务需求。那些不可行的需求被摒弃,或者换成更加可行的解决方案。这就是需求规格说明书的重要作用。领域驱动设计所提倡的就是要让用户、需求分析员、开发人员站在一个平台,使用统一的语言(一种混合语言),来表达大家都清楚明白的概念 。我们不能拿着用户编写的原始需求就开始开发,只有依据自己的公司、项目、特别是需求分析中采用的方法,写出一份既是从用户角度描述的系统业务需求说明书,又是一份指导开发人员完成设计与开发的技术性文档。 图示:

资源下载

更多资源
腾讯云软件源

腾讯云软件源

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

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文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

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

用户登录
用户注册