首页 文章 精选 留言 我的

精选列表

搜索[人员工作量视图],共10003篇文章
优秀的个人博客,低调大师

运维人员的解放----Docker快速部署

Docker是一个用了一种新颖方式实现的超轻量虚拟机,在实现的原理和应用上还是和VM有巨大差别,专业的叫法是应用容器(Application Container)。(我个人还是喜欢称虚拟机) Docker应用容器相对于VM有以下几个优点: 启动速度快,容器通常在一秒内可以启动,而VM通常要更久 资源利用率高,一台普通PC可以跑上千个容器,你跑上千个VM试试 性能开销小,VM通常需要额外的CPU和内存来完成OS的功能,这一部分占据了额外的资源 因为VM的Hypervisor需要实现对硬件的虚拟化,并且还要搭载自己的操作系统,自然在启动速度和资源利用率以及性能上有比较大的开销。 个人体会较深的两处优点: 1、快速部署,传统的部署模式是:安装(包管理工具或者源码包编译)->配置->运行;Docker的部署模式是:复制->运行。 2、可以保证线上与测试环境一致,计划以后上线就直接复制测试使用的docker容器) 什么是docker? http://oilbeater.com/docker/2014/06/29/what-is-docker.html 为什么你应该关注docker? http://oilbeater.com/docker/2014/06/13/why-you-should-care-about-docker.html 1、docker安装 debian7安装docker 参考地址:http://www.webmaster.me/server/installing-docker-on-debian-wheezy-in-60-seconds.html echo deb http://get.docker.io/ubuntu docker main | sudo tee/etc/apt/sources.list.d/docker.list sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9 sudo apt-get update sudo apt-get install -y lxc-docker #四行命令,Docker就安装好了。下面创建一个ubuntu虚拟系统: docker pull ubuntu #此处是从官网拉取名为ubuntu的image,也可手动在https://index.docker.io上搜索想要的镜像。 docker run -i -t ubuntu /bin/bash #创建一个容器,-t是临时终端。 ubuntu12.04、windows、macOS安装docker 参考docker中文文档http://www.widuu.com/docker/ 2、docker使用过程实践 2.1在测试机启动容器,安装ssh docker run -i -t ubuntu /bin/bash #此方式运行的容器,退出后容器就会关闭。 apt-get install openssh-server #安装ssh #需要修改/etc/sshd/sshd_config文件中内容 PermitRootLogin yes UsePAM no 2.2启动ssh,容器以后台方式运行 docker run -d -p 50001:22 <镜像id> /usr/sbin/sshd-D #容器id可通过docker ps -a查看,最上面的为最新的。 2.3通过ssh连接到容器安装软件 sshroot@127.0.0.1-p 50001 #连上后想装什么就装什么,可使用exit退出容器,但后台还会运行。 2.4服务安装完成后,停止容器。 docker stop <容器id> #停止运行的容器 2.5把容器提交生成最新的镜像 docker commit <容器id> debian02#把这个容器提交生成新的debian02镜像(该镜像是原始镜像与容器的整合) 2.6打包镜像 docker save debian02 >/root/debian02.tar #debian02镜像打包 2.7在另外的机器上导入镜像 docker load < debian02.tar #导入镜像 docker images #查看存在的镜像 2.8启动容器 docker run -h="redis-test" --name redis-test -d -p 51000:22 -p51001:3306 -p 51003:6379 -p 51004:6381-p 51005:80 -p 51006:8000 -p 51007:8888debian02 /etc/rc.local #此处是我测试机器启动命令,指定主机名与端口映射。 #启动后,后面又装了程序,开机自启动命令可放在/etc/rc.local文件中。 docker容器迁移简单方便,可以任意的拷贝部署,以后再也不怕新部署环境了,一堆依赖装的想死有木有。 3、关于docker容器的端口映射 由于docker容器的IP地址每次启动都会变,所以不适用于手动添加端口映射(难道每次重启都来查看容器的IP么?),所以需要每次启动容器时由docker程序自动添加NAT规则,前期尽可能的把需要映射的端口在创建容器时配置好,如下: docker run -h="activemq" --name activemq -d -p 51000:22 -p 51001:3306-p 51003:6379 -p 51004:6381 -p 51005:80-p 51006:8000 -p 51007:8888 debian/base/etc/rc.local #此处我把mysql,redis,nginx,ssh都进行了映射。 后续对于docker容器的管理,记住容器的名称,如上述名称是activemq,则使用docker stop,start来控制容器进程。 dockerstop activemq docker start activemq 当然,也可以不让docker每次启动容器修改容器的IP地址,参考如下: docker网络配置:http://www.open-open.com/lib/view/open1404896485747.html 4、关于docker容器的多程序开机自动运行 docker容器每次启动时,开机自启动的命令都要在启动容器前指定。如docker run -I -t debian /bin/bash命令,只会运行/bin/bash程序,其它的程序都不会运行,对于要跑多个程序的容器特别纠结。 多程序开机自动运行方法: 可把前面所说的启动命令换成dockerrun -I -t debian /etc/rc.local,在容器中把所有需要开机自的启动命令放在/etc/rc.local中,就可以达到多程序开机自启动了。 后台运行则是:docker run -d -p 50001:22 debian /etc/rc.local。注意:run命令是创建一个新的容器,如果要启动一个曾经运行过的容器,则用命令docker ps -a中找对应的容器ID,然后使用docker start <容器ID>即可。 5、关于docker容器和镜像的关系 无论容器里做什么操作,写文件,删文件。该容器的基本镜像都不会有任何改变。 这是因为Docker从父镜像建立增量镜像,只存储每个容器的更改。因此,如果你有一个300MB的父镜像,如果你在容器中安装了50MB的额外应用或服务,你的容器只有50MB,父镜像还是300MB。 但是可以使用Dockfile或commit命令来,把增量镜像和父镜像一起生成一个新的镜像。 commit使用: docker commit <容器id> <新镜像名称> Dockfile使用: root@yangrong:/data# cat Dockerfile FROMubuntu/testa #这是基础镜像 CMD["/root/start.sh"] #这是启动命令 root@yangrong:/data# docker build -t <新镜像名> ./ 关于Dockfile更多参数参考地址: http://www.tuicool.com/articles/FRvAbe http://www.colorscode.net/2014/01/04/howto-build-image-with-automatic-startup-ssh-service-from-dockerfile/ 6、docker参数详解 docker useage of docker -D默认false允许调试模式(debugmode) -H默认是unix:///var/run/docker.sock tcp://[host[:port]]来绑定或者unix://[/path/to/socket]来使用(二进制文件的时候),当主机ip host=[0.0.0.0],(端口)port=[4243]或者path=[/var/run/docker.sock]是缺省值,做为默认值来使用 -api-enable-cors默认flase允许CORS header远程api -b默认是空,附加在已存在的网桥上,如果是用'none'参数,就禁用了容器的网络 -bip默认是空,使用提供的CIDR(ClasslessInter-Domain Routing-无类型域间选路)标记地址动态创建网桥(dcoker0),和-b参数冲突 -d默认false允许进程模式(daemonmode) -dns默认是空,使docker使用指定的DNS服务器 -g默认是"/var/lib/docker":作为docker使用的根路径 -icc默认true,允许inter-container来通信 -ip默认"0.0.0.0":绑定容器端口的默认Ip地址 -iptables默认true禁用docker添加iptables规则 -mtu默认1500 :设置容器网络传输的最大单元(mtu) -p默认是/var/run/docker.pid进程pid使用的文件路径 -r默认是true重启之前运行的容器 -s默认是空,这个是docker运行是使用一个指定的存储驱动器 -v默认false打印版本信息和退出 7、docker run命令详解 Usage: docker run [OPTIONS] IMAGE[:TAG] [COMMAND] [ARG...] Run a command in a new container -a=map[]:附加标准输入、输出或者错误输出 -c=0:共享CPU格式(相对重要) -cidfile="":将容器的ID标识写入文件 -d=false:分离模式,在后台运行容器,并且打印出容器ID -e=[]:设置环境变量 -h="":容器的主机名称 -i=false:保持输入流开放即使没有附加输入流 -privileged=false:给容器扩展的权限 -m="":内存限制(格式:<number><optional unit>, unit单位= b, k, m or g) -n=true:允许镜像使用网络 -p=[]:匹配镜像内的网络端口号 -rm=false:当容器退出时自动删除容器(不能跟-d一起使用) -t=false:分配一个伪造的终端输入 -u="":用户名或者ID -dns=[]:自定义容器的DNS服务器 -v=[]:创建一个挂载绑定:[host-dir]:[container-dir]:[rw|ro].如果容器目录丢失,docker会创建一个新的卷 -volumes-from="":挂载容器所有的卷 -entrypoint="":覆盖镜像设置默认的入口点 -w="":工作目录内的容器 -lxc-conf=[]:添加自定义-lxc-conf="lxc.cgroup.cpuset.cpus = 0,1" -sig-proxy=true:代理接收所有进程信号(even in non-tty mode) -expose=[]:让你主机没有开放的端口 -link="":连接到另一个容器(name:alias) -name="":分配容器的名称,如果没有指定就会随机生成一个 -P=false: Publish all exposed ports to thehost interfaces公布所有显示的端口主机接口 8、docker常用命令总结 docker pull <镜像名:tag> #从官网拉取镜像 docker search <镜像名> #搜索在线可用镜像名 8.1查询容器、镜像、日志 docker top <container> #显示容器内运行的进程 docker images #查询所有的镜像,默认是最近创建的排在最上。 docker ps#查看正在运行的容器 docker ps -l #查看最后退出的容器的ID docker ps -a #查看所有的容器,包括退出的。 docker logs {容器ID|容器名称} #查询某个容器的所有操作记录。 docker logs -f {容器ID|容器名称} #实时查看容易的操作记录。 8.2删除容器与镜像 docker rm$(docker ps -a -q)#删除所有容器 docker rm <容器名or ID> #删除单个容器 docker rmi <ID> #删除单个镜像 docker rmi$(docker images | grep none | awk '{print $3}' | sort -r)#删除所有镜像 8.3启动停止容器 docker stop <容器名or ID> #停止某个容器 docker start <容器名or ID> #启动某个容器 docker kill <容器名or ID> #杀掉某个容器 8.4容器迁器 docker export <CONTAINER ID> > /home/export.tar #导出 cat /home/export.tar | sudo docker import - busybox-1-export:latest #导入export.tar文件 docker save debian> /home/save.tar #将debian容器打包 docker load< /home/save.tar #在另一台服务器上加载打包文件 save和export的对比参考地址: http://www.fanli7.net/a/bianchengyuyan/C__/20140423/452256.html 8.5运行一个新容器 #运行一个新容器,同时为它命名、端口映射。以debian02镜像为例 docker run -h="redis-test" --name redis-test -d -p 51000:22 -p51001:3306 -p 51003:6379 -p 51004:6381-p 51005:80 -p 51006:8000 -p 51007:8888debian02 /etc/rc.local #从container中拷贝文件,当container已经关闭后,在里面的文件还可以拷贝出来。 sudo docker cp 7bb0e258aefe:/etc/debian_version . #把容器中的/etc/debian_version拷贝到当前目录下。 8.6 docker Dockfile镜像制作 root@yangrong:/data# cat Dockerfile FROM ubuntu/testa #这是基础镜像 CMD ["/root/start.sh"]#这是启动命令 root@yangrong:/data# docker build -t <新镜像名> ./ #生成新的镜像 Dockfile更多参数参考: http://www.tuicool.com/articles/FRvAbe http://www.colorscode.net/2014/01/04/howto-build-image-with-automatic-startup-ssh-service-from-dockerfile/ <完> 如果要把docker应用到生产环境,就要好好的规划一下,可参考下面文章: docker容器端口IP规划及端口动态扩容 http://yangrong.blog.51cto.com/6945369/1582184 本文转自杨云1028 51CTO博客,原文链接:http://blog.51cto.com/yangrong/1551327,如需转载请自行联系原作者

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

谷歌首席工程师称 Claude Code 仅用 1 小时便完成团队一年的工作量

Google 负责 Gemini API 的首席工程师 Jaana Dogan 在社交平台 X 上公开盛赞 Anthropic 推出的新工具Claude Code。她透露,自己曾向该工具描述了一个困扰团队一年的复杂难题——分布式代理编排系统,结果 Claude Code 仅用1小时就生成了可运行的系统框架。 尽管 Google 团队此前曾尝试过多种方案,但始终未能达成共识。令人意外的是,Dogan 提供给 Claude Code 的提示词仅有短短三段话。虽然她坦言生成的代码并非完美,仍需后续打磨,但其完成度已足以与团队耗时一年打磨出的成果相媲美。 Dogan 回顾道,2022年的 AI 只能补全单行代码,而到了2025年,AI 已经能够重构甚至从零创建整个代码库。这种超越预期的进化速度,让原本认为“自动化编程还需五年才能普及”的专家们纷纷改变了看法。 目前,出于安全考虑,Google 内部仅允许在开源项目中使用Claude Code。对此,Dogan 表现出积极的竞争心态,表示这种行业内的相互激励将促使 Google 的 Gemini 团队更加努力地优化自身模型。

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

Android减少布局层次--有关Activity根视图DecorView的思考

1Android应用图层 一直觉得有关DecorView还是有些问题没有搞清楚,今天在看了一点有关SurfaceFlinger的内容以后,顿时突发奇想,想到之前的问题,之前的思考是: 虽然可以将DecorView作为Activity布局的父View,也就是只存在 DecorView---->ActivityLayout两层,但是经过试验还是会存在Title Bar,或者说是现在的Action Bar,尝试如下: [html] view plain copy protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); ViewGroupgroup=(ViewGroup)getWindow().getDecorView(); LayoutInflater.from(this).inflate(R.layout.activity_main,group,true); ViewServer.get(this).addWindow(this); } 一个简单的APP运行出来看到的View结构图就是下面这样: 图中左右两边相同颜色的区域是对应的,下面是详细的View tree结构图: 可以看到即使像上面那样写,在DecorView下面有3个子View,放大看一下: DecorView里面包含: (1)ActionBarOverklayLayout :ActionBar带来的一个布局,遍布了除了第三层最上端View的所有区域 (2)RelativeLayout : Activity的Layout(上述的activity_main布局) (3)View : 屏幕最上端状态栏的背景 可以看到activity_main中的根布局RelativeLayout和ActionBarOverklayLayout并列的,虽然减少了Activity中布局的层次,但是还是存在ActionBarOverklayLayout 这个我们实际上可能不需要的布局。 2 改进--减少层次 上面的改法有很多的问题,首先DecorView是一个FrameLayout,里面的所有的内容简单的叠在了一起,上面的RelativeLayout里面其实放了一个TextVIew,显示“Hello world”,但是都被其余层重叠了,所以看不到(仔细看勉强能看到),顺理成章想到DecorView作为一个Viewgroup,自然能够进行View的add和remove操作,于是想把其余的都remove删掉,不就只剩下Activity的Layout,于是改了一下代码: [html] view plain copy protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); ViewGroupgroup=(ViewGroup)getWindow().getDecorView(); group.removeAllViews(); LayoutInflater.from(this).inflate(R.layout.activity_main,group,true); ViewServer.get(this).addWindow(this); } 结果崩溃了,信息如下: 看信息好像是和ActionBar有关,但是还是没有什么头绪,于是逐行加log看看到底是在onCreate的哪一行出现这样的问题,其实看上面的崩溃信息的调用栈就知道和onCreate没有关系,应该是在onCreate的后面哪一步调用的时候出现了问题,但是还是尝试了一下: [html] view plain copy protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); System.out.println("onCreate0"); ViewGroupgroup=(ViewGroup)getWindow().getDecorView(); System.out.println("onCreate1"); group.removeAllViews(); System.out.println("onCreate2"); LayoutInflater.from(this).inflate(R.layout.activity_main,group,true); System.out.println("onCreate3"); ViewServer.get(this).addWindow(this); System.out.println("onCreateover"); } 运行以后结果如下: onCreate已经完整调用结束,但是比较常规使用方法,就是少了一个setContentView函数,于是先看一下getWindow().getDecorView(),根据前面的学习知道这里的getWindow()返回的是一个PhoneWindow对象,于是看一下PhoneWindow.getDecorView(): [html] view plain copy publicfinalViewgetDecorView(){ if(mDecor==null){ installDecor(); } returnmDecor; } 这里就是调用installDecor(),这个函数会调用PhoneWindow.generateDecor()和PhoneWindow.generateLayout(DecorView)函数分别创建一个DecorView对象、为DecorView加载一个系统布局,再看一下Activity.setContentView函数: [html] view plain copy publicvoidsetContentView(intlayoutResID){ getWindow().setContentView(layoutResID); initWindowDecorActionBar(); } 先看一下这里的getWindow().setContentView(layoutResID)函数,同样这里的getWindow()返回的是一个PhoneWindow对象,看 PhoneWindow.setContentView: [html] view plain copy publicvoidsetContentView(intlayoutResID){ //Note:FEATURE_CONTENT_TRANSITIONSmaybesetintheprocessofinstallingthewindow //decor,whenthemeattributesandthelikearecrystalized.Donotcheckthefeature //beforethishappens. if(mContentParent==null){ installDecor(); }elseif(!hasFeature(FEATURE_CONTENT_TRANSITIONS)){ //FEATURE_CONTENT_TRANSITIONS这个属性以后可能会用到, //这里先标记一下,注意看上面的注释 mContentParent.removeAllViews(); } if(hasFeature(FEATURE_CONTENT_TRANSITIONS)){ finalScenenewScene= Scene.getSceneForLayout(mContentParent,layoutResID,getContext()); transitionTo(newScene); }else{ mLayoutInflater.inflate(layoutResID,mContentParent); } finalCallbackcb=getCallback(); if(cb!=null&&!isDestroyed()){ cb.onContentChanged(); } } 里面没有什么特别的流程,基本上也就只有installDecor()和实例化布局对象这两个调用,这里的installDecor调用和上面的效果完全是一样的,所以基本上可以排除问题不在这里。 再往回看,Acyivity.setContentView函数除了调用了PhoneWindow.setContentView以外还调用了Acyivity.initWindowDecorActionBar函数,看函数名称这个函数调用好像是和ActionBar有关系的,刚刚好刚才的问题也是和ActionBar有关系的,问题应该就是在这里,看一下Acyivity.initWindowDecorActionBar: 先看注释:创建一个新的ActionBar对象,定位和实例化ActionBar对应的View,并用这个View来初始化ActionBar对象,最后将ActionBar对象的引用存储在mActionBar中。同样这里的Window是一个PhoneWindow,于是再看一下下面的几个测试条件: (1)isChild(): 这个很简单就是判断当前的Activity有没有Parent,这个目前还没有遇到Activity有Parent,所以这一个应该是false,这个直接在Acticity.onCreate里面就可以测试 (2)window.hasFeature(Window.FEATURE_ACTION_BAR):判断当前的Activity有没有指定FEATURE_ACTION_BAR这个Feature,后面会再细说到这个,一般情况不做设置,这一个是true (3)mActionBar: 一开始自然是null 到这里基本上已经可以解决这个问题了,只要不创建这个WindowDecorActionBar,就不会出现与ActionBar有关的问题,只要让上面的三个判断的其中之一失效就可以直接return了,也就不会创建WindowDecorActionBar对象了,比较一下最合适的应该是window.hasFeature(Window.FEATURE_ACTION_BAR)这个判断,那现在要做的就是要让window.hasFeature(Window.FEATURE_ACTION_BAR)返回false即可,先分析一下这个Window.FEATURE_*****它的值是什么?先看一下Window.Java: [html] view plain copy /**Flagforthe"optionspanel"feature.Thisisenabledbydefault.*/ publicstaticfinalintFEATURE_OPTIONS_PANEL=0; /**Flagforthe"notitle"feature,turningoffthetitleatthetopofthescreen.*/ publicstaticfinalintFEATURE_NO_TITLE=1; /**Flagfortheprogressindicatorfeature*/ publicstaticfinalintFEATURE_PROGRESS=2; /**Flagforhavinganiconontheleftsideofthetitlebar*/ publicstaticfinalintFEATURE_LEFT_ICON=3; /**Flagforhavinganiconontherightsideofthetitlebar*/ publicstaticfinalintFEATURE_RIGHT_ICON=4; /**Flagforindeterminateprogress*/ publicstaticfinalintFEATURE_INDETERMINATE_PROGRESS=5; /**Flagforthecontextmenu.Thisisenabledbydefault.*/ publicstaticfinalintFEATURE_CONTEXT_MENU=6; /**Flagforcustomtitle.Youcannotcombinethisfeaturewithothertitlefeatures.*/ publicstaticfinalintFEATURE_CUSTOM_TITLE=7; /**FlagforenablingtheActionBar.Thisisenabledbydefaultforsomedevices.TheActionBarreplacesthetitlebar *andprovidesanalternatelocationforanon-screenmenubuttononsomedevices.*/ publicstaticfinalintFEATURE_ACTION_BAR=8; /** *FlagforrequestinganActionBarthatoverlayswindowcontent. *NormallyanActionBarwillsitinthespaceabovewindowcontent,butifthis *featureisrequestedalongwith{@link#FEATURE_ACTION_BAR}itwillbelayeredover *thewindowcontentitself.Thisisusefulifyouwouldlikeyourapptohavemorecontrol *overhowtheActionBarisdisplayed,suchaslettingapplicationcontentscrollbeneath *anActionBarwithatransparentbackgroundorotherwisedisplayingatransparent/translucent *ActionBaroverapplicationcontent. */ [html] view plain copy publicstaticfinalintFEATURE_ACTION_BAR_OVERLAY=9; publicstaticfinalintFEATURE_ACTION_MODE_OVERLAY=10; publicstaticfinalintFEATURE_SWIPE_TO_DISMISS=11; publicstaticfinalintFEATURE_CONTENT_TRANSITIONS=12; publicstaticfinalintFEATURE_ACTIVITY_TRANSITIONS=13; 目前一共是有13个FEATURE_**,各个FEATURE_**的作用可以在用到的时候看一下注释,这里面有2点很重要: (1)通过Window.getFeatures函数可知,实际上所有的FEATURE_**最终会集中在mFeatures这个变量里面; (2)再看下面的hasFeature函数,里面用的是位运算判断某一位是否为1,所以上述的FEATURE_**定义的值实际上是移位运算时候的位移量; [html] view plain copy publicbooleanhasFeature(intfeature){ return(getFeatures()&(1<<feature))!=0; } 在Activity中获取Activity对应的Window的mFeatures变量的值,也就是PhoneWindow的mFeatures值,但是这个值定义在Window里面,下面利用反射: [html] view plain copy intgetFeature(){ Stringname="android.view.Window"; try{ Fieldfield=Class.forName(name).getDeclaredField("mFeatures"); field.setAccessible(true); returnfield.getInt(getWindow()); }catch(Exceptione){ e.printStackTrace(); } return-1; } 这样就可以获取Window的mFeatures值了。找到了问题的原因,也找到了解决的办法,下面分析该怎么写代码。把上面的异常信息在分析一下,然后总结一下: 问题:Activity里面所有默认的创建的ActionBar的操作都是从initWindowDecorActionBar里面开始的,看上面的异常信息问题就是如何让initWindowDecorActionBar函数里面的 window.hasFeature(Window.FEATURE_ACTION_BAR)判断返回false; 常见有两种方法: 方法一: 调用一下requestWindowFeature(Window.FEATURE_NO_TITLE)就行了,为什么是这样?看一下Activity.requestWindowFeature: 然后跳转到PhoneWindow.requestWindowFeature,列出主要的部分: [html] view plain copy @Override publicbooleanrequestFeature(intfeatureId){ finalintfeatures=getFeatures();//获取mFeatures finalintnewFeatures=features|(1<<featureId); if((newFeatures&(1<<FEATURE_CUSTOM_TITLE))!=0&&(newFeatures&~CUSTOM_TITLE_COMPATIBLE_FEATURES)!=0){ thrownewAndroidRuntimeException("Youcannotcombinecustomtitleswithothertitlefeatures"); } /* 1(features&(1<<FEATURE_NO_TITLE))!=0:当前没有title 2(features&(1<<FEATURE_NO_TITLE))!=0 &&featureId==FEATURE_ACTION_BAR: 当前没有title,这时候指定ACTION_BAR没有任何用处 */ if((features&(1<<FEATURE_NO_TITLE))!=0&&featureId==FEATURE_ACTION_BAR){ returnfalse;//Ignore.Notitledominates. }/* 1(features&(1<<FEATURE_ACTION_BAR))!=0:当前有ACTION_BAR 2(features&(1<<FEATURE_ACTION_BAR))!=0 &&featureId==FEATURE_NO_TITLE: 当前有ACTION_BAR,这时候指定NO_TITLE会去除ACTION_BAR */ if((features&(1<<FEATURE_ACTION_BAR))!=0 &&featureId==FEATURE_NO_TITLE){ removeFeature(FEATURE_ACTION_BAR); } returnsuper.requestFeature(featureId); } 看上面的彩色部分,当原来指定了FEATURE_ACTION_BAR,并且当前指定FEATURE_NO_TITLE的话,就会从当前的mFeatures中的FEATURE_ACTION_BAR标志位去掉,所以下次调用到initWindowDecorActionBar来初始化ActionBar的时候都不会创建ActionBar。 方法二: 利用Theme主题,上网一搜一大把,这些主题可能满足不了我们的需求,有时候不能单单的为了一个配置项去设置一个完全没有关系的Theme,可以通过查找Theme中关于属性值的设置,然后加到自己的定义的Theme里面就可以了,下面的这些Theme,他们的关键配置属性都能在sdk里面找到,路径在: android sdk根路径\platforms\android-xx\data\res\values [html] view plain copy android:theme="@android:style/Theme.Dialog"将一个Activity显示为能话框模式 android:theme="@android:style/Theme.NoTitleBar"不显示应用程序标题栏 android:theme="@android:style/Theme.NoTitleBar.Fullscreen"不显示应用程序标题栏,并全屏 android:theme="Theme.Light"背景为白色 android:theme="Theme.Light.NoTitleBar"白色背景并无标题栏 android:theme="Theme.Light.NoTitleBar.Fullscreen"白色背景,无标题栏,全屏 android:theme="Theme.Black"背景黑色 android:theme="Theme.Black.NoTitleBar"黑色背景并无标题栏 android:theme="Theme.Black.NoTitleBar.Fullscreen"黑色背景,无标题栏,全屏 android:theme="Theme.Wallpaper"用系统桌面为应用程序背景 android:theme="Theme.Wallpaper.NoTitleBar"用系统桌面为应用程序背景,且无标题栏 android:theme="Theme.Wallpaper.NoTitleBar.Fullscreen"用系统桌面为应用程序背景,无标题栏,全屏 android:theme="Translucent"透明背景 android:theme="Theme.Translucent.NoTitleBar"透明背景并无标题 android:theme="Theme.Translucent.NoTitleBar.Fullscreen"透明背景并无标题,全屏 android:theme="Theme.Panel"面板风格显示 android:theme="Theme.Light.Panel"平板风格显示 找一下Theme.NoTitleBar需要的属性,android sdk根路径\platforms\android-xx\data\res\values\themes.xml: [html] view plain copy <!--Variantof{@link#Theme_Light}withnotitlebar--> <stylenamestylename="Theme.Light.NoTitleBar"> <itemnameitemname="android:windowNoTitle">true</item> </style> <!--Variantof{@link#Theme_Light}thathasnotitlebarand nostatusbar.Thistheme sets{@linkandroid.R.attr#windowFullscreen}totrue.--> <stylename="Theme.Light.NoTitleBar.Fullscreen"> <itemnameitemname="android:windowFullscreen">true</item> <itemnameitemname="android:windowContentOverlay">@null</item> </style> 这样就能知道: 去掉TitleBar的关键属性是<itemname="android:windowNoTitle">true</item> 全屏的关键属性是<item name="android:windowFullscreen">true</item> 3 再次思考 上面给出的是一个三层状态,DecorView里面包含: (1) ActionBarOverklayLayout:ActionBar带来的一个布局,遍布了除了第三层最上端View的所有区域 (2) RelativeLayout : Activity的Layout (3) View : 状态栏背景 上面直观的认为是因为ActionBar导致了ActionBarOverklayLayout的创建,根据上面的方法一再做一次尝试: [html] view plain copy protectedvoidonCreate(BundlesavedInstanceState){ requestWindowFeature(Window.FEATURE_NO_TITLE); super.onCreate(savedInstanceState); ViewGroupgroup=(ViewGroup)getWindow().getDecorView(); LayoutInflater.from(this).inflate(R.layout.activity_main,group,true); ViewServer.get(this).addWindow(this); } 再看一下布局图: 依旧还是3层,再想一想为什么?因为我们上面只是指定了当前的Activity不需要ActionBar,但是回忆一下最上面的Activity的View层次图,系统首先会在DecorView上面加载一个初始布局,然后把Activity的布局放到这个初始布局上id为content的位置上,上面ActionBarOverklayLayout实际上是一个自带了ActionBar布局的初始布局,现在设置了FEATURE_NO_TITLE以后,系统加载的初始布局就是这里的LinearLayout,所以这一层布局依旧还是存在的,再结合上面的removeView修改一下: [html] view plain copy protectedvoidonCreate(BundlesavedInstanceState){ requestWindowFeature(Window.FEATURE_NO_TITLE); super.onCreate(savedInstanceState); ViewGroupgroup=(ViewGroup)getWindow().getDecorView(); group.removeAllViews(); LayoutInflater.from(this).inflate(R.layout.activity_main,group,true); ViewServer.get(this).addWindow(this); } 再看一下这时候的布局图: 出来了,这下子少了一层并列的系统层了,下面的这个View是手机顶端的信号时间之类的状态信息,经过测试,在group.removeAllViews();的时候并没有这个View,具体什么时候创建的就不去深究了,但是借鉴 http://chaosleong.github.io/blog/2015/11/28/Android-%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD-layout-%E8%B5%84%E6%BA%90/ 这篇文章的内容,在inflate布局实例的时候,会调用ContextThemeWrapper.getResources()和ContextThemeWrapper.getTheme()函数(Activity继承了ContextThemeWrapper),根据当前的资源和主题来实例化对象,我们只要在Application的Theme中加一个全屏配置项: <itemname="android:windowFullscreen">true</item> 然后再看一下这时候的情况: 就只有这一层了,再来对比一下一般情况下设置全屏模式的布局: 复杂程度可见一斑,但是去掉前面这两层目前还不知道有没有什么问题,还需要经过一些测试。根据目前Android系统事件的传输机制来看,应该是 没有什么问题的,通过上述方式可以将我们的布局直接放到根View里面去,减少了中间的两层系统布局。 4 完整的demo https://github.com/houliang/Android-DecorView 里面用到了ViewServer类,该类的使用方法在注释里面说的很清楚了,加上这个类就可以利用sdk根路径\tools\hierarchyviewer.bat观察Activity的布局 最后注明一点:ActionBar和Activity里面放到content里面的View是相同的等级关系,互不隶属。 本文转自 一点点征服 博客园博客,原文链接:http://www.cnblogs.com/ldq2016/p/6835095.html,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

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

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等操作系统。

用户登录
用户注册