【济南中心】Android就业面试技巧系列-技术篇(敏捷开发
一)
敏捷开发由来
2001年2月11日到13日,17位软件开发领域的领军人物聚集在美国犹他州的滑雪胜地雪 鸟(Snowbird)雪场。经过两天的讨论,“敏捷”(Agile)这个词为全体聚会者所接受,用以概括一套全新的软件开发价值观。这套价值观,通过一 份简明扼要的《敏捷宣言》传递给世界,同时即宣告了敏捷开发运动的开始。《敏捷宣言》
我们通过身体力行和帮助他人来揭示更好的软件开发方式。经由这项工作,我们形成了如下价值观:
个体与交互
重于 过程和工具 可用的软件
重于 完备的文档 客户协作
重于 合同谈判 响应变化
重于 遵循计划
在每对比对中,后者并非全无价值,但我们更看重前者。敏捷开发模式
敏捷开发是一种以人为核心、迭代、循序渐进的开发方法。敏捷方法强调以人为本,专注于交付对客户有价值的软件。在高度协作的开环境中,使用迭代式的方式进行增量开发,经常使用反馈进行思考、反省和总结,不停的进行自我调整和完善.敏捷开发,相对传统软件开发模式,它主要是针对快速变化的需求,不断优化管理流程,最终推出优质软件.黑马程序员济南中心 编著
敏捷开发的宣言
一:个体及交互比流程与工具更具价值 二:可用的软件比冗长的文档更有价值 三:与客户的协作比合同谈判更有价值 四:对变化的响应比遵循计划更有价值 5个价值
1.承诺 – 愿意对目标做出承诺
2.专注– 把你的心思和能力都用到你承诺的工作上去 3.开放– Scrum 把项目中的一切开放给每个人看 4.尊重– 每个人都有他独特的背景和经验
5.勇气– 有勇气做出承诺,履行承诺,接受别人的尊重 Scrum的重要名词
Backlog一次迭代开发的时间周期,一般最多以30天为一个周期。在这段时间内,开发团队需要完成一个制定的Backlog。
Product Owner负责监督整个Scrum进程、修订计划的一个团队成员。研发项目管理经理
流程经理 敏捷教练 开发主管
Sprint planning meeting开发团队成员参加,一般为15分钟。每个开发成员需要向Scrum Master汇报三个项目:今天完成了什么? 是否遇到了障碍? 即将要做什么?通过该会议,团队成员可以相互了解项目进度。
Sprint review meeting对刚结束的Sprint进行总结。会议的参与人员为团队开发的内部人员。一般该会议为3小时。
PBI Product Backlog Item 产品待办清单条目,简称PBI 敏捷开发成员架构 Scrum Master
负责管理Scrum流程,确保Scrum正常运转。Scrum Master是教练,是牧羊犬,是Scrum项目秩序的维护者。
· 负责监督整个Scrum项目进程,调整项目计划 · 确保开发团队成员的能力能够胜任产品的开发;
· 促进团队中不同角色的成员间充分交流和沟通,并负责为项目的进行扫除障碍; · 保证开发团队不受外力的干扰和阻挠;
· 掌握产品开发进度,参与每日Scrum会议、Sprint计划会议和Sprint评审会议。· Scrum Master最经常的情况就是由过去的项目组长(Team leader)来担当 产品负责人 Product Owner
负责管理产品Backlog 并使游戏项目价值最大化,代表项目的全体利益相关者。
黑马程序员济南中心 编著
Product Owner的角色通常由市场部门的人员或开发部门内部主要使用该产品的人来担任,他的主要工作是根据市场需求,确定产品的功能,列入Product Backlog中,并为这些功能确定优先级别。
Scrum团队按照功能的优先级,将它们从高到低分配到各个Sprint中进行开发,这些被分配到一个Sprint中完成的功能就形成了Sprint Backlog。
在产品的整个开发过程中,Product Owner对于产品的需求可能会发生改变。他可以修改Product Backlog,增加某些功能需求、删除某些功能需求、修改优先级等等,但这些行为只能在各个Sprint之间进行 团队
团队是负责开发软件的跨职能小组。团队是自我管理的,在Scrum Master 的帮助下,团队提出承诺,完成自己的承诺,实现软件价值。
一般由5-10个能全职工作的成员组成较为理想;团队成员横跨各个职能,通常包含开发,测试,文档设计人员等等。敏捷开发团队原则 最大的分歧
最大的分歧在于开发人员和测试人员之间。作为敏捷团队的成员,测试人员被期望能编写一点代码,同时开发人员可以做一 些测试。各自的强项还是很重要:新的角色要求每个成员成为大家所谓的“通才”。测试人员大多数时间作测试,开发人员大都编写代码,但所有人都分享他们的工 作,而且有能力承担他们面前的任务。发现中立点
团队决定作为一个团队需要做什么,如何最好地分配工作。第一步是让团队成员说说他们自己的技能集、优点和缺点。但却不希望他们根据以前角色(如,软件测试员或开发员)来定
黑马程序员济南中心 编著
义自己。所以找到一个中立点,列出了小型离线会议,和每周工作之外的小时集体活动所需的事项。正确执行应用程序
团队找到了让自己感到舒服的新水平。整个项目的工作流程顺利进行,只做一个待办的事情,而不是四个。Scrum过程简单介绍 将整个产品的Backlog分解成若干Sprint Backlog,每个Sprint Backlog是按照目前的人力物力条件可以完成的。召开Sprint planning meeting,划分、确定这个Sprint内需要完成的任务,标注任务的优先级并分配给每个成员。进入Sprint开发周期,在这个周期内,每天需要召开Daily Scrum meeting。4 整个Sprint周期结束,召开Sprint review meeting,将成果演示给Product Owner。5 团队成员最后召开Sprint retrospective meeting,总结问题和经验。6 周而复始,按照同样的步骤进行下一次Sprint。敏捷开发流程
黑马程序员济南中心 编著
敏捷开发模型流程图
从敏捷开发流程模型图当中可以看出,在敏捷实施过程当中,有四种会议,分别是计划会,每日站会,回顾会,评审会,其中数计划会最为重要。在敏捷开发模式中,每种会议都有其特殊的职责和使命,不同的会议上所讨论的内容是不一致的,只要把握住会议的关键点,就可以为团队的敏捷模式服务。
Sprint Planning敏捷迭代计划会议 1 Sprint Planning敏捷迭代计划会议
在每个敏捷迭代开始之初,由产品负责人讲解需求,并由开发团队进行估算工时的计划会议。在会议上需要:排列需求优先级;分析和评估产品Backlog并确定该迭代的目标;计划会议上还需要制定迭代计划,包括: 根据产品Backlog(功能点)创建Sprint Backlog(即迭代任务);然后为Sprint backlog中的任务做估算;团队成员从产品Backlog中挑选他们承诺完成的条目。
敏捷的迭代实现始于计划会议,所以一个好的计划会议是每个迭代成功的基础,一般分两个阶段进行,两个阶段参与会议的人员会不一样; 计划会议的目标:
黑马程序员济南中心 编著
1、基于敏捷规划产生的Product Backlog以及优先级,通过计划会议,确定迭代的目标、团队成员、形成Sprint Backlog,明确评审会、回顾会时间;
2、分解Sprint Backlog并确定相应的完成时间,并由团队成员共同挑选这些Sprint Backlog;
阶段一参与人员:产品经理、Product Owner、Scrum Master、团队成员,有业务人员的话还可以邀请业务人员一起参加。会议时长:1-4小时 一般参考进程安排如下:
1、Scrum Master公开迭代时间表;
2、产品经理和Product Owner讲述Product Backlog,对应的业务价值和优先级;
3、团队针对Sprint Backlog和优先级达成一致;
4、Scrum Master和团队成员共同确定Sprint Backlog; 阶段二参与人员:Scrum Master、团队成员,其他人员选择性参加 会议时长:1-4小时 一般参考进程安排如下:
1、团队成员针对Sprint Backlog共同分解任务;
2、团队成员共同进行工作量评估(每个Task不超过2天),确定开始时间和完成时间;
3、团队成员共同认领任务;
4、共同确定DoD,团队达成一致;
5、团队共同确认迭代目标和价值;
如果单个迭代内安排的Product Backlog安排的比较多的话,一般迭代计划会议需要开一个整天,虽然时间有点长,但这个会议会确认整个迭代的详细计划和安排,因此也是值得的。
黑马程序员济南中心 编著
一个典型的Sprint计划会议时间表
Sprint 计划会议:13:00 – 17:00(建议每小时休息10分钟)
13:00 – 13:30 产品负责人对Sprint目标进行总体介绍,概括产品Backlog。定下演示的时间地点。
13:30 – 15:00 团队估算时间,在必要的情况下拆分Backlog条目——把“故事”进一步拆分成“任务”。产品负责人在必要时修改重要性评分。理清每个条目的含义。所有重要性高的Backlog条目都要填写“如何演示”。
15:00 – 16:00 团队选择要放入Sprint中的故事。计算生产率,用作核查工作安排的基础。16:00 – 17:00 为每日Scrum会议(简称每日例会)安排固定的时间地点——如果和上次不同的话。
Sprint应该多长才好?
时间短就好。公司会因此而变得“敏捷”,有利于随机应变。
短的Sprint = 短反馈周期 = 更频繁的交付 = 更频繁的客户反馈 = 在错误方向上花的时间更少 = 学习和改进的速度更快 绘制任务版
任务版中的任务是分解到手头的实际的工作
把要做的任务,正在做的任务和已经完成的任务,用简单的贴士贴在白板上.不同的颜色表示不同的重要程度.开发人员选择任务帖在规定时间内完成任务
黑马程序员济南中心 编著
敏捷开发遇到的扑克牌(计划纸牌)
每个人都会得到如上图所示的13张卡片。在估算故事(任务)的时候,每个人都选出一张卡片来表示他的时间估算(以故事点的方式表示),并把它正面朝下扣在桌上。所有人都完成以后,桌上的纸牌会被同时揭开。这样每个人都会被迫进行自我思考,而不是依赖于其他人估算的结果。
如果在两个估算之间有着巨大差异,团队就会就此进行讨论,并试图让大家对故事内容达成共识。他们也许会进行任务分解,之后再重新估算。这样的循环会往复进行,直到时间估算趋于一致为止,也就是每个人对这个故事的估算都差不多相同。2 Daily Stand-up Meeting每日站会
黑马程序员济南中心 编著
团队每天进行沟通的内部短会,因一般只有15分钟且站立进行而得名,团队成员通常会在会议上讲述如下3点内容: 1)
昨天我做了什么 2)
今天我计划要做什么
3)
我遇到了什么问题,妨碍了我尽可能有效地工作
Scrum Master记录会议上提出的问题,但是不要在会议上讨论和解决问题,而是要会后在找相关人员进行讨论和解决。3 Sprint Review 敏捷迭代评审会议
在迭代结束前给产品负责人演示并接受评价的会议,并根据反馈结果,提出新的产品Backlog 参与人员:产品经理、Product Owner、Scrum Master、团队所有成员 会议时长:1-4小时,视演示内容而定
主要是检验迭代成果,检查是否完成迭代计划中的迭代目标,有可能的话要求用户参与测试流程,并得到用户对产品的认可,鼓励用户自己进行测试设计和进行破坏性测试,充分暴露产品的设计和功能问题。
由Scrum Master来推进会议进程,Product Owner记录用户反馈,根据结果维护产品 backlog,一般在迭代结束前做一次。4 Sprint Retrospective 敏捷迭代回顾会议
在每个迭代结束后召开的关于自我持续改进的会议,围绕如下三个问题进行讨论: 1)
本次迭代有哪些做得好;
2)
本次迭代我们在哪些方面还能做得更好; 3)
我们在下次迭代准备在哪些方面改进;
黑马程序员济南中心 编著
团队确定问题优先级,并根据优先级确定团队能够解决的Top问题;团队讨论Top问题的措施,并选择在下一个迭代可以完成措施,分配责任人进行跟踪。参与人员:Scrum Master,Product Owner,团队成员。会议时长:0.5-1.5小时
主要针对当前迭代,团队成员自由讲述可以需要保持的做法,改进的点以及持续跟踪计划。Scrum Master将团队讨论以及行动计划形成会议纪要,并发送给整个团队和有关同事。需要按照回顾会议的结论,维护一份待办事项列表,在下次回顾会议上进行跟踪。案例分析
案例一:某Team在每日站会中,Scrum master准时组织大家开始晨会,成员一个接着一个说,昨天做了什么事情,今天计划做什么事情,遇到什么问题,成员A说昨天遇到了一个问题未能解 决,Scrum master问遇到的是什么问题,成员A详细说明了该问题,这时成员B说这个问题他也遇到过,他是通过XX方式解决的,讨论后成员A明白了,然后继续晨 会,由于小组成员有10个人,整个会议开下来大概花费了30分钟。
问题分析:Scrum master不应该在每日站会上询问详细的问题细节,而应该转移到会下询问,当团队成员之间进行讨论的时候,Scrum master需要及时拉回来,讨论应该转移到会下进行,晨会要在固定的时间固定的地方并且在固定的时间内完成。会议时间需要控制在15分钟之内。
案例二:某Team在开回顾会议中,Scrum master详细总结了本次迭代中有哪些做不够好的,并指出了对应的事和人,接着对应的责任人开始述说哪些地方确实是做的不够好及其原因,最后给出改进措施然后结束会议。
问题分析:回顾会不是批斗会,不应该只说做的不好的,做的好的也要说,Scrum master主要是鼓舞大家的士气,应该先从做的好的方面开始说起;并且做的不好的方面都只对事,黑马程序员济南中心 编著
不对人,做的不好是整个Team的责任,不仅仅是某几个 人的责任;最后的改进措施需要给有后续跟踪的责任人和有效性的反馈。
在敏捷的迭代执行过程中,上述四种会议会随着每个迭代一直进行,基本上形成了一个闭环,可以让团队在每个迭代的执行过程当中去学习和总结,从而正确的按照敏捷的要求去做,使团队真正的敏捷起来。
黑马程序员济南中心 编著
01、什么是3G 02、android系统简介 03、android背景介绍 04、android的framewor简介 05、两种虚拟机的比较 06、sdk的下载以及简介 07、创建android模拟器 08、ddms简介
09、platform-tools的简介及常见adb指令
10、android项目的目录结构
11、android下apk安装的过程
12、常见的adb指令介绍
13、创建模拟器遇到的常见错误
14、电话拨号器
15、点击事件的四种写法
16、短信发送器
17、相对布局&单位介绍
18、现形布局&布局的组合
19、表格布局&绝对布局 20、帧布局
21、测试相关概念
22、android下junit测试框架配置
23、logcat简介
24、保存文件到手机内存
25、android下文件访问的权限
26、保存文件到SD卡中
27、分析setting源代码获取SD卡大小
28、_sharePreference入门
29、xml文件的序列化 30、采用pull解析xml文件
31、采用断电调试的方法观察pull解析的的流程
32、android下创建一个sqllite数据库
33、sql语句实现数据库的增删改查
34、系统api实现数据库的增删改查&Sqlite3工具的使用
35、数据库的事物
36、listView入门
37、采用layoutInflater打气筒创建一个view对象
38、采用数据适配器ArryAdapter
39、常用数据适配器simpleAdapter 40、数据适配器总结
41、内容提供者简介
42、内容提供者的实现
43、短信的备份
44、插入一条记录到系统短信应用
45、内容观察者
46、获取系统的联系人信息
47、保存联系人到系统通讯录
48、读取联系人的一个小细节
49、网络图片查看器
50、anr产生的原理&如何避免
51、android消息机制入门
52、网络html查看器
53、字符乱码问题的处理
54、采用get方式提交数据到服务器
55、采用post方式提交数据到服务器
56、提交数据到服务器中文乱码问题的处理
57、采用httpclient提交数据到服务器
58、异步http框架简介&实现原理
59、异步http框架提交数据到服务器 60、上传文件到服务器
61、smartimageview&常见开源代码 62、多线程下载的原理 63、多线程断点下载的原理
64、多线程java代码移植到android 65、多线程下载文本页面的更新 66、显示意图激活另一个activity 67、隐式意图激活另一个activity 68、隐式意图的配置
69、隐式意图和显示意图的使用场景 70、在不同activity之间数据传递 71、activity的声明周期 72、activity的启动模式
73、activity横竖屏切换的声明周期 74、开启新的activity获取他的返回值 75、请求码和结果码的作用 76、利用广播实现ip拨号 77、短信窃听器
78、自定义广播时间&发送自定义广播&广播接受者优先级 79、采用服务执行长期后台操作 80、采用服务窃听电话&服务的声明周期 81、android进程优先级&为什么使用服务 82、绑定方式开启服务&调用服务的方法 83、服务的声明周期(混合开启 84、采用aidl绑定远程服务
85、代码注册广播接受者&利用广播调用服务的办法 86、加载大图片到内存 87、获取图片exif信息 88、从gallery获取图片 89、图片画画板 90、扒开美女衣服 91、图片的缩放 92、图片的旋转
93、图片的平移&镜面&倒影效果 94、图片的合成 95、图片的颜色处理 96、多媒体播放api简介 97、人脸识别
98、mediaplayer的生命周期 99、soundpoo简介
100、sufaceview的生命周期 101、播放在线视频
102、视频播放器进度的处理 103、调用系统照相机拍照和录像 104、采用camera拍照 105、常见对话框 106、notification入门 107、菜单
108、android下的样式 109、android下的主题
110、代码编写ui 111、html创建ui 112、帧动画
113、代码创建创建的tween动画 114、xml文件定义动画 115、传感器简介 116、117、杀死进程 118、apk的安装 119、应用程序的反编译 120、动态创建fragment 121、用fragment创建一个选项卡 122、fragment的向下兼容性 123、fragment的生命周期 124、fragment之间的通讯 125、应用程序国际化
04、android的framewor简介
Wap:wait and play Wireless Makeup Language(WML)精简的html语言 Applications:android自带的基本上层应用 Aplication framework:应用程序框架 Librarics: Linux lernel:
05、两种虚拟机的比较
编译后文件格式:
jvm:.java->.class->.jar dalvik vm:.java->.dex->.odex 基于的架构:
jvm:基于栈的架构
dalvik vm:基于寄存器的架构
Cpu直接访问寄存器因此dalvik虚拟机的效率比jvm高
06、sdk的下载以及简介
->获取sdk工具包(sdk:standard develope kits)->ADT(android develop tools,实际上是eclipse的插件)SDK具体内容
Android 4.2.2(API16)
->SDK Plateform:开发时使用到的jar包->Samples for sdk:
->ARM EABI V7a System Image:模拟器运行时的镜像->Intel n86 Aton System:模拟器运行时的镜像->MIPS System Image:模拟器运行时的镜像->google APIs:google提供的jar包,可以直接使用google提供的一些API->source for android SDK:SDK全部的源代码 Extrals:
->tools:开发的工具
->support library:实现高版本的android向下的兼容->google Admed Ads SDK:gongle提供的广告插件->Analyties App Irackiong SDK:应用的用户分析->cloud message:云消息
->gongle play service:收费服务
->google USB Driver:真实的设备驱动
开发时:基于4.0,兼容2.2、2.3.3
07、创建android模拟器
avd:android virture developer VGA:480*640(电视的标准分辨率)QVGA:240*320(四分之一)HVGA:320*480(一半)WVGA:480*800(width)FWVGA:480*854(更宽)
08、ddms简介
ddms:模拟器不支持中文,因此发送中文会显示不出来
09、platform-tools的简介及常见adb指令
Android调试桥:内部实现就是socket让两个系统之间实现数据交互
->reset adb:模拟器找不到时候可以重启->adb device:列出所有的连接的设备->adb kill-server:杀死adb调试桥->adb start-server 启动adb调试桥 dx.bat:将.class文件打包
10、android项目的目录结构
一:SDK的目录结构
->Samples->Api demo:根据API demo(模拟器上面可以看见)的效果可以在sample中看见
相应的代码
->Source:jar包所有的sdk源代码都在这个文件夹里->SystemImage:系统镜像
->temp:下载更新临时存储的文件夹,一般是空的->tools:emulater.ext 不同版本的模拟器
二:New Android Application->theme:留给以后作为扩展,现在并没有太大的作用->target SDK:一般选择高版本,因为高版本对下兼容
->mark project as a library:一般不选择,意思是将这个项目提供一个
jar包供别人使用 三:文件夹目录
.setting:设置目录
assets:资产目录,存放一些文件,这些文件会被原封不动打包到应用程序的 apk中
bin:
gen:自动生成的目录
->builderConfig.java:生成的配置信息->R.java: Android 4.1.2->android.jar开发环境,jar包
可以在properties中修改,jar包就是SDK
011、Android下apk的安装过程
一、Android安装过程分析:
->setContentView:甚至view的对象,把里面的xml文件加载到
->在project中选择build automaticly会自动把文件生成字节码文件,.class $代表的class文件生成的是内部类->dex.bat文件会把.class文件生成.dex文件
->apk压缩文件解压内部内容
->META-INF: 应用程序的签名
eclipse的调试签名文件
->res:资源文件
->classes.dex:class文件
->resources.arsc:资源ID映射
->android软件安装的过程:
->拷贝xxx.apk带/data/app/xxx-1.apk->在/data/data目录下创建一个文件夹,文件夹名称当前应用程序的报名
012、常见adb指令
前提:
->设备连接上电脑而且驱动安装正常,如果安装不正常的话,会有黄色的问号显示;
->设备上打开USB调试;
指令:
->adb device(如果启动发现这个程序没有安装会自动安装)->adb kill-server->adb start-server->adb uninstall <包名>->adb-s emulator-5554 install c:usersadministratorhello.apk 如果有多个设备的话,如果不指定安装的是哪个设备程序会报错->adb push haha.prop /sdcard/haha.txt 将文件移到
(360管家,豌豆荚之类的软件他们也是用的adb指令,倘若电脑上装这些软件的话,会因为两个adb指令抢端口号而挂掉)(adb版本之间兼容不是很好,经常报错可以考虑下版本的问题)->adb shell:远程连接到了android的linux终端
ls:显示文件夹
ps:显示正在运行的程序 ping:网络连通性
013、创建模拟器遇到的常见错误
->路径最好不要有中文:
->应用安装不上,或者安装模拟器的时候开启一个新的模拟器:
可能是模拟器的资源被占用,模拟器在运行的时候其实占用着硬盘上面的一个文件,这个文件位于工作空间.android/avd/iphone.avd 里面会有镜像文件,当一个模拟器开启起来了,就给你创建一个文件夹.knock的文件夹,代表着这个模拟器被锁定了,如果把模拟器关掉,就没有程序占据这几个镜像资源了,那么这几个程序就会被自动删除。通常情况下不会出问题,开启时候创建文件,关闭时关闭文件,但是当电脑出现不正常状态时:比如蓝屏,停电关机时候这些资源还没来得及删除,模拟器就关闭了,因此开启时这些资源仍在,程序默认模拟器被占用,因此会重新开启一个模拟器。
->模拟器没有信号:
模拟器用socket桥接在电脑上
终结解决方案是给电脑连上网,分配一个IP->常见命令操作:
14、电话拨号器
->新建文件
->界面设置:文本框、点击按钮
-> :一旦获得焦点,会立刻弹出,输入文本的软键盘->ctrl+x删除->ctrl+1提示
->设置点击事件:找到空间,然后设置点击事件,再点击事件里面获得了另外一
个空间的数据,激活一个intent->获得权限:清单文件中添加uses permision
15、点击事件的四种写法
->电话拨号器的优化:
每次拨打电话都会执行的操作是:查找控件,然后找到控件的文本,拨打电
话。其实每次拨打电话文本控件已经创建好了没有必要每次查找按钮之后再 查询控件。
package cn.wqrt.mobile;
import android.app.Activity;import android.content.Intent;import android.net.Uri;import android.os.Bundle;import android.text.TextUtils;import android.view.Menu;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.Toast;
public class MainActivity extends Activity {
private EditText et_number;@Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button button =(Button)findViewById(R.id.bt_dial);et_number =(EditText)findViewById(R.id.et_number);button.setOnClickListener(new MyListener());}
private class MyListener implementsandroid.view.View.OnClickListener{
@Override
public void onClick(View arg0){
String number = et_number.getText().toString().trim();//去除回车和空格
if(TextUtils.isEmpty(number)){
Toast.makeText(MainActivity.this, “号码不能为空”, Toast.LENGTH_SHORT).show();
return;
}
Intent intent = new Intent();
intent.setAction(intent.ACTION_CALL);
intent.setData(Uri.parse(“tel:”+number));
startActivity(intent);
}
}
@Override public boolean onCreateOptionsMenu(Menu menu){ // Inflate the menu;this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;} }
->
1、点击事件的四种写法:
->给按钮注册点击事件:创建一个内部类定义点击事件。具体代码见上
button.setOnClickListener(new MyListener());
->
2、采用匿名内部类创建点击事件:
button.setOnClickListener(new OnClickListener()){
package cn.wqrt.mobile;
import android.app.Activity;import android.content.Intent;import android.net.Uri;import android.os.Bundle;import android.text.TextUtils;import android.view.Menu;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.Toast;
public class MainActivity extends Activity {
private EditText et_number;@Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button button =(Button)findViewById(R.id.bt_dial);et_number =(EditText)findViewById(R.id.et_number);button.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0){
// TODO 自动生成的方法存根
callPhone();
}
});}
@Override public boolean onCreateOptionsMenu(Menu menu){ // Inflate the menu;this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}
private void callPhone(){
String number = et_number.getText().toString().trim();//去除回车和空格
if(TextUtils.isEmpty(number)){
Toast.makeText(MainActivity.this, “号码不能为空”, Toast.LENGTH_SHORT).show();
return;
}
Intent intent = new Intent();
intent.setAction(intent.ACTION_CALL);
intent.setData(Uri.parse(“tel:”+number));
startActivity(intent);} } }
->
3、如果有很多的按钮点击事件,建议用这种方式:让Activity实现点击 事件的接口,每个按钮点击事件都设置成this,让该类实现 OnClickListener然后进行判断。package cn.wqrt.mobile;
import android.app.Activity;import android.content.Intent;import android.net.Uri;import android.os.Bundle;import android.text.TextUtils;import android.view.Menu;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.Toast;
public class MainActivity extends Activity implements OnClickListener {
private EditText et_number;@Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button button =(Button)findViewById(R.id.bt_dial);et_number =(EditText)findViewById(R.id.et_number);button.setOnClickListener(this);}
@Override public boolean onCreateOptionsMenu(Menu menu){ // Inflate the menu;this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}
private void callPhone(){
String number = et_number.getText().toString().trim();//去除回车和空格
if(TextUtils.isEmpty(number)){
Toast.makeText(MainActivity.this, “号码不能为空”, Toast.LENGTH_SHORT).show();
return;
}
Intent intent = new Intent();
intent.setAction(intent.ACTION_CALL);
intent.setData(Uri.parse(“tel:”+number));
startActivity(intent);}
@Override public void onClick(View v){
// TODO 自动生成的方法存根
switch(v.getId()){
case R.id.bt_dial:
callPhone();
break;
} } }->
4、在布局文件中绑定一个点击的方法,如果点击按钮就会调用这个方法,通
过反射技术试图调用这个方法
布局文件中设置: package cn.wqrt.mobile;
import android.app.Activity;import android.content.Intent;import android.net.Uri;import android.os.Bundle;import android.text.TextUtils;import android.view.Menu;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.Toast;
public class MainActivity extends Activity {
private EditText et_number;@Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button button =(Button)findViewById(R.id.bt_dial);et_number =(EditText)findViewById(R.id.et_number);
}
@Override public boolean onCreateOptionsMenu(Menu menu){ // Inflate the menu;this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}
public void dialButtonClick(View v){ callPhone();}
private void callPhone(){
String number = et_number.getText().toString().trim();//去除回车和空格
if(TextUtils.isEmpty(number)){
Toast.makeText(MainActivity.this, “号码不能为空”, Toast.LENGTH_SHORT).show();
return;
}
Intent intent = new Intent();
intent.setAction(Intent.ACTION_CALL);
intent.setData(Uri.parse(“tel:”+number));
startActivity(intent);} }
16、短信发送器
->界面的设计:两个large Text,一个Button
android:textColor 设置字体颜色
android:singleLine=“true” 设置是否是单行
android:lines=“5” 设置行数
windows下面的颜色是GBR,而android下需要输入的格式确实
RGB,所以需要转换
adb默认设置time out为5秒->内容设计:按钮-文本->判断->发送
导包的时候千万别导到gsm包,否则会显示过时;
发送没有历史记录 package com.example.sms;
import java.util.ArrayList;
import android.app.Activity;import android.os.Bundle;import android.telephony.SmsManager;import android.text.TextUtils;import android.view.Menu;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.Toast;
public class MainActivity extends Activity implements OnClickListener {
private EditText et_number;private EditText et_content;
@Override protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button =(Button)findViewById(R.id.bt_send);
et_number =(EditText)findViewById(R.id.et_number);
et_content =(EditText)findViewById(R.id.et_content);
button.setOnClickListener(this);}
@Override public boolean onCreateOptionsMenu(Menu menu){
// Inflate the menu;this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);
return true;}
@Override public void onClick(View v){
// TODO 自动生成的方法存根
switch(v.getId()){
case R.id.bt_send:
String number = et_number.getText().toString().trim();
String content = et_content.getText().toString().trim();
if(TextUtils.isEmpty(number)||TextUtils.isEmpty(content)){
Toast.makeText(this, “号码或者内容不能为空”,Toast.LENGTH_SHORT).show();
return;
}else{
SmsManager smsManager = SmsManager.getDefault();
ArrayList contents = smsManager.divideMessage(content);
for(String str:contents){
smsManager.sendTextMessage(number, null, str, null, null);
}
}
} } }
17、相对布局&单位介绍
->布局说明:
->同级控件:
android:layout_toRightOf=“" android:layout_toLeftOf=”“ android:layout_below=”' android:layout_above=“" android:layout_maginBottom=”“
->相对父控件:
android:ayout_centerInParent=”“ android: layout_centerHorizontal=”“ android:layout_centerVertical=”“ android:layout_alignParentBottom=”“ android:layout_alignParentRight=”“->对齐方式:
->文本颜色:#00000000~#ff000000(argb)文字的透明度->单位介绍:
dp也就是dip:device independent pixels(设备独立像素),是一种与密度无关的像素单位,在每英寸160点的屏幕上,1dp = 1px。不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA、HVGA和QVGA 推荐使用这个,不依赖像素
1.2.android:layout_height=”wrap_content“
3.android:text=”@string/clickme“
4.android:layout_marginTop=”20dp“ />
scaled pixels(刻度像素).主要用于定义字体的大小,而从来不再layout上使用
o
1.2.android:layout_height=”wrap_content“
3.android:textSize=”20sp“ />
px:pixels(像素).不同设备显示效果相同,一般我们HVGA代表320x480像素,这个用的比较多 总结: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 和 dp 互转换
1.package com.hujl.util;import android.content.Context;
public class DensityUtil {
/**
* 根据手机的分辨率从 dp 的单位转成为 px(像素)
*/
public static int dip2px(Context context, float dpValue){
final float scale = context.getResources().getDisplayMetrics().density;
return(int)(dpValue * scale + 0.5f);
}
/**
* 根据手机的分辨率从 px(像素)的单位转成为 dp
*/
public static int px2dip(Context context, float pxValue){
final float scale = context.getResources().getDisplayMetrics().density;
return(int)(pxValue / scale + 0.5f);
} }
18、线性布局&布局的组合
->线性布局:
->线:就是view对象
android:layout_height=”1px“
android:background=”#ff0000“ > />
通常采用相对布局和绝对布局联合使用的方式。
19、表格布局&绝对布局
->表格布局:渲染权重
->绝对布局:对控件位置任意摆放,需要计算不同屏幕中的位置,因为android
软件的屏幕大小实在太多,所以并不方便,不推荐使用。
20、帧布局
>帧布局:
->类似于网页布局中的div
android:visibility:”“ //显示是否可见,播放器最喜欢使用帧布局,暂停播放的时候,会在上面显示一个按钮
21、测试相关概念
->根据测试测试是否知道程序的源代码:
->黑盒测试:不知道源代码,只关心程序执行的过程和程序的结果,一个资
深的黑盒程序人员工资很高,因为他们和正常用户的使用思维
不一样
->白盒测试:根据源代码写测试方法或者测试用例->根据测试的粒子度:
->方法测试:function test->单元测试:unit test->集成测试:intergration test->根据测试的次数:
->冒烟测试:smoke test 反复不停的执行,反复不停的使用(android猴子
来测试)
->adb shell
->monkey
->monkey 5000(点击五千次)
->压力测试:pressure test同时抗住多人的请求->
22、android下junit测试框架配置
23、logcat简介
->日志信息级别:
Verbose:提醒 黑色
Debug: 调试 蓝色
Info: 信息 绿色
Warn: 警告 橙色
Error: 错误 红色
24、保存文件到手机内存
->数据存储与访问
->文件
->SharePreferences(参数)
->SQLite数据库
->内容提供者(Content Provide)
->网络
->LinearLayout一定要设置水平还是垂直->文件保存:
->javase中通过创建文件对象,但是在androi中这种存放方式会失败,因
为会默认为存储在当前目录文件下
->android中创建一个包:com.itheima.login.service
创建一个类:LoginService.java
异常的处理:如果是返回值是boolean,那么抛出处理都可以,但是如果返回值是void,那么只能抛出了
->context:上下文就是一个类,这个类提供了很多方便的API,可以得到应用程
序的环境
环境包名 安装路径 文件的路径 资源的路径 资产的路径
放到缓存文件夹里面:getCacheDir();->getAssest();->getResource();->getFilesDir();/data/data/包名
->getCacheDir();/data/data/包名/cache
->MainActivity.java package com.example.login;
import java.util.Map;
import android.app.Activity;import android.os.Bundle;import android.text.TextUtils;import android.view.Menu;import android.view.View;import android.widget.CheckBox;import android.widget.EditText;import android.widget.Toast;
import com.example.login.service.LoginService;
public class MainActivity extends Activity {
private EditText et_number;private EditText et_passwd;private CheckBox cb_remPass;
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);//首先要把页面加载进来然后才有控件的获取
et_number =(EditText)findViewById(R.id.et_number);
et_passwd =(EditText)findViewById(R.id.et_passwd);
cb_remPass =(CheckBox)findViewById(R.id.cb_remPass);
Map map = LoginService.getSavaUserInfo(this);
if(map!= null){
et_number.setText((CharSequence)map.get(”username“));
et_passwd.setText((CharSequence)map.get(”passwd“));
} }
@Override public boolean onCreateOptionsMenu(Menu menu){
// Inflate the menu;this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);
return true;} public void login(View v){
String number = et_number.getText().toString().trim();
String passwd = et_passwd.getText().toString().trim();
if(TextUtils.isEmpty(number)||TextUtils.isEmpty(passwd)){
Toast.makeText(this, ”登录名或者密码不能为空“, Toast.LENGTH_SHORT).show();
return;
}else{
if(cb_remPass.isChecked()){
//如果选择了保存用户密码,那么就保存用户密码
boolean results = LoginService.saveuserInfo(this,number, passwd);
if(results){
Toast.makeText(this, ”保存用户信息成功“, Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this, ”保存用户信息失败“, Toast.LENGTH_SHORT).show();
}
}
//登陆发送消息到服务器,服务器验证是否正确
if(”zhangsan“.equals(number)&&”123456“.equals(passwd)){
Toast.makeText(this, ”登陆成功“, Toast.LENGTH_LONG).show();
}else{
Toast.makeText(this, ”登录失败,用户名或者密码不正确“, Toast.LENGTH_LONG).show();
}
} } }
->LoginService.java package com.example.login.service;
import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStreamReader;import java.util.HashMap;import java.util.Map;
import android.content.Context;/* * 保存用户名密码的的业务方法 */ public class LoginService { public static boolean saveuserInfo(Context context,String userName,String passWord){//没有使用任何类的方法,推荐使用静态方法
//File file = new File(”/data/data/com.example.login/info.txt“);
File file = new File(context.getFilesDir(),”info.txt“);
try {
FileOutputStream fos = new FileOutputStream(file);
fos.write((userName+”##“+passWord).getBytes());
fos.close();
return true;
} catch(FileNotFoundException e){
// TODO 自动生成的 catch 块
e.printStackTrace();
return false;
} catch(IOException e){
// TODO 自动生成的 catch 块
e.printStackTrace();
return false;
}
} /* * 获取保存到的数据
*/ public static Map getSavaUserInfo(Context context){
File file = new File(context.getFilesDir(),”info.txt“);
Map map = new HashMap();;
try {
FileInputStream fis = new FileInputStream(file);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fis));
String str = bufferedReader.readLine();
String[] infos = str.split(”##“);
map.put(”username“, infos[0]);
map.put(”passwd“, infos[1]);
} catch(FileNotFoundException e){
// TODO 自动生成的 catch 块
e.printStackTrace();
return null;
} catch(IOException e){
// TODO 自动生成的 catch 块
e.printStackTrace();
return null;
}
return map;} }
->activity_main.xml
android:id=”@+id/bt_login“
android:onClick=”login“
android:layout_width=”100dp“
android:layout_height=”wrap_content“
android:layout_alignParentRight=”true“
android:text=”@string/bt_login“
/>
android:id=”@+id/cb_remPass“
android:layout_width=”wrap_content“
android:layout_height=”wrap_content“
android:layout_alignParentLeft=”true“
android:layout_alignParentTop=”true“
android:layout_alignBottom=”@id/bt_login“
android:text=”@string/remPass“
android:checked=”true“ />
25、android下文件访问的权限
->private、readable、writeable、public
26、保存文件到SD卡中
->存储空间:
->手机的内部存储空间:小硬盘 /data/data->外部存储空间:SD卡 路径/mnt/sdcard 可以简写成/sdcard/
需要权限WRITE_EXTER_STORAGE
操作SD卡必须要权限
->保存数据到SD卡只需要把路径改为SD卡,读不需要权限,否则需要权限
在4.0以前的版本读SD卡不需要权限,但是在4.0以
后读写SD卡可以设置SD卡保护,读就需要权限 READ_EXTER_STORAGE->判断是否存在SD卡:Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
->为了保证程序的兼容性,有些SD卡可能路径会改变,因此系统提供了获取SD 卡的路径的方法
Environment.getExternalStorageDirectory()
27、分析setting源代码获取SD卡大小
->source的源代码是SDK的源代码,是jar里面的源代码->导入通用的文件项目eclipse要求必须要有setting文件->ctrl+h搜索文件夹
package com.example.sdsize;
import java.io.File;
import android.app.Activity;import android.os.Bundle;import android.os.Environment;import android.os.StatFs;import android.text.format.Formatter;import android.view.Menu;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;import android.widget.Toast;
public class MainActivity extends Activity {
private TextView tv_SDsize;protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button =(Button)findViewById(R.id.bt_find);tv_SDsize =(TextView)findViewById(R.id.tv_SDSize);
button.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0){
// TODO 自动生成的方法存根
StringBuilder memorySizeInfo = new StringBuilder();
if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){
memorySizeInfo.append(getExternalSize());
}else{
Toast.makeText(MainActivity.this,”无内存卡“, Toast.LENGTH_SHORT).show();
}
memorySizeInfo.append(getRomSpaceInfo());
tv_SDsize.setText(memorySizeInfo.toString());
}
});} /* * 获取SD卡的存储信息 */ public String getExternalSize(){
File path = Environment.getExternalStorageDirectory();
StatFs stat = new StatFs(path.getPath());
long blockSize = stat.getBlockSize();
long totalBlocks = stat.getBlockCount();
long availableBlocks = stat.getAvailableBlocks();
long totalSize = blockSize*totalBlocks;
long availSize = blockSize*availableBlocks;
String totalStr = Formatter.formatFileSize(this, totalSize);
String availStr = Formatter.formatFileSize(this, availSize);
String ExternalSize = ”SD总存储空间:“+ totalStr + ”可使用的空间:“ + availStr;
return ExternalSize;} /* * 获取可用的内部存储 */ public String getRomSpaceInfo(){
File path = Environment.getDataDirectory();
StatFs stat = new StatFs(path.getPath());
long internalblockSize = stat.getBlockSize();
long internalblockcounts = stat.getBlockCount();
long internaltotalSize = internalblockSize*internalblockcounts;
String totalStr = Formatter.formatFileSize(this, internaltotalSize);
String RomSpaceInfo = ”可用的内存“+ totalStr;
} return RomSpaceInfo;} @Override public boolean onCreateOptionsMenu(Menu menu){ // Inflate the menu;this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}
28、sharedPreferences入门
->数据存储的API:用##分割用户名和密码的缺陷,真实存
储的话必须要把##转移成其他字符,sharePreferences
(共享参数)提供了一种方便存储数据的方式。
->在data目录下创建了一个xml文件,根节点是map,其实是以map集合来存
储的用户名和密码的对特殊字符进行了转义
package loginsharedPreference.service;
import android.content.Context;import android.content.SharedPreferences;import android.content.SharedPreferences.Editor;
/* * 保存用户名密码的的业务方法 */ public class LoginService { public static void SavaUserInfo(Context context,String username,String passwd){
//拿到上下文之后,有个方法叫getSharedPreferences
SharedPreferences sharedPreferences = context.getSharedPreferences(”config“, Context.MODE_PRIVATE);
Editor editor = sharedPreferences.edit();//得到sharedPreferences的编辑器
}
editor.putString(”username“,username);editor.putString(”passwd“,passwd);//类似于数据库的事物
editor.commit();//当前方法不会存在异常,所以设置为void } package loginsharedPreference;
import java.util.Map;
import loginsharedPreference.service.LoginService;import android.app.Activity;import android.content.SharedPreferences;import android.os.Bundle;import android.text.TextUtils;import android.view.Menu;import android.view.View;import android.widget.CheckBox;import android.widget.EditText;import android.widget.Toast;
import com.example.login.R;
public class MainActivity extends Activity {
private EditText et_number;private EditText et_passwd;private CheckBox cb_remPass;
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);//首先要把页面加载进来然后才有控件的获取
et_number =(EditText)findViewById(R.id.et_number);
et_passwd =(EditText)findViewById(R.id.et_passwd);
cb_remPass =(CheckBox)findViewById(R.id.cb_remPass);
SharedPreferences sharedPreferences = getSharedPreferences(”config“,MODE_PRIVATE);
String username = sharedPreferences.getString(”username“, ”“);
String passwd = sharedPreferences.getString(”passwd“, ”“);
et_number.setText(username);
et_passwd.setText(passwd);
}
@Override public boolean onCreateOptionsMenu(Menu menu){
// Inflate the menu;this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);
return true;} public void login(View v){
String number = et_number.getText().toString().trim();
String passwd = et_passwd.getText().toString().trim();
if(TextUtils.isEmpty(number)||TextUtils.isEmpty(passwd)){
Toast.makeText(this, ”登录名或者密码不能为空“, Toast.LENGTH_SHORT).show();
return;
}else{
if(cb_remPass.isChecked()){
//如果选择了保存用户密码,那么就保存用户密码
LoginService.SavaUserInfo(this,number, passwd);
Toast.makeText(this, ”保存用户信息成功“, Toast.LENGTH_SHORT).show();
}
//登陆发送消息到服务器,服务器验证是否正确
if(”zhangsan“.equals(number)&&”123456“.equals(passwd)){
Toast.makeText(this, ”登陆成功“, Toast.LENGTH_LONG).show();
}else{
Toast.makeText(this, ”登录失败,用户名或者密码不正确“, Toast.LENGTH_LONG).show();
}
} } }
29、xml文件的序列化
->一个小异常:如果没有识别这个设备,重启的话要记得吧adb杀掉->自己手动添加,这种方式效率低,容易出错->XmlSerializer:XML序列化生成器
30、采用pull解析xml文件
->用于对象的持久化,将对象写到硬盘中,需要用的时候再反序列化取出来。
所谓序列化其实就是将程序中的数据(对象)通过某种方式,保存到本地中。然后可以在程序关闭之后还保存程序的某个执行状态,方便在程序下次
执行的时候通过”反序列化“读取出来,并且能够还原数据的类型,从而延续程序退出时的状态。
一般来说,我们会使用序列化保存一些需要持久化的数据,当然如果这个数据会比较庞大的话,我们就直接使用数据库了!所以,序列化实际上目前很多领域用的已经不多了,大部分使用 都已被数据库替代了!
序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStrea
->xml文件的解析方式:
->DOM一次将XML文件加载进内存,生成树状结构,在内存中对树状结构进
行操作,缺点是消耗内存大,->SAX解析:基于事件的方式,自上而下,事件下去了就不能解析了,优点
是速度快,效率高,缺点是不能倒退;
->android下增加了一种解析xml文件的方式,pull解析,类似于SAX解析,定义了一个指针,指向了文档的开头,得到指针,一个tag一个tag的解析下去
->利用类加载器走到文件->创建一个解析器:pullParse0
具体代码:
(MainActivity.java)package com.example.xml;
import java.util.List;
import org.w3c.dom.Text;
import com.example.xml.domain.WeatherInfo;import com.example.xml.service.WeatherService;
import android.support.v7.app.ActionBarActivity;import android.support.v7.app.ActionBar;import android.support.v4.app.Fragment;import android.app.Activity;import android.os.Bundle;import android.view.LayoutInflater;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;import android.os.Build;
public class MainActivity extends Activity {
@Override protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv =(TextView)findViewById(R.id.tv);
List weatherInfos = WeatherService.getWeatherInfos(MainActivity.class.getClassLoader().getResourceAsStream(”weather.xml“));
StringBuilder sb = new StringBuilder();
for(WeatherInfo info:weatherInfos){
sb.append(info.toString()+”n“);
}
tv.setText(sb.toString());}
@Override public boolean onCreateOptionsMenu(Menu menu){
// Inflate the menu;this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);
return true;} }
(WeatherInfo.java)/** * */ package com.example.xml.domain;
import android.R.integer;/** * @author yonghen * */ public class WeatherInfo { private int id;private String name;private String wind;private String weather;private String temp;private String pm;/*(non-Javadoc)* @see java.lang.Object#toString()*/ @Override public String toString(){
return ”WeatherInfos [id=“ + id + ”, name=“ + name + ”, wind=“ + wind
+ ”, weather=“ + weather + ”, temp=“ + temp + ”, pm=“ + pm
+ ”]“;}
/** * @param id * @param name * @param wind * @param weather
* @param temp * @param pm */ public WeatherInfo(){ super();} public WeatherInfo(int id, String name, String wind, String weather,String temp, String pm){ super();this.id = id;this.name = name;this.wind = wind;this.weather = weather;this.temp = temp;this.pm = pm;} /** * @return the id */ public int getId(){ return id;} /** * @param id the id to set */ public void setId(int id){ this.id = id;} /** * @return the name */ public String getName(){ return name;} /** * @param name the name to set */ public void setName(String name){ this.name = name;} /** * @return the wind */
public String getWind(){ return wind;} /** * @param wind the wind to set */ public void setWind(String wind){ this.wind = wind;} /** * @return the weather */ public String getWeather(){ return weather;} /** * @param weather the weather to set */ public void setWeather(String weather){ this.weather = weather;} /** * @return the temp */ public String getTemp(){ return temp;} /** * @param temp the temp to set */ public void setTemp(String temp){ this.temp = temp;} /** * @return the pm */ public String getPm(){ return pm;} /** * @param pm the pm to set */ public void setPm(String pm){ this.pm = pm;
}
}
(WeatherService.java)/** * */ package com.example.xml.service;
import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;import java.util.List;
import org.xmlpull.v1.XmlPullParser;import org.xmlpull.v1.XmlPullParserException;
import android.R.integer;import android.util.Xml;
import com.example.xml.domain.WeatherInfo;/** * @author yonghen * */ public class WeatherService { public static List getWeatherInfos(InputStream inputStream){
XmlPullParser xmlPullParser = Xml.newPullParser();
WeatherInfo weatherInfo = null;
List weatherInfos = null;
try {
xmlPullParser.setInput(inputStream, ”utf-8“);
int type = xmlPullParser.getEventType();//拿到的是当前的事件类型:
while(type!= xmlPullParser.END_DOCUMENT){
switch(type){
case XmlPullParser.START_TAG:
if(”info“.equals(xmlPullParser.getName())){//解析到全局开始的标签
weatherInfos = new ArrayList();
}else if(”city“.equals(xmlPullParser.getName())){
weatherInfo = new WeatherInfo();
String idString = xmlPullParser.getAttributeName(0);
weatherInfo.setId(Integer.parseInt(idString));//字符串转化成整型数据
}else if(”temp“.equals(xmlPullParser.getName())){
String temp = xmlPullParser.nextText();
weatherInfo.setTemp(temp);
}else if(”wind“.equals(xmlPullParser.getName())){
String wind = xmlPullParser.nextText();
weatherInfo.setWind(wind);
}else if(”name“.equals(xmlPullParser.getName())){
String name = xmlPullParser.nextText();
weatherInfo.setName(name);
}else if(”weather“.equals(xmlPullParser.getName())){
String weather = xmlPullParser.nextText();
weatherInfo.setName(weather);
}else if(”pm“.equals(xmlPullParser.getName())){
String pm = xmlPullParser.nextText();
weatherInfo.setPm(pm);
}
break;
case XmlPullParser.END_TAG:
if(”city“.equals(xmlPullParser.getName())){
weatherInfos.add(weatherInfo);
weatherInfo=null;
}
break;
}
type = xmlPullParser.next();
}
} catch(XmlPullParserException e){
// TODO Auto-generated catch block
e.printStackTrace();
} catch(IOException e){
// TODO Auto-generated catch block
e.printStackTrace();
}
return weatherInfos;} }(Weather.xml)
20/30
5月20日 多云转晴
南风3-4
上海
200
20/30
5月19日 多云转晴
南风3-4
上海
200
20/30
5月18日 多云转晴
南风3-4
上海
200
20/30
5月17日 多云转晴
南风3-4
上海
200
31、采用断点调试的方法观察pull解析的的流程
->现在代码双单击添加断点
->debug as Android Application->然后打开调试视图
32、android下创建一个sqllite数据库
->SQLiteOpenHelper(数据库大概帮助类):数据库创建和打开的帮助类->
->PersonSQLiteOpenHelper.java /** * */ package com.example.sqlite;
import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteDatabase.CursorFactory;import android.database.sqlite.SQLiteOpenHelper;/** * @author yonghen * */ public class PersonSQLiteHelper extends SQLiteOpenHelper {
/**
* @数据库的构造方法,用来定义数据库的名称,数据库查询的结果集,数据库的版本 */ public PersonSQLiteHelper(Context context){//Context:上下文告诉数据库存放在什么位置,String name:数据库名,factory一般为null,设置系统默认的游标工厂,super(context, ”Person.db“, null, 1);
} /* * 数据库第一次被创建的时候调用的方法,db创建的数据库 */ @Override public void onCreate(SQLiteDatabase db){
db.execSQL(”create table person id integer primary antoincrement,name varchar(20),number varchar(20)");//底层存储类型都是String,(20)都是给程序员看的,其实没有影响
}
/*(non-Javadoc)* @see android.database.sqlite.SQLiteOpenHelper#onUpgrade(android.database.sqlite.SQLiteDatabase, int, int)*/ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){ } }
->TestPersonDB.java /** * */ package com.example.sqlite;
import android.database.sqlite.SQLiteAbortException;import android.database.sqlite.SQLiteDatabase;import android.test.AndroidTestCase;/** * @author yonghen * */ public class TestPersonDB extends AndroidTestCase { public void testCreateDB(){ PersonSQLiteHelper personSQLiteHelper = new PersonSQLiteHelper(getContext());//new出来一个对象,实际上数据库并未被真正的创建,测试框架提供了一个获取Context的方法
personSQLiteHelper.getWritableDatabase();//数据库才会被真正的创建出来, } }
33、sql语句实现数据库的增删改查
->javaweb:
->加载到jdbc的驱动;//android已经集成在framework->链接到数据库;//只要拿到数据库的引用
->准备sql语句 增删改查
->增加:insert into person(name,number)values('zhang','110')->删除:delete from person where name = 'zhangsan'->修改:update person set number = '119' where name = 'zhangsan'->查找:select * from person->查找具体:select * from person where name = 'zhangsan'
->PersonSQLiteHelper.java /** * */ package com.example.sqlite;
import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteDatabase.CursorFactory;import android.database.sqlite.SQLiteOpenHelper;/** * @author yonghen * */ public class PersonSQLiteHelper extends SQLiteOpenHelper {
/** * @数据库的构造方法,用来定义数据库的名称,数据库查询的结果集,数据库的版本
*/ public PersonSQLiteHelper(Context context){//Context:上下文告诉数据库存放在什么位置,String name:数据库名,factory一般为null,设置系统默认的游标工厂,
结构化面试技巧系列一:即兴演讲必备
一、即兴演讲题含义
含义——又称即席演讲或即时演讲,它相对于命题演讲而言,指演讲者在某种特定的景物或某种特定的人物,气氛的激发下,兴之所至,在事先没有准备或没有充分准备的情况下有感而发的临时性演讲。
二、即兴演讲题测评能力
1.语言表达能力
2.逻辑思维能力
3.自我认知与表达能力
4.自我情绪控制能力
三、即兴演讲题答题技巧
即兴演讲大多数属议论性的。一般的即兴演讲采取的抽签式进行,临时准备时间较短,要在比较短的时间内完整地打腹稿也是非常困难的。于是就必须注意以下几点:
第一,审题
第二,审好题后接下来就是结构布局、层次安排。
第三,设计好开头和结尾。好的开头是成功的一半。
第四,充分运用好支撑观点的材料,即事实论据与理论论据。
河南公务员考试网提醒进行即兴演讲需要多方面的知识素养,又需要敏捷的思维能力,快速的语言表达能力和应变能力。