精华内容
下载资源
问答
  • 元素——答题

    万次阅读 多人点赞 2019-09-19 14:10:44
    元素——答题 微元素每日任务,答题

    微元素——答题

    刺客、奶妈属于微库中的什么子类——职业
    持有哪个装备可以每天收入2000元素币?——圣剑-【塞姆里亚】
    当一个帖子被锁定之后,你不能做的是?——不能回复
    定义帖子标签,多少个能够领奖?——300
    发帖一次最大上传的图片数量是?——99
    发布悬赏帖如何获取更多的元素大神赞助?——价格合理且有充分的描述截图
    关于多关键词搜索的描述正确的是?——【UI】 空格 【科幻】 可以找到 所有科幻题材的UI资源
    购买了失效区的资源,应该怎么办?——自己承担部分损失
    购买了失效区的资源,发举报投诉帖会怎么样?——自己承担部分损失
    购买的资源如果失效不能下载,正确的做法是?——在论坛举报投诉区发帖
    画板订阅任务要求需要订阅多少个画板才能获得奖励?——30个
    胡乱回复被大神扣活跃的规则是?——活跃度越高扣的越多
    胡乱回复被管理扣活跃的规则是? —— 活跃度越高扣的越多
    获取装备【赤铁剑】需要发布多少个主题才能申请购买?——400【土豪金 ≥ 6000】
    据官方投票统计,元素会员最常用的发现新帖方式是?——论坛左上角最新
    进入元素矿场,发现提示“您的矿场已经被外星生物侵占!,请入群咨询”是怎么回事?——没有登录微元素
    “技术文章来两篇”任务怎么样才能够完成并领取任务奖励?——必须在【技术文库】大板块下发两个有内容有意义的技术文章帖
    可以不用回复,就能看到回复可见内容的能力是?——元素神的天眼
    矿场不产出以下哪种材料?——秘银
    【扩散大招】任务究竟该怎么做?——在QQ群发扩散链接+该帖的图,截图发帖在扩散区
    目前活跃度兑换元素币的起步金额是?——2000
    目前土豪金兑换元素币的起步金额是?——1000
    目前新会员的注册方式是?——QQ注册
    满足一定条件后,购买装备【元素之盾】需要消耗什么?—— 8000活跃度【在线时间(小时) ≥ 1200 并且 土豪金 ≥ 3750】
    [每天一早上元素]的下一句是?——挖矿撩妹两不误
    哪些内容是微元素不提倡发布的?——源代码
    哪些用户不是微元素的目标用户群?——同性交友
    哪个等级可以上传视频文件?——元素王
    如果你有一组国外大神画的Q版怪物想分享,应该发布在哪个版块?——怪物军团
    如果你有一组3D怪物的CG图片想分享,应该发在哪个版块?——3D作品中的CG角色
    如果你浏览论坛的时候发现你喜欢的帖子想分类收藏,正确的做法是?——帖子左下角点画板
    如果你在看某个帖子时,你想“私信”楼主,那它的按钮在哪里?——点击帖子里楼主头像下方的信封图标
    如果您发现自己不能上传头像或图片,这说明?——您的浏览器不支持flash,换个浏览器试试看
    如果充值遇到失败的情况,正确的做法是?——联系群主并获得额外补偿
    如果我想练习发帖,正确的做法是?——在[元素口水]练习
    如果我想快速通关元素学堂,学习元素知识,最迅速全面的方法是?——去[网站帮助][赚币方法]阅读指导
    如果我想修改网站登录时的用户名,正确的做法是?——购买道具改名卡
    如果我想要给已经发布的帖子补充新图片,正确的做法是?——编辑帖子 ,插入图片
    如果我忘记了社区规则,比如活跃度兑换规则,想要搜索下重新温习,应该?——搜索 【活跃度】,最简单的关键词
    如果我搜索一个明确的资源 如 【unity第一人称射击操作系统工程】没有想要的结果我应该怎么做?——输入简单的词用空格隔开,如 【unity】 【FPS】
    如果想让更多人在搜索和你帖子内容相关的贴时,能轻易搜索到你的帖子,你可以——添加帖子的标签,尽可能丰富完整
    如果一个帖子的网盘失效了,最简单的做法是?——在举报区发帖,必须带有原帖地址
    如果发错了帖子或发多了相同的重复帖子,该怎么删帖?——在申请区发帖并附上要删的帖子链接
    如果发布的3D模型资源中没有max或maya文件,帖子会被优先移动到——综合模型
    如果对账户名不满意,网站会员该如何正确地修改自己的账户名?——购买改名卡道具并使用
    如何有效增加在线时间?——不断看帖
    我如果完成了某项元素成就,希望获取丰厚的奖励,那么应该?——在申请区发帖-附带成就名称
    任务究竟该怎么做?——在QQ群发扩散链接+该帖的图,截图发帖在扩散区
    热搜排行榜中的词来源为?——元素网用户经常搜索的词
    热搜排行榜页面能显示多少个热搜词?——450
    设置封面的正确做法是?——先插入完成,再鼠标移动到图上设置
    什么可以直接兑换微币?——元素币
    什么样的帖子会被立刻移动到[重复区]——截图展示与之前的一样
    什么样的内容会被移动到【推荐重发】?——展示图的数量和内容不佳,无法判定品质
    申请扩散大招赚币,哪一项是必须的?——个人帖子链接
    神石这个积分是什么?——统计管理员贡献的积分
    搜索结果中,分词的显示底色是什么颜色?——绿色
    搜索结果中,同义词的显示底色是什么颜色?——蓝色
    搜索结果界面右侧的“热搜词”浮动框下面不同颜色区域的是什么词?——推荐词
    “搜索”除了能搜索帖子外,下拉框中还能够选择搜索什么?——微库图片、画板、用户
    收费资源帖内的【销售总额】是指?——楼主的税前总收入
    [首发必发微元素]的下一句是?——荣耀加身装备酷
    失效资源,付费后不能下载的退币时限是?——购买算起的1个月内
    SD专区板块位于以下哪个大版块中?——TA技术美术
    土豪金是因为什么而存在?——元素送给大家的购买返利福利
    推荐的在QQ群内迅速升级并获取奖励的的方法是?——相互交流学习
    微库如何查看按照发布时间来排序的图片?——在微库页面点击“新上传”
    微库一次最大上传的图片数量是?——99
    微库的体力有什么用?——上传图片到微库会扣减体力
    微库总共有多少个一级分类?——16
    【微库】中,关于素材排序的描述正确的是——【关注度】排序是按照用户认可度排序,【新上传】可以看到最新上传的素材
    【微库】微库VIP功能专属特权是哪个?—— 批量下图
    微元素QQ群-超级大群的人数是?——2000人
    微元素5群 群号是多少?——616268846
    微元素-原画QQ群的群号是——575782850
    微元素-新原画QQ群的群号是——674421744
    微元素 平面设计/影视后期 交流群的群号是?——727880933
    微元素TA技术美术QQ群的群号是——318958005
    微元素 地编 SD技术QQ群的群号是?——782480353
    微元素官方群,等级最低的头衔是?——虚灵
    微元素官方的微信公众帐号全名是?——微元素CG
    微元素qq注册登录的初始密码是什么?——没有初始密码,就是空的,要重置后才有
    微币有什么作用?——能消耗它观看并下载微库的高清图片
    网站平时说的“私信”,它的按钮在哪里?——头像下方的信封图标
    网站如果被黑客攻击,无法正常访问,我需要做的事情是?——静静的等待并祈祷
    为什么有时候帖子发了,但是自己查看时却发现帖子正在审核无法查看呢?——部分板块有发帖人工审核,通过时间不定
    为什么新的头像上传了,但是头像却没有变化?——需要刷新页面的缓存才能看到新头像
    为什么兑换的申请贴完成后,总积分有时候会下降?——因为土豪金的积分计算是×12的而元素币的积分计算是×1的
    完成成就后?如何获得到丰厚奖励?——在申请区发帖
    元素扩散大招是指?——把群扩散截图等信息发到扩散者专区
    元素神的文字颜色是?——绿色
    元素导航中的[最新]页面,会显示最新的多少张帖子?——1000
    元素左上角的常用菜单导航中进去的【最新】页面,会显示最新的多少张帖子?——1000
    元素没有出现过以下哪个培训机构的广告?——水晶石
    元素王的下一个等级是?——元素皇
    元素王的上一个等级是?——元素魔
    元素鼓励师主要负责哪些事情?——为好的帖子或回复加分
    元素社区内的大神是指?——网站版主
    元素装备有什么作用?——酷炫装逼
    元素悬赏时间到了,也没有满意的答案,该怎么撤销?——在申请区发申请撤销悬赏任务的帖子
    元素画板目前可以选择的分类是多少个?——14
    [元素帖子强]的下一句是?——满满正能量
    【元素搜索】时,怎样的技巧能获取更多结果?——尽可能简单的一个词
    【元素搜索】有怎样的独家特点?—专业领域的同义词智能匹配
    【元素搜索】时,怎样把符合多个条件的帖子筛选出来?——多个词之间用空格隔开
    “游戏资讯来两篇”任务怎么样才能够完成并领取任务奖励?——必须在【游戏新闻】板块下发两个有内容有意义的游戏新闻帖
    原创作品中,新人的诚意制作,功底和制作技巧较浅,缺乏细节和完成度,可被评定为什么等级?——【青铜】
    原创作品中,大神级巅峰的完美杰作,在全球范围内都堪称经典神作,可被评定为什么等级?——【钻石】
    原创作品中,水准可以到达主流商业水平标准可被评定为什么等级?——【黄金】
    用什么图片作为封面最佳而且不会被管理员扣分或移出版块?——资源里最漂亮的画面的截图
    拥有12个首发资源帖才可以申请的装备是?——圣杖-【安东尼达斯】【元素币 ≥ 50000 并且 首发 ≥ 12】
    拥有50件元素装备才可以申请的装备是?——女皇之泪

    【装备】持有什么装备可以每天都获得一定的土豪金?—— 盾系列装备
    【装备】持有什么装备可以每天都获得一定的贡献值?—— 杖系列装备
    如果发布的3D模型资源中没有max、maya源文件、OBJ、FBX等文件,帖子会被优先移动到—— 综合模型
    【装备】需要满足账号已经注册一定天数后才能申请购买获得的装备是?—— 战甲系列装备
    在[申请区]可以申请的是哪种?—— 兑换活跃度
    发布完整规格的帖子时,设置付费信息应该放在?—— 帖子最顶部
    【装备】购买什么系列的装备需要消耗的是活跃度?—— 盾系列装备
    发帖获取网站顶部推荐的决定性因素是?—— 管理员喜好
    因为网络卡顿造成一个资源的重复购买,我应该怎么做?——在举报区发帖并附上重复购买的资源贴的链接

    新注册的号,用户名中有[qq]开头字样的,因为是?——QQ昵称与网站某个会员的用户名相同,名字已被占用。

    想查看自己购买过的帖子记录,最快捷的方法是?——导航-个人中心-购买记录

    悬赏帖发布多少日之后,大神可以帮助帖主选择正确答案?——5
    以下哪种方式可获取网站板块的畅下权限?——成为元素大神
    以下那种积分可以转换为元素币?——活跃度
    以下哪种行为会被扣积分呢?——活动贴内无意义回复
    以下哪种操作可能降低你的积分等级?——兑换土豪金为元素币
    以下哪个区要求持有一定数量的元素币才能进入?——解剖结构
    以下哪个因素会影响搜索排名?——帖子被查看的数量
    以下哪个因素不会影响你的元素积分?——扩散
    以下哪个是教程专区版块的分类名称?——技术文库
    以下哪个是2D资源版块的分类名称——场景资源
    以下哪个是3D模型版块的分类名称?——原创角色
    以下哪个是元素比其他游戏CG网站独创的内容——联想搜索
    以下哪个管理是元素真女神?——沐语橙风
    以下哪个管理不是元素真女神——小小小芳
    以下哪个不是每天都可以做的任务?——参与活动
    以下哪个版块的封面不是正方形?——游戏研发中的插件资源版块
    以下哪个页面链接能看到元素历代顶部推荐集合?——元素推荐
    以下哪一个是元素徽章——感动
    以下哪一条不是微元素的业内首创?——真实交友
    以下哪些是元素禁发的内容?——WebEasy游戏
    以下可以开启充值双倍buff的日子是?——十一月十一
    以下什么样的封面是不合格的,会被移区?——文件夹内容截图当封面
    元素资源专区有多少个大版块?——12
    元素出售资源的交易税是多少?——所有人都是20%
    元素原创艺术版块的美术作品排位有几个等级?——5
    元素矿场一共有几种矿石?——活动时增加
    元素矿场每月什么时间会销毁一颗星球——每个月的24号
    元素矿场每月随机一爆在哪几个星球中选择——所有星球随机选择
    元素挖矿:星球爆炸的条件是?——总量低于2%
    元素挖矿:升级房子的主要目的是——爆炸前有地方安置
    元素挖矿:哪种矿物质最便宜——煤矿
    元素活动:如果在要求回复的活动下面灌水会?——被扣活跃度
    元素活动:如果在要求回复的活动下面灌水会?——被扣积分
    元素预售达成发放下载地址的步骤是?——有xx人购买帖子内容后,再开放下载地址
    元素帖子页面,最大能显出的图片宽度是?——1440
    元素网目前可以上传最大多大的视频?——200M
    装备【龙枪】的获取条件是?——精华16 【精华帖数 ≥ 16 300 贡献值】
    装备[深渊]的获取条件是?——精华50

    在[申请区]能申请的是以下哪种?——兑换土豪金
    在搜索结果中把鼠标移动到帖子封面上显示最多时只能看到以下的什么内容?——标签和同义都有
    在元素怎么申请首发资源并获得独家推荐?——在申请区发帖附首发贴的链接
    在同一天内,花费总计1W元素币可以申请获得的装备是?——满天星
    在同一天内,花费总计1W元素币可以申请的成就是?——挥洒自如
    在同一天内,连续发布30个有效资源帖子可以申请的成就是?——暴走连击
    在同一天内,连续发布30个有效资源帖子可以申请获得的装备是?——散夜对剑
    在悬赏活动中,非参与的回复会被扣分,但是想发表自己的看法或者建议应该怎么办?——帖子左下角评分表达
    在PC上,点击头像后进入的页面是?——个人首页
    在哪个区发帖,需要有正确的分类信息?——Unity插件
    在以下哪个区,非认真参与者且随意回复的话会被扣除大量活跃度?——【悬赏活动】
    在PSD原画区发布资源,不展示哪种资源细节将会被移出该板块?——PSD分层
    怎样的购买方式会返还土豪金?——购买支付框模式会返还
    怎么样的画板不会出现在画板首页,也不会被推荐?——没有封面
    转载帖子,以下那种行为可能会被扣分?——没有使用正确的文字底色
    转载文章时,复制过来的文字背景颜色错误,快速修正的方法是?——刷子工具
    资源板块首页 顶部[主题]后面的第一个橙色数字是?——今天发布的新帖子数
    2D资源中的【角色资源】指的是?——能直接在游戏中使用的如角色序列,像素角色等素材
    以下哪个是原画插画版块的分类名称?—— 精美壁纸
    原画插画区下面有几个[子区]分类?——16
    元素矿场,矿长有多少个等级?——24
    元素矿场总共有几个矿场成就?——7
    元素晋级会员组总共有几个等级?——10
    【交易】购买别人的资源就会增加土豪金,转化比例是——10%
    元素帖子页面,最大能显出的图片宽度是?——1440
    发布哪种类型的帖子并不会被移动到[综合分享]?——价格不合理
    【搜索】顶部导航栏的“排行”默认打开是什么榜单?—— 热搜词榜单
    【举报】发举报帖举报用脚本外挂刷分行为的人,管理确认有效的,最低将能得到多少奖励?——2000元素币
    【搜索】搜索界面右侧的“热搜词”浮动框中会随机显示多少个全站前300的热搜词?——20
    【界面】如果你在看某个帖子时,你想“私信”楼主,那它的按钮在哪里?—— 点击帖子里楼主头像下方的信封图标
    装备【深渊】的获取条件是?—— 精华50
    导航中的购买记录可看到记录是?—— 我买其它人资源的记录
    2D资源中的【角色资源】是指?—— 能直接在游戏中使用的如角色序列,像素角色等素材
    新注册的号,用户名中有【qq_】开头字样的,因为是?——QQ昵称与网站某个会员的用户名相同,名字已被占用
    把售价50+元素币的普通帖升级为精华帖的条件是?—— 出售次数50
    把售价200+元素币的普通帖升级为精华帖的条件是?—— 出售次数30
    把售价500+元素币的普通帖升级为精华帖的条件是?—— 出售次数20
    把售价1000+元素币的普通帖升级为精华帖的条件是?—— 出售次数10
    把售价2000+元素币的普通帖升级为精华帖的条件是?—— 出售次数5
    把售价5000+元素币的普通帖升级为精华帖的条件是?—— 出售次数3
    编辑器板块位于以下哪个大版块中?——TA技术美术
    关于做【技术文章】任务以下说法正确的是?—— 做【技术文章】任务只能在技术文章大板块下发技术文章
    【任务】第一次完成“我的推荐任务”奖励多少元素币?——200
    【任务】画板订阅任务要求需要订阅多少个画板才能获得奖励?——30
    关于【悬赏活动】 正确的说法是?—— 每个认真参与者都可以获得对应奖励
    【标签】定义帖子标签,多少个能够领奖?——300
    什么样的内容会被移动到【推荐重发】?—— 展示图的数量和内容不佳,无法判定品质
    【装备】持有装备【圣剑系列】挂机可获取的元素币上限是多少?——100万元素币
    想查看自己购买过的帖子记录,最快捷的方法是?—— 导航-个人中心-购买记录
    元素QQ群的主要功能是? —— 学习
    关于违规内容的处理,以下说法正确的是 —— 违规内容会移动到其他版块,进行屏蔽处理
    关于发布的没有角色面部资源的问题,哪项说法是正确的?—— 没有角色头部的摄影或者绘画全部定义为违规内容处理
    如果我是萌新想练习发帖,正确的做法是? ——在【发帖练习】板块练习
    关于元素头像上传,2020年情况,说法正确的是 —— 头像只能上传静态的正方形状图片,GIF动态头像已经是绝版
    关于发任务帖赚取元素币或积分,以下哪项说法是正确的? —— 发布任务帖要注意用刷子工具清理错误格式,再设置规范的封面
    【题目】 关于发布的没有角色面部资源的问题,哪项说法是正确的? —— 没有角色头部的摄影或者绘画全部定义为违规内容处理
    悬赏帖发布多少日之后,管理员可以帮助帖主选择正确答案? —— 5
    关于元素装备,以下说法正确的是? —— 部分装备会不断增加某种积分,例如元素币、贡献值、活跃度或土豪金,如果会员已经持有量超过说明中的最大值,则不继续增加
    在2019年,元素搜索中最高频率出现的词是什么 —— 场景
    在画板封面左上角的橙色数字代表 —— 关注人数
    画板左上角的数字代表什么 —— 关注人数
    最新的元素首页分为三种主色,以下说法正确的是 —— 元素首页三种颜色分别代表了,蓝色资源,橙色技术,绿色原创
    查看自己帖子收入情况以下哪种说法是正确的 —— 在搜索中搜索【我的收入】或者【帖子收入】
    关于【微库识图】以下说法正确的是? —— 微库识图可以通过上传图片的配色,构图,主体内容来以图找图
    以下哪种做悬赏的方式,是可以安全获得全场最佳的 —— 资源类必须有下载地址或元素帖子,但设置付费外人不可见,并私发给楼主
    如果星球的周期产量远远低于正在挖矿的人数,那么会发生什么? —— 大家谁都挖不到
    【微库】把贴内图片采集到微库的正确方式是? —— 鼠标移动到贴内图片上,点击【采集到微库】
    打开2个窗口,从帖内【拖动到微库】界面 右键保存再【上传到微库】任意类型 鼠标移动到贴内图片上,点击【采集到微库】 在系统工具中开启【采集到微库】的辅助工具
    在资源专区/3D作品/CG角色 内发布的帖子应该是那种资源 —— 只是图片资源,图片的内容仅为3D高模角色参考图
    【分区】在资源专区/3D作品/CG角色 内发布的帖子应该是那种资源 —— 一般的3D模型软件打开的高模3D角色或3D场景 参考图片 或 渲染图片
    在资源专区/3D作品/游戏模型 内发布的帖子应该是那种资源 —— 只是图片资源,图片的内容仅为3D低模游戏角色参考图
    在资源专区/3D作品/游戏模型展示 内发布的帖子应该为只是图片资源,图片的内容仅为3D低模游戏角色参考图或渲染图
    2020积分改革后,在线时间对总积分的影响是——在线时间的权重变成了 X 10
    2020-6月-元素新开了一个等级叫?—— 元素大神
    在资源专区/3D模型/CG模型 内发布的帖子应该是那种资源?—— 一般的3D模型软件打开的高模3D角色或3D场景
    【神器】轩辕剑的获取条件是 —— 有一个正规资源贴的销售量达到50W元素币
    蚩尤斧的获取条件是 —— 有10个超过10W元素币的帖子!
    以下哪一条属于元素群文化?—— 谨慎交友,禁止搞基
    【积分】活跃度100%领取以下哪些条件是必备的? ———— 答案是:合适合规的论坛头像
    天眼是不用回复就能看到需要强行回复的内容,现在是什么等级的用户组可以获得?
    —— 元素王
    以下对装备特性描述正确的是? —— 装备有最大上限,超过上限后,需要花费后,才能继续增长增长
    在一天内连续发布的5个帖子,在发布后的当天内销量都超过500元素币 —— 散夜对剑
    在一天内连续发布价格超过500元素币的5个有效资源帖子可以申请获得的装备是? —— 散夜对剑
    关于查看自己帖子收入情况,以下说法正确的是? —— 页面顶部的【积分】按钮,积分-【积分记录】-【收入】
    【微库】关于微库采集或上传到正确分类,正确的做法是 —— 采集中的输入框先输入相关的分类关键词,选择与图片符合的分类,再采集
    【题目】 关于【炸弹题】以下说法正确的是? —— 炸弹题是为了判断是否使用外挂答题,监控答题100%正确的人
    装备的【负载值】指的是?——当超过武器等级设定的积分持有上限后,用户还可以稳定获得【负载值】设定带来的增益 C、提醒用户赶紧买更多装备
    转载其它网站的帖子,以下那种行为可能会被扣分?—— 没有使用刷子工具改正成正确的文字底色
    2021年
    翡翠碎片获取的条件是 —— 收入榜单,在本月内进入前六

    紫棠碎片获取的条件是 —— 发帖榜单,在本周内进入前六

    冰青碎片获取的条件是 —— 消费榜单,在本周内进入前六

    赤虹碎片获取的条件是?—— 热销榜单,在本月内进入前五

    蔚蓝碎片获取的条件是?—— 热销榜单,在本周内进入前五!

    绯红碎片获取的条件是 —— 收入榜单,在本周内进入前六

    铭黄碎片获取的条件是 —— 发帖榜单,在本月内进入前六

    碧绿碎片获取的条件是 —— 消费榜单,在本月内进入前六

    炫彩碎片获取的条件是 —— 销量榜单,在本月内进入前五
    我被其他人关注,可以获得什么系列的装备?----吉他
    史莱姆是和什么相关的装备—在特殊分类内规范发布相关帖子
    完全100%兑换活跃度的需要智慧的条件是?——持有智慧积分大于50
    以下哪种做悬赏的行为是无效,即使获取奖励也会被扣回 —— 有人发悬赏,我直接把正确答案私发给了他,他给了我最佳
    元素碎片一共有几块? —— 9
    下面哪些数据是有排行榜的? —— 智慧
    下面哪些积分可以自己在积分面板兑换为元素币 —— 智慧
    以下关于同义词搜索正确的说法是 —— 元素搜索可以搜到同义词,但是排名不高
    勾玉系列的装备该怎么获取?——建设元素微库
    通过参与WK建设活动,可以获得哪个系列的装备?——可以获得勾玉系列装备!
    WK中VIP批量下载,一次最多下载多少图,描述正确的是? ——一次可以下载一整页
    中性回复不能算有意义的回复,以下哪种回复是没有诚意的中性刷回复? ——很有礼貌的谢谢楼主,并表示出自己对楼主的敬仰
    【每周大放送】可以得到什么?——白嫖资源跟元素币
    【题目】通过冲击排行榜,名列前茅,可以获得哪个系列的装备?——碎片
    WK是什么意思?—微库
    通过发布原创高品质资源,可以获得哪个系列的装备?——龙珠
    需要满足下面那些条件可以免费获得【每周大放送】的资源? ——关注微元素官方微信公众号,在公众号内回复关键字
    以下哪种方式获取智慧是属于刷分,会被处罚? —— 多处自己胡乱回答,然后自己疯狂点赞
    【每周大放送】帖子,一般会在周几发布?——周二
    【题目】 以下哪种情况的发帖会被判定为重复的? ——原贴太贵了,我发了一套一样但更便宜的
    可自助领取成就装备的系统叫做? —— 科技实验室
    以下哪种方式可以快速找到自己购买资源的记录? ——直接搜索【购买记录】
    【题目】关于资源中存在Max病毒,以下说法正确的是?——发布病毒资源的发布者会受到十分严重的处罚
    【创作】元素原创艺术版块的美术作品排位有几个等级? —— 5
    【地图编辑】板块位于以下哪个大版块中?——TA技术美术
    关于积分兑换,以下哪种说法是正确的 —— 在设置/积分界面,可以自己兑换智慧和土豪金,且多次后有额外奖励
    【原创】原创右侧加技能点的点数是几个?
    7个技能点
    【原创】原创区右侧的可加技能点共有多少个选项?
    13个
    【知识】关于元素【勇士工会】以下哪个说法是正确的?
    勇士工会多数是有挑战的高难度高回报任务
    【原创】关于原创哪些说法是不正确的
    发帖时如果选择原创,那么必须是我本人的创作,否则会被删除
    【原创】关于盖楼的意义,以下说法正确的是?
    只有作者本人可盖楼,用来系列更新,拆解过程等用途
    【问答】关于问答中的回答哪些说法正确?
    只能给最正确的答案点赞,否则是无效点赞
    【题目】 【装备】关于有些区不能进入的说法,以下哪些是正确的
    一般情况下,需要【长枪】才能进入,长枪需要精华1
    【题目】 【送分】以下哪种上网方式可能导致不能访问微元素?
    使用科学上网挂了梯子
    感谢大家提供!

    展开全文
  • Android开发艺术探索——一章:Activity的生命周期和启动模式 怀着无比崇敬的心情翻开了这本书,路漫漫其修远兮,程序人生,为自己加油! 一.序 作为这本书的一章,主席还是把Activity搬上来了,也确实,和...

    Android开发艺术探索笔记——第一章:Activity的生命周期和启动模式


    怀着无比崇敬的心情翻开了这本书,路漫漫其修远兮,程序人生,为自己加油!

    一.序

    作为这本书的第一章,主席还是把Activity搬上来了,也确实,和Activity打交道的次数基本上是最多的,而且他的内容和知识点也是很多的,非常值得我们优先把他掌握,Activity中文翻译过来就是”活动”的意思,但是主席觉得这样翻译有些生硬,直接翻译成“界面”可能更好,的确,Activity主要也是用于UI效果的呈现,不过两者翻译都不为过,我们知其意就行了,正常情况下,我们除了Window,Dialog,Toast,我们还能见到的就只有Activity了,他需要setContentView()去绑定一个视图View作为效果的呈现,然而,作为一本高质量的进阶书。肯定不会去围绕着入门知识讲解,本章的侧重点在于对Activity使用过程中搞不清楚的概念,生命周期和启动模式已经IntentFilter的匹配规则分析,毕竟Activity在异常状态下的生命周期是多样化的,至于Activity的启动模式和各种各样的Flags,更是让很多人摸不着头脑,还有隐式启动Activity中也有着复杂的Intent匹配过程,所以我们还是一步步的去学习下去,真正的了解Activity这个小家伙!

    二.Activity的生命周期全面分析

    Activity的生命周期,本章主要讲解两个方面

    • 典型情况下的生命周期
    • 异常情况下的生命周期

    典型情况是指用户参与的情况下,Activity所经过的生命周期的变化,异常情况下的话,就有多种可能了,比如系统回收或者由于当前设备的Configuration发生改变从而导致Activity被销毁重建,异常情况下的生命周期的关注点和典型情况下有些不同,所以要分开来描述才能描述的清楚些

    1.典型情况下的生命周期分析

    在正常的情况下,生命周期会经历以下的生命周期

    • onCreate:表示Activity正在被创建,这是生命周期的第一个方法,在这个方法中,我们可以做一些初始化的工作,比如调用onContentView去加载界面布局资源,初始化Activity所需数据等

    • onRestart:表示Activity正在重新启动,一般情况下,当当前Activity从不可见重新变为可见时,onRestart就会被调用,这总情况一般是用户行为所导致的,比如用户按home键切换到桌面或者用户打开了一个新的Activity,这时当前的Activity就会被暂停,也就是onPause和onStop方法被执行了,接着用户又回到了这个Activity,就会出现这种情况

    • onStart:表示Activity正在被启动,即将开始,这个时候Activity已经可见了,但是还没有出现在前台,还无法和用户交互,这个时候我们可以理解为Activity已经启动了,但是我们还没有看见

    • onResume:表示Activity已经可见了,并且出现在前台,并开始活动了,要注意这个和onStart的对比,这两个都表示Activity已经可见了,但是onStart的时候Activity还处于后台,onResume的时候Activity才显示到前台

    • onPause:表示Activity正在停止,正常情况下,紧接着onStop就会被调用,在特殊情况下,如果这个时候再快速的回到当前Activity,那么onResume就会被调用,主席的理解是这个情况比较极端,用户操作很难重现这个场景,此时可以做一些数据存储,停止动画等工作,但是注意不要太耗时了,因为这样会影响到新的Activity的显示,onPause必须先执行完,新Activity的onResume才会执行

    • onStop:表示Activity即将停止,同样可以做一些轻量级的资源回收,但是不要太耗时了

    • onDestroy:表示Activity即将被销毁,这是Activity生命周期的最后一个回调,在这里我们可以做一些最后的回收工作和资源释放

    正常情况下,Activity的常用生命周期用官网的一张图就足够表示了

    这里写图片描述

    这里附加几个说明

    • 1.针对一个特定的Activity,第一次启动,回调如下:onCreate ——> onStart ——> onResume

    • 2.当用户打开新的Activity或者切换到桌面的时候,回调如下:onPause ——> onStop ——> 这里有一种特殊的情况就是,如果新的Activity采取了透明的主题的话,那么当前Activity不会回调onStop

    • 3.当用户再次回到原来的Activity,回调如下:onRestart ——> onStart ——> onResume

    • 4.d当用户按back键的时候回调如下:onPause ———> onStop ——> onDestroy

    • 5.当Activity被系统回收的时候再次打开,生命周期回调方法和1是一样的,但是你要注意一下就是只是生命周期一样,不代表所有的进程都是一样的,这个问题等下回详细分析

    • 6.从整个生命周期来说,onCreate和onDestroy是配套的,分别标示着Activity的创建和销毁,并且只可能有一次调用,从Activity是否可见来说,onStart和onStop是配套的,随着用户的操作和设备屏幕的点亮和熄灭,这两个方法可能被调用多次,从Activity是否在前台来说,onResume和onPause是配套的,随着用户操作或者设备的点亮和熄灭,这两个方法可能被多次调用

    这里提出两个问题

    • 1.onStart和onResume,onPause和onStop从描述上都差不多,对我们来说有什么实质性的不同呢?
    • 2.假设当前Activity为A,如果用户打开了一个新的Activity为B,那么B的onResume和A的onPause谁先执行尼?

    我们先来回答第一个问题,从实际使用过程来说, onStart和onResume,onPause和onStop看起来的确差不多,甚至我们可以只保留其中的一对,比如只保留onStart和onStop,既然如此,那为什么Android系统还会提供看起来重复的接口呢?根据上面的分析,我们知道,这两个配对的回调分别代表不同的意义,onStart和onStop是从Activity是否可见这个角度来回调的,除了这种区别,在实际的使用中,没有其他明显的区别

    第二个问题,我们就要从源码的角度来分析以及得到解释了,关于Activity的工作原理会在本书后续章节进行讲解,这里我们大致的了解即可,从Activity的启动过程来看,我们来看一下系统的源码,Activity启动过程的源码相当复杂,设计到了Instrumentation,Activit和ActivityManagerService(AMS),这里不详细分析这一过程,简单理解,启动Activity的请求会由 Instrumentation 来处理,然后他通过Binder向AMS发请求,AMS内部维护着一个ActivityStack,并负责栈内的Activity的状态同步,AMS通过ActivityThread去同步Activity的状态从而完成生命周期方法的调用,在ActivityStack中的resumeTopActivityLnnerLocked方法中,有这么这段代码

    
            //we need to start pausing the current activity so the top one can be resumed
            boolean dontWaitForPause = (next.info.flags& ActivityInfo.FLAG_RESUME_WHILE_PAUSING)!=0;
            boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, KeyStore.TrustedCertificateEntry,dontWaitForPause);
            if(mResumedActivity != null){
                pausing != startPaUSINGlOCAKED(userLeaving,false,true,dontWaitForPause);
                if(DEBUG_STATES){
                    Slog.d(TAG,"resumeTopActivityLocked:pausing" + mResumedActivity);
                }
            }

    从上述的代码中我们可以看出,在新Activity启动之前,栈顶的Activity需要先onPause后,新的Activity才能启动,最终,在ActvityStackSupervisor中的realStartActivityLocked方法中,会调用如下代码

    app.thread.scheduleLaunchActivity(new Intent(r.intent),r.appToken,System.identityHashCode(r),r.info,new Configuration(mService.mConfiguration)
            ,r.compat,r.task.voiceInteractor,app.repProcState,r.icicle,r.persistentState,results,new Intents,!andResume,mService.isNextTransitionForward()
            ,profilerInfo);

    我们都知道,在这个app.thread的类型是IApplicationThread的具体实现实在ActivityTread中,所以,这段代码实际上遇到了ActivityThread当中,,即ApplicationThread的scheduleLaunchActivity方法,而scheduleLaunchActivity方法最终会完成生命周期的调用过程,因此可以得出结论,是旧Activity县onPause,然后新的Activityy再启动

    至于ApplicationThread的scheduleLaunchActivity方法为什么会完成新Activity的生命周期,请看接下来的代码,scheduleLaunchActivty为什么会完成新的Activty

    private void handlerLaunchActivity(ActivityClientRecord r, Intent customIntent){
    
            //if we are getting ready to gc after going to the background,well we are back active so skip it
            unscheduleGcIdler();
            mSomeActivitiesChanged =true;
            if(r.profilerInfo != null){
                mProfiler.setProfiler(r.profilerInfo);
                mProfiler.startProfiling;
            }
            //Make sure we are running with the most recent config
            handlerConfigurationChanged(null,null);
    
            if(localLOGV)Slog.v
                        TAG,"Handling launch of"+r);
    
            //在这里新Activity被创建出来,其onCreate和onStart被调用
            Activity a = PerformLaunchActivity(r,customIntent);
    
            if(a != null){
                r.createdConfig = new Configuration(mConfiguration);
                Bundle oldState = r.start;
                handlerResumeActivity(r.token,false,r.isForward,
                        !r.activity.mFinished && r.startsNotResumed);
            }
            //省略...
        }
    

    c从上面的分析可以看出,当新的Activity启动的时候,旧的Activity的onPause方法会先执行,然后才启动新的Activity,到底是不是这样尼?我们可以写一个小栗子来验证一下,如下是两个Activity的代码,在MainActivity中点击按钮可以跳转到SecondActivity,同时为了分析生命周期,我们把log日志也打出来

    MainActivity

    package com.liuguilin.activitysample;
    
    import android.content.Intent;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.View;
    
    public class MainActivity extends AppCompatActivity {
    
        public static final String TAG = "MainActivity";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            findViewById(R.id.btnTo).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    startActivity(new Intent(MainActivity.this, SecondActivity.class));
                }
            });
    
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            Log.i(TAG, "onPause");
        }
    
        @Override
        protected void onStop() {
            super.onStop();
            Log.i(TAG, "onStop");
        }
    }
    

    SecondActivity

    package com.liuguilin.activitysample;
    
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    
    /**
     * Created by lgl on 16/8/24.
     */
    public class SecondActivity extends AppCompatActivity {
    
        private static final String TAG = "SecondActivity";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_second);
            Log.i(TAG, "onCreate");
        }
    
        @Override
        protected void onStart() {
            super.onStart();
            Log.i(TAG, "onStart");
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            Log.i(TAG, "onResume");
        }
    }
    
    

    这样我们可以观察到他的生命周期

    这里写图片描述

    通过这个生命周期我们可以观察到,旧的Activity的onPause先调用,然后新的Activity才启动,这也证实了我们上面的分析原理,也许有人问,你只是分析了Andorid5.0的源码,你怎么所有的版本源码逻辑都相同,的确,我们不能把所有的版本都概括,但是作为Android的一个运行过程的基本逻辑,随着版本的更新并不会很大的改变,因为Android也需要兼容性,,不能说在同一个版本上运行有两种不同的逻辑,那根本不可能,关于这一点,我们要把握一个度,就是对于Android的基本运行机制,的不同,Android不能在onPause中做重量级的操作,因为必须在onPause执行完成以后新的Activity才能Resume,从这一点我们也间接性的证明了我们的结论,通过分析这个问题,我们知道onPause和onStop都不能做耗时的操作,尤其是onPause,这也意味着,我们应当尽量的在onStop中做操作,从而使新的Activity尽快显示出来并且换到前后台

    三.异常情况下的生命周期分析

    上一节我们分析的是正常事情下的生命周期,但是我们写程序也不要理想化,居多的问题就是出在异常情况下,我们知道,Activity除了受用户操作导致的正常生命周期的调度,同时还会存在一些异常的情况,比如当资源相关的系统配置发生改变以及系统内存不足的时候,Activity就有可能被杀死,下面我们具体来分析下这几种情况

    1.情况1:资源相关的系统配置发生改变导致Activity被杀死并重新创建

    理解这个问题,首先要对系统的资源加载有一定的了解,这里就不详细分析系统资源加载的机制了,但是我们简单说明一下,拿最简单的图片来说,当我们把一张图片挡在drawable中的时候,就可以通过Resources去获取这张图片了,同时为了兼容不同的设备,我们可能还需要在其他一些目录下放置不同的图片,比如drawable-xhdpi之类的,当应用程序启动时,系统会根据当前设备的情况去加载合适的Resources资源,比如说横屏手机和竖屏手机会拿着两张不同的图片(设定了landscape或者portrait状态下的图片),比如之前Activity处于竖屏,我们突然旋转屏幕,由于系统配置发生了改变,在默认情况下,Activity会被销毁并且重新创建,当然我们也可以阻止系统重新创建我们的Activity

    默认情况下,如果我们的Activity不做特殊处理,那么当系统配置发生改变之后,Activity就会销毁并且重新创建,可以看图

    这里写图片描述

    当系统配置发生改变的时候,Activity会被销毁,其onPause,onStop,onDestroy均会被调用,同时由于Activity是异常情况下终止的,系统会调用onSaveInstanceState来保存当前Activity的状态,这个方法调用的时机是在onStop之前,他和onPause没有既定的时序关系,他即可能在onPause之前调用,也有可能在之后调用,需要强调的是,这个方法只出现在Activity被异常终止的情况下,正常情况下是不会走这个方法的吗,当我们onSaveInstanceState保存到Bundler对象作为参数传递给onRestoreInstanceState和onCreate方法,因此我们可以通过onRestoreInstanceState和onCreate方法来判断Activity是否被重建。如果被重建了,我们就取出之前的数据恢复,从时序上来说,onRestoreInstanceState的调用时机应该在onStart之后

    同时我们要知道,在onSaveInstanceState和onRestoreInstanceState方法中,系统自动为我们做了一些恢复工作,当Activity在异常情况下需要重新创建时,系统会默认我们保存当前的Activity视图架构,并且为我们恢复这些数据,比如文本框中用户输入的数据,ListView滚动的位置,这些View相关的状态系统都会默认恢复,具体针对某一个特定的View系统能为们恢复那些数据?我们可以查看View的源码,和Activity一样,每一个View都有onSaveInstanceState和onRestoreInstanceState这两个方法,看一下他们的实现,就能知道系统能够为每一个View恢复数据

    关于保存和恢复View的层次结构,系统的工作流程是这样的:首先Activity被意外终止时,Activity会调用onSaveInstanceState去保存数据,然后Activity会委托Window去保存数据,接着Window再委托上面的顶级容器去保存数据,顶级容器是一个ViewGroup,一般来说他可能是一个DecorView,最后顶层容器再去一一通知他的子元素来保存数据,这样整个数据保存过程就完成了,可以发现,这是一种典型的委托思想,上层委托下层,父容器委托子容器,去处理一件事件,这种思想在Android 中有很多的应用,这里就不再重复介绍了,接下来举个例子,那TextView来说,我们分析一下他到底保存了那些数据

     @Override
        public Parcelable onSaveInstanceState() {
            Parcelable superState = super.onSaveInstanceState();
    
            // Save state if we are forced to
            boolean save = mFreezesText;
            int start = 0;
            int end = 0;
    
            if (mText != null) {
                start = getSelectionStart();
                end = getSelectionEnd();
                if (start >= 0 || end >= 0) {
                    // Or save state if there is a selection
                    save = true;
                }
            }
    
            if (save) {
                SavedState ss = new SavedState(superState);
                // XXX Should also save the current scroll position!
                ss.selStart = start;
                ss.selEnd = end;
    
                if (mText instanceof Spanned) {
                    Spannable sp = new SpannableStringBuilder(mText);
    
                    if (mEditor != null) {
                        removeMisspelledSpans(sp);
                        sp.removeSpan(mEditor.mSuggestionRangeSpan);
                    }
    
                    ss.text = sp;
                } else {
                    ss.text = mText.toString();
                }
    
                if (isFocused() && start >= 0 && end >= 0) {
                    ss.frozenWithFocus = true;
                }
    
                ss.error = getError();
    
                return ss;
            }
    
            return superState;
        }
    
    

    从上述源码中我们可以看到,TextView为了保存自己的文本选中和文本结构内容,并且通过查看onRestoreInstanceState方法的源码,可以发现它的确恢复了这些数据,具体源码就不在贴出,读者可以自己去看下源码,下面我们看来看下实际的例子,对比一下Activity正常终止和异常终止的不同,同时验证一下系统的数据恢复能力,为了方便测试,我们采用了旋转屏幕来终止Activity,在我们旋转屏幕以后,Activity被销毁重建,我们输入的文本被正确还原了,说明我们的系统能够正确的做一些View层的分析,我们看下代码

    package com.liuguilin.activitysample;
    
    import android.os.Bundle;
    import android.os.PersistableBundle;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    
    public class MainActivity extends AppCompatActivity {
    
        public static final String TAG = "MainActivity";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            if (savedInstanceState != null) {
                String test = savedInstanceState.getString("extra_test");
                Log.i(TAG, test);
            }
        }
    
        @Override
        public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
            super.onSaveInstanceState(outState, outPersistentState);
            Log.i(TAG, "onSaveInstanceState");
            outState.putString("extra_test", "test");
        }
    
        @Override
        protected void onRestoreInstanceState(Bundle savedInstanceState) {
            super.onRestoreInstanceState(savedInstanceState);
            String test = savedInstanceState.getString("extra_test");
            Log.i(TAG, test);
        }
    }
    

    上面的代码很简单,首先我们在onSaveInstanceState中保存一个字符串,然后当我们的Activity被销毁并且重新创建之后,我们再去获取之前存储的字符串,接收的位置可以选择onRestoreInstanceState或者onCreate,两者的区别是:onRestoreInstanceState一旦被调用,其参数Bundler savedInstanceState一定有值,我们不用额外的判断是否为空但是onCreate不行,onCreate如果正常启动的话,其参数Bundler onSaveInstanceState为null,所以需要一些额外的判断,这两个方法我们选择任意一个都是可以进行数据恢复的,但是关键建议我们使用onRestoreInstanceState去恢复数据

    Activity销毁后调用了onSaveInstanceState来保存数据,重新创建以后再onCreate和onRestoreInstanceState中能恢复数据,这个正好证明了我们刚才的分析,针对onSaveInstanceState我们有一点要说明,那就是系统只会在即将被销毁并且有机会重新显示的情况下才会去调用它,考虑到这一种情况,当Activity正常销毁的时候,系统不会调用onSaveInstanceState,因为被销毁的Activity不可能再次被显示出来,这句话不好理解,但是我们可以对比一下旋转屏幕所造成的Activity异常销毁,这个过程和正常停止的Activity是不一样的,因为旋转屏幕之后,Activity被销毁的同时会立即创建新的Activity实例,这个时候Activcity有机会再次立刻显示,所以系统进行了数据存储,这里可以简单的这么理解,系统只在Activity异常终止的情况下才会调用onSaveInstanceState和onRestoreInstanceState来存储和恢复数据,其他情况不会触发

    2.情况2:资源内存不足导致低优先级的Activity被杀死

    这个情况我们不好模拟,但是其数据的存储和恢复过程和情况一是一致的,这里我们描述一下Activity的优先级情况,Activity按照优先级的从高往低,可以分为三种:

    • 1.前台Activity:正在和用户交互的Activity,优先级最高
    • 2.可见但非前台Activity:比如对话框,导致Activity可见但是位于后台无法和用户直接交互
    • 3.后台Activity:已经被暂停的Activity,比如执行了onStop,优先级最低

    当系统内存不足的时候,系统就会按照上述优先级去杀死目标Activity所在的进程,并且在后续通过onSaveInstanceState和onRestoreInstanceState来存储和恢复数据,如果一个进程中没有四大组件在执行,那么这个进程将很快被系统杀死,因此,一些后台工作不适合脱离四大组建而独立运行在后台中,这样进程很容易就被杀死了,比较好的方法就是将后台工作放在Service中从而保证了进程有一定的哟徐爱你集,这样就不会轻易的被杀死

    上面分析了系统的数据存储和恢复机制,我们知道,当系统配置发生改变后,Activity会被重新创建,那我们有没有什么办法不重新创建尼?答案是有的,接下来我们来分析一下这个问题,系统配置中有很多内容,如果当某项内容发生改变后,我们不想系统重新创建,就可以给configChangs属性加上orientation这个值

    android:configChanges="orientation"
    

    如果想指定多个值的话可以用“|”连接起来

    mcc:The IMSI mobile country code (MCC) has changed — a SIM has been detected and updated the MCC.
    IMSI(国际移动用户识别码)发生改变,检测到SIM卡,或者更新MCC

    mnc:The IMSI mobile network code (MNC) has changed — a SIM has been detected and updated the MNC.
    IMSI网络发生改变,检测到SIM卡,或者更新MCC其中mcc和mnc理论上不可能发生变化

    locale:The locale has changed — the user has selected a new language that text should be displayed in.
    语言发生改变,用户选择了一个新的语言,文字应该重新显示

    touchscreen:The touchscreen has changed. (This should never normally happen.)
    触摸屏发生改变,这通常是不应该发生的

    keyboard:The keyboard type has changed — for example, the user has plugged in an external keyboard.
    键盘类型发生改变,例如,用户使用了外部键盘

    keyboardHidden:The keyboard accessibility has changed — for example, the user has revealed the hardware keyboard.
    键盘发生改变,例如,用户使用了硬件键盘

    navigation:The navigation type (trackball/dpad) has changed. (This should never normally happen.)
    导航发生改变,(这通常不应该发生) 举例:连接蓝牙键盘,连接后确实导致了navigation的类型发生变化。因为连接蓝牙键盘后,我可以使用方向键来navigate了

    screenLayout:The screen layout has changed — this might be caused by a different display being activated.
    屏幕的布局发生改变,这可能导致激活不同的显示

    ontScale:The font scaling factor has changed — the user has selected a new global font size.
    全局字体大小缩放发生改变

    orientation:The screen orientation has changed — that is, the user has rotated the device.设备旋转,横向显示和竖向显示模式切换。

    screenSize: 屏幕大小改变了

    smallestScreenSize: 屏幕的物理大小改变了,如:连接到一个外部的屏幕上

    4.2增加了一个layoutDirection属性,当改变语言设置后,该属性也会成newConfig中的一个mask位。所以ActivityManagerService(实际在ActivityStack)在决定是否重启Activity的时候总是判断为重启。
    需要在android:configChanges 中同时添加locale和layoutDirection。
    在不退出应用的情况下切换到Settings里切换语言,发现该Activity还是重启了。

    从上面的属性中我们可以知道,如果我们没有在Activity的configChanges中设备属性的话,当系统发生改变后就会导致Activity重新被创建,上面表格中的项目很多,但是我们常用的只有locale,orientation,keyboardHidden这三个选项,其他用的还是比较少的,这里设置之后显示的效果我就不演示了

    四.Activity的启动模式

    Android的启动模式,是很有用的,对于Activity的栈的处理,也是极其讲究的,所以你一定要清除他的标志位和启动模式

    一.Activity的LaunchMode

    首先说一下Activity为什么需要启动模式,我们知道,在默认的情况下,当我们多次启动同一个Activity的时候,系统会创建多个实例并把他们一一放入任务栈中,当我们点击back键的时候会发现这些Activity会一一回退,任务栈是一种先进先出的栈结构,这个好理解, 每按一次back键就有一个activity退出栈,知道栈空为止,当这个栈为空的时候,系统就会回收这个任务栈,关于任务栈的系统工作原理,这里我们暂且不说,在后续章节也会介绍任务栈,知道了Activity的启动模式,我们可发现一个问题,:多次启动同一个Activity会创建多个实例,这样是不是很逗,Activity在设计的时候不可能不考虑到这个问题,所以他提供了启动模式来修改系统的默认行为,目前有四种启动模式

    • standard
    • singleTop
    • singleTask
    • singleInstance

    我们先来把这几种启动模式都给介绍完

    • standard:标准模式,这也是系统的默认模式,每次启动一个Activity都会重新创建一个实例,是否这个实例已经存在,被创建的实例的生命周期符合典型情况下Activity的生命周期,如上述:onCreate(),onStart();onResume()都会被调用,这是一种典型的多实例实现,一个任务栈都可以有多个实例,每个实例都可以属于不同的任务栈,在这种模式下,谁启动了这个Activity,那么这个Activity就运行在启动它的Activity所在的栈内,比如Activity A启动了Activity B(B是标准模式),那么B就会进入到A所在的栈内,不知道读者有没有注意到,当我们用ApplicationContext去启动standard模式的Activity的时候就会报错:
    E/AndroidRuntime(674): android.util.androidruntiomException: Calling startActivity from outside of an Activity context requires the FLAG_ACTIVITY_TASK flag . Is this really what are want?

    相信读者对这句话不会陌生,这是因为我们的standard模式的Activity默认会进入启动它的Activity所属的任务栈中,但是由于非Activity类型的Context(如ApplicationContext)并没有所谓的任务栈,所以这就有问题了,解决这个问题,就是待启动Activity指定FLAG_ACTIVITY_TASK标记位,这样启动的时候就会为他创建一个新的任务栈,这个时候待启动Activity实际上是以singleTask模式启动的,读者可以仔细体会

    • singleTop:栈顶复用模式,在这个模式下,如果新的Activity已经位于任务栈的栈顶,那么此Activity不会被重新创建,同时他的onNewIntent方法会被调用,通过此方法的参数我们可以取出当前请求的信息,需要注意的是,这个Activity的onCreate,onStart不会被系统调用,因为他并没有发生改变,如果新Activity已存在但不是在栈顶,那么新Activity则会重新创建,举个例子,假设现在栈内的情况为ABCD,其中ABCD为四个Activity,A位于栈底,D位于栈顶,这个时候假设要再启动D,如果D的启动模式为singleTop,那么站栈内的情况仍然是ABCD,如果D的启动模式是standard,那么由于D会被重新创建,导致情况就是ABCDD

    • singTask:栈内复用模式,这是一种单实例模式,在这种模式下,只要Activity在一个栈内存在,那么多次启动此Activity都不会创建实例,和singTop一样,系统也会回调其onNewIntent方法,具体一点,当一个具有singleTask模式的Activity请求启动后,比如Activity A,系统首先会去寻找是否存在A想要的任务栈,如果不存在,就小红心创建一个任务栈,然后创建A的实例把A放进栈中,如果存在A所需要的栈,这个时候就要看A是否在栈中有实例存在,如果实例存在,那么系统就会把A调到栈顶并调用它的onNewIntent方法,如果实例不存在,就创建A的实例并且把A压入栈中,举几个例子

      • 比如目前任务栈S1中的情况为ABC,这个时候Activity D以singleTask模式请求启动,其所需的任务栈为S2,由于S2和D的实例都不存在,所以系统会先创建任务栈S2,然后创建D的实例将其入栈到S2
      • 另外一种情况,假设D所需的任务栈为S1,其他情况如如上面的一样,那么由于S1已经存在,所以系统会直接创建D的实例并将其引入到S1中
      • 如果D所需要的任务栈为S1,并且当前任务栈S1的情况为ABCD,根据栈内复用的原则,此时D不会被重新创建,系统会把D切换到栈顶并且调用其oNnNewIntent方法,同时由于singleTask默认具有clearTop的效果,会导致栈内所有在D上面的Activity全部出栈,于是最终S1中的情况为AD,这一点比较特殊,在后面还会对此情况详细的分析

    通过上述的三个例子,读者应该还是比较清晰的理解singTask的含义吧

    • singleInstance:单实例模式,这是一种加强的singleTask的模式,他除了具有singleTask的所有属性之外,还加强了一点,那就是具有此模式下的Activity只能单独的处于一个任务栈中,换句话说,比如Activity A是singleInstance模式,当A启动的时候,系统会为创建创建一个新的任务栈,然后A独立在这个任务栈中,由于栈内复用的特性,后续的请求均不会创建新的Activity,除非这个独特的任务栈被系统销毁了

    上面介绍了几种启动模式,这里需要指出一种情况,我们假设目前有两个任务栈,前台任务栈的情况为AB,而后台任务栈的情况是CD,这里假设CD的启动模式都是singleTask,现在请求启动D,那么整个后台任务站都会被切换到前台,这个时候整个后退列表变成了ABCD,当用户按back键的时候,列表中的Activity会一一出栈,如图

    这里写图片描述

    如果不是请求D,而是请求C,那么情况就不一样了,如图,具体原因我们在后续章节中分析

    这里写图片描述

    另外一个问题,在singkleTask启动模式中,多次提到了某个Activity所需的任务栈,什么是Activity所需的任务栈尼?这要从一个参数说起:TaskAffinity,可以翻译成任务相关性,这个参数标示了一个Activity所需要的任务栈的名字默认情况下,所有的Activity所需要的任务栈的名字为应用的包名,当然,我们可以为每个Activity都单独指定TaskAffinity,这个属性值必须必须不能和包名相同,否则就相当于没有指定,TaskAffinity属性主要和singleTask启动模式或者allowTaskReparenting属性配合使用,在其他状况下没有意义,另外,任务栈分为前台任务栈和后台任务栈,后台任务栈中的Activity位于暂停状态,用户可以通过切换将后台任务栈再次调为前台

    当TaskAffinity和singleTask启动模式配对使用的时候,他是具有该模式Activity目前任务栈的名字,待启动的Activity会运行在名字和TaskAffinity相同的任务栈中

    当TaskAffinity和allowTaskReparentiing结合的时候,这种情况比较复杂,会产生特殊的效果,当一个应用A启动了应用B的某一个Activity后,如果这个Activity会直接从应用A的任务栈转移到应用B的任务栈中,这还是很抽象的,再具体点,比如现在有2个应用A和B,A启动了B的一个Activity C ,然后按Home键回到桌面,然后再单击B的桌面图标,这个时候并不是启动; B的主Activity,而是重新显示了已经被应用A启动的Activity C,或者说,C从A的任务栈转移到了B的任务栈中,可以这么理解,由于A启动了C,这个时候C只能运行在A的任务栈中,但是C属于B应用,正常情况下,他的TaskAffinity值肯定不可能和A的任务栈相同(因为包名不同),所以,当B启动后,B会创建自己的任务栈,这个时候系统发现C原本所想要的任务栈已经被创建出来了,所以就把C从A的任务栈中转移过来,这种情况读者可以写一个例子测试一下,这里就不做演示了

    如何给Activity指定启动模式?有两种方法,第一种是通过清单文件为Activity指定

    <activity android:name=".SecondActivity"
                android:launchMode="singleTask"/>
    

    另一种启情况就是通过intent的标志位为Activity指定启动模式

     Intent intent = new Intent();
     intent.setClass(this,SecondActivity.class);
     intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
     startActivity(intent);
    

    这两种方式都可以为Activity指定启动模式,但是二者还是有一些区别的,首先,优先级上,第二种比第一种高,当两种同时存在的时候,以第二种为准,其次,上述两种方式在限定范围内有所不同,比如,第一种方式无法直接为Activity设置FLAG_ACTIVITY_CLEAR_TOP标识,而第二种方式无法指定singleInstance模式

    关于Intent中为Activity指定的各种标记位,在下面的小节中会继续说道,下面通过一个实例来体验启动模式的使用效果,还是前面的例子,我们把MainActivity的启动模式设置成singleTask,然后重复启动它,看看他是否会重复创建

         <activity
                android:name=".MainActivity"
                android:configChanges="orientation|screenSize"
                android:launchMode="singleTask">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
         //点击事件
         findViewById(R.id.btnTo).setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View view) {
                    Intent intent = new Intent();
                    intent.setClass(MainActivity.this,MainActivity.class);
                    intent.putExtra("time", System.currentTimeMillis());
                    startActivity(intent);
                }
            });
    
        @Override
        protected void onNewIntent(Intent intent) {
            super.onNewIntent(intent);
            Log.d(TAG, "onNewIntent , time =" + intent.getLongExtra("time", 0));
        }
    

    上述修改,我们做了如下操作,连续点击三次按钮启动三次,算上原本的MainActivity实例,正常情况下,任务栈中应该有四个MainActiivty实例,但是我们为其指定了singTask模式,我们一起来看下有何不同

    执行命令

    adb shell dumpsys activity
    

    ok,输入日志

    这里写图片描述

    从上面的信息中不难看出,尽管启动了四次MainActivity,但是他始终只有一个实例在任务栈中,从log中我们也可以看到

    这里写图片描述

    Activity的确没有被创建,只是暂停了一下,然后调用了onNewIntent,接着又onResume又继续了,现在我们去掉singTask,再来比对一下我们的操作,同样是点击三次按钮,执行adb命令

    这里写图片描述

    我们能够得到目前总共有2个任务栈,前台任务栈taskAffinity值为包名。里面有四个Activity,后台是一个com.android.launcher,他里面就一个桌面

    从上面的导出信息可以看到,在任务栈中有四个MainActivity,这也就验证了Activity的启动模式的工作方式

    上述四种启动模式,standard和singleTop都比较好理解,singleInstance由于其特殊性也比较好理解,但是关于singleTask还有一种情况需要理解,比如我们刚才那张启动D的图,在Activity B中请求的不是D而是C,那情况该如何尼?这里可以告诉读者的是,任务列表变成了ABC,是不是很奇怪,Activity为什么直接出栈了,我们用一个实例来说明情况

           <activity
                android:name=".MainActivity"
                android:configChanges="orientation|screenSize"
                android:launchMode="standard">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
            <activity
                android:name=".SecondActivity"
                android:configChanges="screenLayout"
                android:launchMode="singleTask"
                android:taskAffinity="com.liuguilin.activitysample1"  />
    
            <activity
                android:name=".CodeActivity"
                android:configChanges="screenLayout"
                android:launchMode="singleTask" 
                android:taskAffinity="com.liuguilin.activitysample1" />
    

    我们把SecondActivity和CodeActivity的启动模式都改成了singleTask,并且把android:taskAffinity设置为com.liuguilin.activitysample,注意这个taskAffinity的值属于字符串,切中间必须有包名分割符‘.’,然后我们做如下的动作,在MainActivity中单击按钮启动SecondActivity,在SecondActivity中单击按钮启动CodeActivity,在CodeActivity启动MainActivity,最后在MainActivity中启动SecondActivity,,现在按Back,你知道会回那个Activity吗?答案是桌面,是不是有点摸不着头脑,我们看图理解一下

    这里写图片描述

    首先,我们来分析一下这个问题,我们知道,A的启动模式是standard,按照规定,A的taskAffinity继承的是application的taskAffinity,而application默认taskAffinity是包名,所以A的taskAffinity是包名,由于我们在XML中为B和C指定了taskAffinity和启动模式,且有相同的taskAffinity,所以B和C是singleTask模式且有相同的taskAffinity,所以A启动B的时候,按照singleTask的规则,这个时候需要为B重新创建一个任务栈了,B再启动C,按照singleTask的规则,由于C所需要的任务栈已经被B给创建了,所以无需再创建新的任务栈,这个时候系统只是创建C的实例放进任务栈,接着C再启动A,A是标准模式,所以系统会为他创建一个新的实例并将他加入到启动的任务栈中,由于是C启动了A,所以A会进入C的栈内并处于栈顶,这个时候已经有两个任务栈了,接着A再启动B,由于B是singleTask,B需要回到任务栈的栈顶,由于栈的模式为‘先进先出’,B想要回到栈顶,就只能是CA出栈,所以到这里就很好理解,按back键,B就出栈了,然后这个任务栈就是空的,被系统回收了,这个时候就只能是回到后台任务栈把A显示出来,注意这个A是后台任务栈的A,不是BC栈的A,接着再按back就回到了桌面,分析到这里,我们就得到了一条结论,singtleTask模式的Activity切换到栈顶会到导致在他之上的栈内activity出栈,我们可以看下运行的结果

    这里写图片描述

    接着我们再实验中再次验证这个问题,我们采用dumpasys命令,看看输出的是什么?

    这里写图片描述

    可以看到在B任务栈中只剩下B了,其他的都出栈了,这个时候按back肯定就回收了,分析到这里,我相信读者对Activity的启动模式有了很深入的了解吧,下面我们再来说下Activity的标志位

    二.Activity 的 Flags

    Activity的Flags有很多,这里主要是分析一些常用的标记位,标记位的作用很多,有些标志位可以设置Activity的启动模式,比如FLAG_ ACTIVITY _ NEW _ TASK,还有一些直接影响Activity的运行状态,比如FLAG_ ACTIVITY_ CLEAR_ TOP,下面我们来说下一些常用的标记位,剩下的读者可以去看下官方文档,大部分的情况下,Activity不需要设置标记位,因此对于标记位理解即可,在使用标记位的时候,要注意有些标记位是系统内部使用的,应用不需要去设置这些以防出问题。

    • FLAG_ ACTIVITY_ NEW _ TASK

      这个标志位的作用是为Activity指向‘singleTask’启动模式,其效果和XML中指定该模式相同

    • FLAG_ ACTIVITY_ SINGLE _ TOP

      这个标志位的作用是为Activity指向‘singleTop’启动模式,其效果和XML中指定该模式相同

    • FLAG_ ACTIVITY_ CLEAR _ TOP

      具有此标记位的Activity,当他启动时,在同一个任务栈中所有位于他上面的Activity都要出栈,这个模式一般需要和FLAG_ ACTIVITY_ NEW _ TASK配合使用,在这种情况下,被启动的Activity的实例如果已经存在,那么系统就会调用它的onNewIntent,如果被启动的Activity采用标准模式,那么他连同他之上的Activity都要出栈,系统会创建新的Activity实例并放入栈顶

    • FLAG_ ACTIVITY_ EXCLUDE_ FROM _ RECENTS

      具有此标记位的Activity,不会出现在历史Activity的列表当中,当某种情况下我们不希望用户通过历史列表回到我们的Activity的时候就使用这个标记位了,他等同于在XML中指定Activity的属性:

        android:excludeFromRecents="true"
    

    三.intentFilter的匹配规则

    我们知道,启动Activity分为两种,显示调用和隐式调用,二者的区别这里就不多讲了,显示调用需要明确的指定被启动对象的组件信息,包括包名和类名,而隐式意图则不需要明确指定调用信息,原则上一个intent不应该即是显式调用又是隐式调用,如果二者共存的话以显式调用为主,显式调用很简单,这里主要介绍隐式调用,隐式调用需要intent能够匹配目标组件的IntentFilter中所设置的过滤信息,如果不匹配将无法启动目标Activity,IntentFilter中的过滤信息有action,category,data,下面是一个过滤规则的实例:

            <activity
                android:name=".CodeActivity"
                android:configChanges="screenLayout"
                android:launchMode="singleTask"
                android:taskAffinity="com.liuguilin.activitysample1">
                <intent-filter>
                    <action android:name="com.liuguilin.activitysample.c" />
                    <action android:name="com.liuguilin.activitysample.d" />
    
                    <category android:name="com.liuguilin.category.c" />
                    <category android:name="com.liuguilin.category.d" />
    
                    <data android:mimeType="text/plain" />
                </intent-filter>
            </activity>
    

    为了匹配过滤列表,需要同时匹配过滤列表中的action,category,data信息,否则匹配失败,一个过滤列表中的action,category,data可以有多个,所有的action,category,data分别构成不同类别,同一类型的信息共同约束当前类别的匹配过程,只有一个intent同时匹配action类别,category类别,data类别才算是匹配完成,只有完全匹配才能成功启动目标Activity,另外一点,一个Activity钟可以有多个intent-filter,一个intent只要能匹配一组intent-filter即可成功启动Activity

             <activity android:name=".ShareActivity">
                <!-- This activity handlers "SEND" actions with text data-->
                <intent-filter>
                    <action android:name="android.intent.action.SEND" />
                    <category android:name="android.intent.category.DEFAULT" />
                    <data android:mimeType="text/plain" />
                </intent-filter>
                <!--This activity also handlers "SEND" and "SEND_MULTIPLE" with media data-->
                <intent-filter>
                    <action android:name="android.intent.action.SEND" />
                    <action android:name="android.intent.action.SEND_MULTIPLE" />
    
                    <category android:name="android.intent.category.DEFAULT" />
    
                        <data android:mimeType="application/vnd.google.panorama360+jpg"/>
                    <data android:mimeType="image/*" />
                    <data android:mimeType="text/plain" />
                </intent-filter>
            </activity>

    下面详细分析各种属性的匹配规则

    • 1.action的匹配规则

      action是一个字符串,系统预定了一些action,同时我们也可以在应用中定义自己的action,action的匹配规则是intent中的action必须能够和过滤规则中的action匹配,这里说的匹配是指action的字符串值完全一样,一个过滤规则中的可以有多个action,那么只要intent中的action能够和过滤规则匹配成功,针对上面的过滤规则,需要注意的是,intent如果没有指定action,那么匹配失败,总结一下,action的匹配需求就是intent中的action存在且必和过滤规则一样的action,这里需要注意的是他和category匹配规则的不同,另外,action区分大小写,大小写不同的字符串匹配也会失败

    • 2.category的匹配规则

      category是一个字符串,系统预定义了一些category,同时我们也可以在应用中定义自己的category。category的匹配规则和action不同,它要求Intent中如果含有category,那么所有的category都必须和过滤规则中的其中一个category相同。换句话说,Intent如果出现了category,不管有几个category,对于每个category来说,它必须是过滤规则中已经定义的category。当然,Intent中可以没有category,如果没有category的话,按照上面的描述,这个Intent仍然可以匹配成功。这里要注意下它和action匹配过程的不同,action
      是要求Intent中必须有一个action且必须能够和过滤规则中的某个action相同,而category要求Intent可以没有category,但是如果你一旦有category,不管有几个,每个都要能和过滤规则中的任何一个category相同。为了匹配前面的过滤规则中的category,我们可出下面的Intent,intent.addcategory (“com.ryg.category.c”)或者Intent.addcategory (“com rcategory.d)亦或者不设category。为什么不设置category也可以匹配呢?原因是系统在调用startActivity或者startActivityForResult的时候会默认为Intent加上“android.intent.category.DEFAULT”这个category,所以这个category就可以匹配前面的过滤规则中的第三个category。同时,为了我们的activity能够接收隐式调用,就必须在intent-filter中指定“android intent categor.DEFAULT”这个category,原因刚才已经说明了。

    • 3.data匹配规则

      data的匹配规则和action有点类似,如果过滤规则中定义了data,那么intent中必须也要定义可匹配的data,在介绍data的匹配规则之前,我们需要来了解一下data的结构,因为data稍微有点复杂

        <data
           android:host="string"
           android:mimeType="string"
           android:path="string"
           android:pathPattern="string"
           android:pathPrefix="string"
           android:port="string"
           android:scheme="sstring" />
    

    data由两部分组成,mimeType和URI,前者是媒体类型,比如image/jpeg等,可以表示图片等,而URI包含的数据可就多了,下面的URI的结构:

        <scheme>://<host>"<port>/[<path>|<pathPrefix>|<pathPattern>]
    

    这里再给几个实际的例子就好理解了

    content://com.liuguilin.project:200/folder/subfolder/etc
    http://www.baidu.com:80/search/info

    看了上面的两个例子你是不是瞬间就明白了,没错,就是这么简单,不过下面还是要一一介绍含义的:

    • Scheme:URI的模式,比如http.file.content等,如果URI中没有指定的scheme,那么整个URI的其他参数无效,这也意味着URI无效
    • Host:URI的主机,比如www.google.com,如果host未指定,那么整个URI中的其他参数无效,这也意味着URI无效
    • Port:URI中的端口号,比如80,不过需要指定上面两个才有意义
    • Path、pathPattem 和 pathPrefix:这三个参数表述路径信息,其中path表示完整的路径信息:pathPattern也表示完整的路径信息,但是它里面可以包含通配符“ * ”,“ * ” 表示0个或多个任意字符,需要注意的是,由于正则表达式的规范,如果想表示真实的字符串,那么“* ” 要写成 “ \*”,“ \ ”要写成“ \\ ”,pathPrefix表示路径的前缀信息。

    介绍完data的数据格式后,我们要说一下data的匹配规则了。前面说到,data的匹配规则和action类似,它也要求Intent中必须含有data数据,并且data数据能够完全匹配过滤规则中的某一个datn.这里的完全匹配是指过滤规则中出现的data部分也出现在了 Intent
    中的data中。下面分情况说明。

    • (1) 如下过来规则
           <intent-filter>
              <data android:mimeType="image/*"/>
          </intent-filter>
    

    这种规则指定了所有类型为图片,那么intent中的mineType属性必须为“image/*”才能匹配,这种情况下虽然过来规则没有指定URI,但是却有默认值,URI的默认值为content何file,也就是说,虽然没有指定URI,但是Intent中的URI部分的scheme必须为content或者file才能匹配,这点事需要注意的,为了匹配一种的规则我们可以这样写:

        intent.setDataAndType(Uri.parse("file://abc"),"image/png");

    另外,如果要为Intent指定完整的data,必须调用setDataAndType方法,不能县调用setData在调用setType,因为这两个方法彼此会清除对方的值,这个看源码就比较好理解了,比如setData:

        public Intent setData(Uri data) {
            mData = data;
            mType = null;
            return this;
        }

    可以发现,setData会把类型设置为null,同样的,对方也是

    • (2)如下规律规则
          <intent-filter>
                    <data android:mimeType="video/mpeg" android:scheme="http" .../>
                    <data android:mimeType="audio/mpeg" android:scheme="http" .../>
          </intent-filter>

    这种规则指定了两组data规则,且每个data都指出了完整的属性值,既有URI又有类型,为了匹配类型二,我们这样写“

        intent.setDataAndType(Uri.parse("http://abc"),"video/png");

    或者

        intent.setDataAndType(Uri.parse("http://abc"),"audio/png"); 

    通过上面的实例,我们应该知道了data的匹配规则,关于data还有一些特殊的情况需要说明一下,这也是他和action不同的地方

      <intent-filter >
         <data android:scheme="file" android:host="www.baidu.com"/>
             ...
     </intent-filter>
    
     <intent-filter >
           <data android:scheme="file" />
           <data android:host="www.baidu.com"/>
             ...
      </intent-filter>

    到这里我们已经把IntentFilter的过滤规则都讲了一遍了,还记得本书前面给出的一个实例吗?现在我们给出完整的intent匹配规则

        Intent intent = new Intent();
        intent.addCategory("com.liuguilin.category.c");
        intent.setDataAndType(Uri.parse("file//abc"),"text/plain");
        startActivity(intent);

    还记得URI中的scheme中的默认值吗?如果把上面的intent.setDataAndType(Uri.parse(“file//abc”),”text/plain”);这句改成intent.setDataAndType(Uri.parse(“http//abc”),”text/plain”);打开的actiivty就会报错,提示无法找到Activity,另外一点,intent-filter的匹配规则对于服务和广播也是同样的道理,不过系统对于Service的建议是尽量使用显式意图来启动服务。

    最后,当我们通过隐式方式启动一个Activity的时候,可以做一下判断,看是否Activity能够匹配我们的隐式Intent,如果不做判断就有可能出现上述的错误了。判断方法有两种:采用PackageManager的resolveActivity方法或者Intent 的resolveActivity方法,
    果它们找不到匹配的Activity就会返回null,我们通过判断返回值就可以规避上述错误了,另外,PackageManager还提供了queryIntentActivities方法,这个方法和resolveActivity方法法不同的是:它不是返回最佳匹配的Activity信息而是返回所有成功匹配的Activity信息,我们看一下queryIntentActivities和resolveActivity的方法原型:

        public abstract List<ResolveInfo>queryIntentActivities(Intent intent,int fladgs);
        public abstract ResolveInfo resolveActivity(Intent intent,int flags);

    上述两个方法的第一个参数比较好理解,第二个参数需要注意,我们要使用MATCH_ DEFAULT _ ONLY这个标记位,这个标记位的含义是仅仅匹配那些在intentfilter中声明了 < category android-name=”android.intent.category DEFAULT”>这个category的 Activity。使用这个标记位的意义在于,只要上述两个方法不返回null,那么startActivity一定可以成功,如果不用这个标记位,就可以把intent-filter 中 category不含DEFAULT的那些Activity给匹配出来,从而导致startActivity可能失败。因为不含有DEFAULT这个category的Activity是无法接收隐式Intent的。在action和 category中,有一类action和category比较重要,他们是:

        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />

    这二者共同作用是用来标明这是一个入口Activity并且会出现在系统的应用列表中,少了任何一个都没有实际意义,也无法出现在系统的应用列表中,也就是二者缺一不可,另外,针对 Service和BroadcastReceiver,PackageManager同样提供了类似的方法去获取成功匹配的组件信息。

    好的,我们的第一章就写到这里了,不得不说这是一本好书,非常的详细,也希望大家仔细的阅读


    ActivitySample:正在上传

    PPT:http://download.csdn.net/detail/qq_26787115/9631588

    MakeDown:http://pan.baidu.com/s/1o7Z4Djs 密码:xdgt

    有兴趣的可以加群:555974449

    展开全文
  • 经过长期的不断改进维护,通过多个软件项目,多位商业用户的实战考验,能满足不同规模软件项目的快速开发、快速整合、快速实施、灵活配置与管理的要求。为企业或个人.NET环境下快速开发信息化系统提供了强大的...

    RDIFramework.NET ━ .NET快速信息化系统开发框架

    第1章 引言

     

    1章 引言

      经过长期的不断改进维护,通过在多个软件项目,多位商业用户的实战考验,能满足不同规模软件项目的快速开发、快速整合、快速实施、灵活配置与管理的要求。为企业或个人在.NET环境下快速开发信息化系统提供了强大的支持,开发人员不需要开发系统的基础功能模块和公共模块,框架本身提供了强大的函数库和开发包,开发人员只须集中精力专注自身业务部分的开发,大大提高开发效率和节约开发成本。

     1.1 文档目的

      本文档为《RDIFramework.NET(.NET快速信息化系统开发整合框架)》产品使用说明书。

      编写本使用说明书的目的是充分叙述RDIFramework.NET框架所能实现的功能及其运行环境,以便使用者了解本软件的使用范围和使用方法,并为软件的维护和更新提供必要的信息。 

     1.2 产品对象与用户群体

      一、中小型软件开发公司,技术支持、技术咨询公司。

      统一的权限、模块分配,授权机制,多数据库开发的支持,多个常用商业控件集,统一的升级部署等。可成为众多中小型软件开发、技术支持、咨询公司项目的配套工具,应用开发的标准参考模型,提高开发效率,节约开发的人力、物力等成本,专注于自身业务。

      二、管理类软件开发者。

      管理类软件开发人员随着自己技术能力、业务能力等提升,难免不会在外面接点私活,对于客户提出的项目要求利用《.NET快速信息化系统开发整合框架(RDIFramework.NET)》你可以只专注其业务要求,开发完成,几分钟即可部署到此平台上,快速简单,安全可靠,又专业。

      三、想进一步提升自身技术能力的开发者、学生等。

      你想提升自身的技术实力吗?你想在职业生涯快速提升吗?你想学习实际的大型商业项目吗?此平台就是你的选择。此平台设计严谨、编码规范、简单易读、同时其通用性与规范性,是作为学习研究的佳品。作为学生、刚出生社会的开发人员或想提升自身开发实力的人,本平台的编码规范,数据库设计思想、分层理念、RBAC授权机制、设计模式、面向服务的开发思想、商业控件开发方法、统一的升级部署等等都值得你参考学习。

      四、培训机构。

      对于培训机构,一个好的培训项目不仅可以让培训的学子受益匪浅,让其培训后方可直接投入实际的工作之中,同时也能提升培训机构的自身品牌。不仅可大大的节省培训成本,更重要是的可以缩短培训周期,让培训学子快速进入工作状态。

      五、政府机关、事业单位。

      对于很多政府机关单位,其内部都有自己的开发团队,他们专注自身业务的同时,若能有一套可把多个系统统一高效、方便的部署到一个平台下,实现统一的管理显得尤为重要。选择一个合适的,安全可靠的,实际使用效果良好的平台非常重要。《.NET快速信息化系统开发整合框架(RDIFramework.NET)》就是你的选择。

      六、企业、工厂等。

      随着信息时代的高速发展,一个企业,工厂等信息化的建设已成为不能忽视的一环。

      不管是企业、工厂,都不止一套管理系统,这些分散的系统很难管理,数据分散不一,集成困难等,如果把这些系统统一的部署到一个平台下,那些这些诸多问题都可迎刃而解。最大程度避免重复开发、反复原地踏步,最大限度使内部的产品、项目等各功能模块之间有更高的兼容性。

     1.3 参考资料

     

     1.4 术语与缩写词

      1) RBAC:基于角色的访问控制(Role-Based Access Control)作为传统访问控制(自主访问,强制访问)的代替受到广泛的关注。在RBAC中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。在一个组织中,角色是为了完成各种工作而创造,用户则依据它的责任和资格来被指派相应的角色,用户可以很容易地从一个角色被指派到另一个角色。角色可依新的需求和系统的合并而赋予新的权限,而权限也可根据需要而从某角色中回收。角色与角色的关系可以建立起来以囊括更广泛的客观情况。

      2) 角色:角色(Role)为RBAC(基于角色的访问控制Role-Based Access Control)模型中的基本元素。 角色是权限分配的单位与载体。角色通过继承关系支持分级的权限实现。我们通过对角色分配访问权限控制,然后对用户或者用户组分派角色来实现用户的访问权限控制。

      3) 用户权限:就是用户的权利,即用一个帐户登录后,那些功能可以使用,那些功能无法使用,这就是管理员对其设置的权限,只有附合权限的人才可以使用对应的功能。权限就是权利的限制范围。

      4) 角色权限:与用户权限相对应,即为角色的权利。

      5) 用户(User):能够使用应用的唯一身份的人。

        角色(Role:一定数量的权限的集合,权限的载体。

        组织机构(Organize:企业管理中企业分层的基本单元,在本系统中机构只支持单树模型一个企业只有一个根机构(总部),除开根机构其他机构只有一个父机构,可以有多个子机构。

        岗位(Position:一个企业的某个部门的职位(相当于在部门下有相同职能的员工的集合),它隶属于某个具体的部门,并且可以有一个或者多个员工在岗位上任职。

        员工(Staff):企业中的人员,一个人员属于一个机构,一个人员可以关联一个用户。

      6) 操作权限:抽象为什么资源有什么权限,操作权限包括用户、角色、组织机构有什么权限。

      7) 数据权限:数据集权限抽象为什么对象对什么资源有什么权限,数据权限包括模块权限、管理范围、授权范围、资源权限、表权限、列权限、数据集权限。数据集权限主要是通过约束条件实现的记录级权限。

      8) 其他。 


    作者: EricHu
    出处: http://blog.csdn.net/chinahuyong
    Email: 406590790@qq.com
    QQ 交流:406590790 
    平台博客:http://blog.csdn.net/chinahuyong
             http://www.cnblogs.com/huyong
    关于作者:高级工程师、信息系统项目管理师、DBA。专注于微软平台项目架构、管理和企业解决方案,多年项目开发与管理经验,曾多次组织并开发多个大型项目,精通DotNet,DB(SqlServer、Oracle等)技术。熟悉Java、Delhpi及Linux操作系统,有扎实的网络知识。在面向对象、面向服务以及数据库领域有一定的造诣。现从事DB管理与开发、WinForm、WCF、WebService、网页数据抓取以及ASP.NET等项目管理、开发、架构等工作。
    如有问题或建议,请多多赐教!
    本文版权归作者和CNBLOGS博客共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,如有问题,可以通过邮箱或QQ 联系我,非常感谢。


    展开全文
  • Java 对象生命周期和类生命周期

    万次阅读 2015-04-21 16:57:30
    JVM运行空间中,对象的整个生命周期大致可以分为7个阶段:创建阶段(Creation)、应用阶段(Using)、不可视阶段(Invisible)、不可到达阶段(Unreachable)、可收集阶段(Collected)、终结阶段(Finalized)与...

    Java 对象生命周期


    在JVM运行空间中,对象的整个生命周期大致可以分为7个阶段:创建阶段(Creation)、应用阶段(Using)、不可视阶段(Invisible)、不可到达阶段(Unreachable)、可收集阶段(Collected)、终结阶段(Finalized)与释放阶段(Free)。上面的这7个阶段,构成了 JVM中对象的完整的生命周期。下面分别介绍对象在处于这7个阶段时的不同情形。 

    创建阶段

    在对象创建阶段,系统要通过下面的步骤,完成对象的创建过程:

    (1)为对象分配存储空间。

    (2)开始构造对象。

    (3)递归调用其超类的构造方法。

    (4)进行对象实例初始化与变量初始化。

    (5)执行构造方法体。

    上面的5个步骤中的第3步就是指递归地调用该类所扩展的所有父类的构造方法,一个Java类(除Object类外)至少有一个父类(Object),这个规则既是强制的,也是隐式的。你可能已经注意到在创建一个Java类的时候,并没有显式地声明扩展(extends)一个Object父类。实际上,在 Java程序设计中,任何一个Java类都直接或间接的是Object类的子类。例如下面的代码:

    public class A { 
         … 
    } 
    这个声明等同于下面的声明: 
    public class A extends java.lang.Object { 
         … 
    } 

    上面讲解了对象处于创建阶段时,系统所做的一些处理工作,其中有些过程与应用的性能密切相关,因此在创建对象时,我们应该遵循一些基本的规则,以提高应用的性能。

    下面是在创建对象时的几个关键应用规则:

    (1)避免在循环体中创建对象,即使该对象占用内存空间不大。

    (2)尽量及时使对象符合垃圾回收标准。

    (3)不要采用过深的继承层次。

    (4)访问本地变量优于访问类中的变量。

    关于规则(1)避免在循环体中创建对象,即使该对象占用内存空间不大,需要提示一下,这种情况在我们的实际应用中经常遇到,而且我们很容易犯类似的错误,例如下面的代码:

    … … 
    for (int i = 0; i < 10000; ++i) { 
        Object obj = new Object(); 
        System.out.println("obj= "+ obj); 
    } 
    … … 

    上面代码的书写方式相信对你来说不会陌生,也许在以前的应用开发中你也这样做过,尤其是在枚举一个Vector对象中的对象元素的操作中经常会这样书写,但这却违反了上述规则(1),因为这样会浪费较大的内存空间,正确的方法如下所示:

    … … 
    Object obj = null; 
    for (int i = 0; i < 10000; ++i) { 
        obj = new Object(); 
        System.out.println("obj= "+ obj); 
    } 
    … … 

    采用上面的第二种编写方式,仅在内存中保存一份对该对象的引用,而不像上面的第一种编写方式中代码会在内存中产生大量的对象应用,浪费大量的内存空间,而且增大了系统做垃圾回收的负荷。因此在循环体中声明创建对象的编写方式应该尽量避免。

    另外,不要对一个对象进行多次初始化,这同样会带来较大的内存开销,降低系统性能,如:

    public class A { 
        private Hashtable table = new Hashtable (); 
        public A() { 
            // 将Hashtable对象table初始化了两次 
            table = new Hashtable(); 
        } 
    } 

    正确的方式为:

    public class B { 
         private Hashtable table = new Hashtable (); 
         public B() { 
         } 
    } 

    不要小看这个差别,它却使应用软件的性能相差甚远,如图2-5所示。

     

     

    图2-5  初始化对象多次所带来的性能差别

    看来在程序设计中也应该遵从“勿以恶小而为之”的古训,否则我们开发出来的应用也是低效的应用,有时应用软件中的一个极小的失误,就会大幅度地降低整个系统的性能。因此,我们在日常的应用开发中,应该认真对待每一行代码,采用最优化的编写方式,不要忽视细节,不要忽视潜在的问题。

    应用阶段

    当对象的创建阶段结束之后,该对象通常就会进入对象的应用阶段。这个阶段是对象得以表现自身能力的阶段。也就是说对象的应用阶段是对象整个生命周期中证明自身“存在价值”的时期。在对象的应用阶段,对象具备下列特征:

    ◆系统至少维护着对象的一个强引用(Strong Reference);

    ◆所有对该对象的引用全部是强引用(除非我们显式地使用了:软引用(Soft Reference)、弱引用(Weak Reference)或虚引用(Phantom Reference))。

    上面提到了几种不同的引用类型。可能一些读者对这几种引用的概念还不是很清楚,下面分别对之加以介绍。在讲解这几种不同类型的引用之前,我们必须先了解一下Java中对象引用的结构层次。

    Java对象引用的结构层次示意如图2-6所示。

     

    图2-6  对象引用的结构层次示意

    由图2-6我们不难看出,上面所提到的几种引用的层次关系,其中强引用处于顶端,而虚引用则处于底端。下面分别予以介绍。

    1.强引用

    强引用(Strong Reference)是指JVM内存管理器从根引用集合(Root Set)出发遍寻堆中所有到达对象的路径。当到达某对象的任意路径都不含有引用对象时,对这个对象的引用就被称为强引用。

    2.软引用

    软引用(Soft Reference)的主要特点是具有较强的引用功能。只有当内存不够的时候,才回收这类内存,因此在内存足够的时候,它们通常不被回收。另外,这些引用对象还能保证在Java抛出OutOfMemory 异常之前,被设置为null。它可以用于实现一些常用资源的缓存,实现Cache的功能,保证最大限度的使用内存而不引起OutOfMemory。再者,软可到达对象的所有软引用都要保证在虚拟机抛出OutOfMemoryError之前已经被清除。否则,清除软引用的时间或者清除不同对象的一组此类引用的顺序将不受任何约束。然而,虚拟机实现不鼓励清除最近访问或使用过的软引用。下面是软引用的实现代码:

    … … 
    import java.lang.ref.SoftReference; 
    … 
    A a = new A(); 
    … 
    // 使用 a 
    … 
    // 使用完了a,将它设置为soft 引用类型,并且释放强引用; 
    SoftReference sr = new SoftReference(a); 
    a = null; 
    … 
    // 下次使用时 
    if (sr!=null) { 
         a = sr.get(); 
    } 
    else{ 
         // GC由于内存资源不足,可能系统已回收了a的软引用, 
         // 因此需要重新装载。 
         a = new A(); 
         sr=new SoftReference(a); 
    } 
    … … 

    软引用技术的引进,使Java应用可以更好地管理内存,稳定系统,防止系统内存溢出,避免系统崩溃(crash)。因此在处理一些占用内存较大而且声明周期较长,但使用并不频繁的对象时应尽量应用该技术。正像上面的代码一样,我们可以在对象被回收之后重新创建(这里是指那些没有保留运行过程中状态的对象),提高应用对内存的使用效率,提高系统稳定性。但事物总是带有两面性的,有利亦有弊。在某些时候对软引用的使用会降低应用的运行效率与性能,例如:应用软引用的对象的初始化过程较为耗时,或者对象的状态在程序的运行过程中发生了变化,都会给重新创建对象与初始化对象带来不同程度的麻烦,有些时候我们要权衡利弊择时应用。

    3.弱引用

    弱引用(Weak Reference)对象与Soft引用对象的最大不同就在于:GC在进行回收时,需要通过算法检查是否回收Soft引用对象,而对于Weak引用对象, GC总是进行回收。因此Weak引用对象会更容易、更快被GC回收。虽然,GC在运行时一定回收Weak引用对象,但是复杂关系的Weak对象群常常需要好几次GC的运行才能完成。Weak引用对象常常用于Map数据结构中,引用占用内存空间较大的对象,一旦该对象的强引用为null时,对这个对象引用就不存在了,GC能够快速地回收该对象空间。与软引用类似我们也可以给出相应的应用代码:

    … … 
    import java.lang.ref.WeakReference; 
    … 
    A a = new A(); 
    … 
    // 使用 a 
    … 
    // 使用完了a,将它设置为weak 引用类型,并且释放强引用; 
    WeakReference wr = new WeakReference (a); 
    a = null; 
    … 
    // 下次使用时 
    if (wr!=null) { 
        a = wr.get(); 
    } 
    else{ 
        a = new A(); 
        wr = new WeakReference (a); 
    } 
    … … 

    弱引用技术主要适用于实现无法防止其键(或值)被回收的规范化映射。另外,弱引用分为“短弱引用(Short Week Reference)”和“长弱引用(Long Week Reference)”,其区别是长弱引用在对象的Finalize方法被GC调用后依然追踪对象。基于安全考虑,不推荐使用长弱引用。因此建议使用下面的方式创建对象的弱引用。

    … … 
    WeakReference wr = new WeakReference(obj); 
    或 
    WeakReference wr = new WeakReference(obj, false); 
    … … 

    4.虚引用

    虚引用(Phantom Reference)的用途较少,主要用于辅助finalize函数的使用。Phantom对象指一些执行完了finalize函数,并且为不可达对象,但是还没有被GC回收的对象。这种对象可以辅助finalize进行一些后期的回收工作,我们通过覆盖Reference的clear()方法,增强资源回收机制的灵活性。虚引用主要适用于以某种比 java 终结机制更灵活的方式调度 pre-mortem 清除操作。

    &注意  在实际程序设计中一般很少使用弱引用与虚引用,使用软引用的情况较多,这是因为软引用可以加速JVM对垃圾内存的回收速度,可以维护系统的运行安全,防止内存溢出(OutOfMemory)等问题的产生。

    不可视阶段

    在一个对象经历了应用阶段之后,那么该对象便处于不可视阶段,说明我们在其他区域的代码中已经不可以再引用它,其强引用已经消失,例如,本地变量超出了其可视范围,如下所示。

    … … 
    public void process () { 
        try { 
             Object obj = new Object(); 
             obj.doSomething(); 
         } catch (Exception e) { 
         e.printStackTrace(); 
         } 
         while (isLoop) { // ... loops forever 
          // 这个区域对于obj对象来说已经是不可视的了 
             // 因此下面的代码在编译时会引发错误 
             obj.doSomething();  
         } 
    } 
    … … 

    如果一个对象已使用完,而且在其可视区域不再使用,此时应该主动将其设置为空(null)。可以在上面的代码行obj.doSomething();下添加代码行obj = null;,这样一行代码强制将obj对象置为空值。这样做的意义是,可以帮助JVM及时地发现这个垃圾对象,并且可以及时地回收该对象所占用的系统资源。

    不可到达阶段

    处于不可到达阶段的对象,在虚拟机所管理的对象引用根集合中再也找不到直接或间接的强引用,这些对象通常是指所有线程栈中的临时变量,所有已装载的类的静态变量或者对本地代码接口(JNI)的引用。这些对象都是要被垃圾回收器回收的预备对象,但此时该对象并不能被垃圾回收器直接回收。其实所有垃圾回收算法所面临的问题是相同的——找出由分配器分配的,但是用户程序不可到达的内存块。

    可收集阶段、终结阶段与释放阶段

    对象生命周期的最后一个阶段是可收集阶段、终结阶段与释放阶段。当对象处于这个阶段的时候,可能处于下面三种情况:

    (1)垃圾回收器发现该对象已经不可到达。

    (2)finalize方法已经被执行。

    (3)对象空间已被重用。

    当对象处于上面的三种情况时,该对象就处于可收集阶段、终结阶段与释放阶段了。虚拟机就可以直接将该对象回收了。





    Java 类生命周期


            最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明白的,主要是因为目前国内java方面的教材大多只是告诉你“怎样做”,但至于“为什么这样做”却不多说,所以造成大家在基础和原理方面的知识比较匮乏,所以笔者今天就斗胆来讲一下这个问题,权当抛砖引玉,希望对在这个问题上有疑惑的朋友有所帮助,文中有说的不对的地方,也希望各路高手前来指正。

            首先来了解一下jvm(java虚拟机)中的几个比较重要的内存区域,这几个区域在java类的生命周期中扮演着比较重要的角色:

    • 方法区:在java的虚拟机中有一块专门用来存放已经加载的类信息、常量、静态变量以及方法代码的内存区域,叫做方法区。
    • 常量池:常量池是方法区的一部分,主要用来存放常量和类中的符号引用等信息。
    • 堆区:用于存放类的对象实例。
    • 栈区:也叫java虚拟机栈,是由一个一个的栈帧组成的后进先出的栈式结构,栈桢中存放方法运行时产生的局部变量、方法出口等信息。当调用一个方法时,虚拟机栈中就会创建一个栈帧存放这些数据,当方法调用完成时,栈帧消失,如果方法中调用了其他方法,则继续在栈顶创建新的栈桢。

            除了以上四个内存区域之外,jvm中的运行时内存区域还包括本地方法栈程序计数器,这两个区域与java类的生命周期关系不是很大,在这里就不说了,感兴趣的朋友可以自己百度一下。



    类的生命周期

            当我们编写一个java的源文件后,经过编译会生成一个后缀名为class的文件,这种文件叫做字节码文件,只有这种字节码文件才能够在java虚拟机中运行,java类的生命周期就是指一个class文件从加载到卸载的全过程。

            一个java类的完整的生命周期会经历加载、连接、初始化、使用、和卸载五个阶段,当然也有在加载或者连接之后没有被初始化就直接被使用的情况,如图所示:

     

     

    下面我们就依次来说一说这五个阶段。

     

    加载

           在java中,我们经常会接触到一个词——类加载,它和这里的加载并不是一回事,通常我们说类加载指的是类的生命周期中加载、连接、初始化三个阶段。在加载阶段,java虚拟机会做什么工作呢?其实很简单,就是找到需要加载的类并把类的信息加载到jvm的方法区中,然后在堆区中实例化一个java.lang.Class对象,作为方法区中这个类的信息的入口。

           类的加载方式比较灵活,我们最常用的加载方式有两种,一种是根据类的全路径名找到相应的class文件,然后从class文件中读取文件内容;另一种是从jar文件中读取。另外,还有下面几种方式也比较常用:

    • 从网络中获取:比如10年前十分流行的Applet。
    • 根据一定的规则实时生成,比如设计模式中的动态代理模式,就是根据相应的类自动生成它的代理类。
    • 从非class文件中获取,其实这与直接从class文件中获取的方式本质上是一样的,这些非class文件在jvm中运行之前会被转换为可被jvm所识别的字节码文件。

           对于加载的时机,各个虚拟机的做法并不一样,但是有一个原则,就是当jvm“预期”到一个类将要被使用时,就会在使用它之前对这个类进行加载。比如说,在一段代码中出现了一个类的名字,jvm在执行这段代码之前并不能确定这个类是否会被使用到,于是,有些jvm会在执行前就加载这个类,而有些则在真正需要用的时候才会去加载它,这取决于具体的jvm实现。我们常用的hotspot虚拟机是采用的后者,就是说当真正用到一个类的时候才对它进行加载。

           加载阶段是类的生命周期中的第一个阶段,加载阶段之后,是连接阶段。有一点需要注意,就是有时连接阶段并不会等加载阶段完全完成之后才开始,而是交叉进行,可能一个类只加载了一部分之后,连接阶段就已经开始了。但是这两个阶段总的开始时间和完成时间总是固定的:加载阶段总是在连接阶段之前开始,连接阶段总是在加载阶段完成之后完成。

     

    连接

           连接阶段比较复杂,一般会跟加载阶段和初始化阶段交叉进行,这个阶段的主要任务就是做一些加载后的验证工作以及一些初始化前的准备工作,可以细分为三个步骤:验证、准备和解析。

    1. 验证:当一个类被加载之后,必须要验证一下这个类是否合法,比如这个类是不是符合字节码的格式、变量与方法是不是有重复、数据类型是不是有效、继承与实现是否合乎标准等等。总之,这个阶段的目的就是保证加载的类是能够被jvm所运行。
    2. 准备:准备阶段的工作就是为类的静态变量分配内存并设为jvm默认的初值,对于非静态的变量,则不会为它们分配内存。有一点需要注意,这时候,静态变量的初值为jvm默认的初值,而不是我们在程序中设定的初值。jvm默认的初值是这样的:
      • 基本类型(int、long、short、char、byte、boolean、float、double)的默认值为0。
      • 引用类型的默认值为null。
      • 常量的默认值为我们程序中设定的值,比如我们在程序中定义final static int a = 100,则准备阶段中a的初值就是100。
    3.  解析:这一阶段的任务就是把常量池中的符号引用转换为直接引用。那么什么是符号引用,什么又是直接引用呢?我们来举个例子:我们要找一个人,我们现有的信息是这个人的身份证号是1234567890。只有这个信息我们显然找不到这个人,但是通过公安局的身份系统,我们输入1234567890这个号之后,就会得到它的全部信息:比如安徽省黄山市余暇村18号张三,通过这个信息我们就能找到这个人了。这里,123456790就好比是一个符号引用,而安徽省黄山市余暇村18号张三就是直接引用。在内存中也是一样,比如我们要在内存中找一个类里面的一个叫做show的方法,显然是找不到。但是在解析阶段,jvm就会把show这个名字转换为指向方法区的的一块内存地址,比如c17164,通过c17164就可以找到show这个方法具体分配在内存的哪一个区域了。这里show就是符号引用,而c17164就是直接引用。在解析阶段,jvm会将所有的类或接口名、字段名、方法名转换为具体的内存地址。

            连接阶段完成之后会根据使用的情况(直接引用还是被动引用)来选择是否对类进行初始化。

     

    初始化

           如果一个类被直接引用,就会触发类的初始化。在java中,直接引用的情况有:

    • 通过new关键字实例化对象、读取或设置类的静态变量、调用类的静态方法。
    • 通过反射方式执行以上三种行为。
    • 初始化子类的时候,会触发父类的初始化。
    • 作为程序入口直接运行时(也就是直接调用main方法)。

            除了以上四种情况,其他使用类的方式叫做被动引用,而被动引用不会触发类的初始化。请看主动引用的示例代码:

    [java]  view plain copy
    1. import java.lang.reflect.Field;  
    2. import java.lang.reflect.Method;  
    3.   
    4. class InitClass{  
    5.     static {  
    6.         System.out.println("初始化InitClass");  
    7.     }  
    8.     public static String a = null;  
    9.     public static void method(){}  
    10. }  
    11.   
    12. class SubInitClass extends InitClass{}  
    13.   
    14. public class Test1 {  
    15.   
    16.     /** 
    17.      * 主动引用引起类的初始化的第四种情况就是运行Test1的main方法时 
    18.      * 导致Test1初始化,这一点很好理解,就不特别演示了。 
    19.      * 本代码演示了前三种情况,以下代码都会引起InitClass的初始化, 
    20.      * 但由于初始化只会进行一次,运行时请将注解去掉,依次运行查看结果。 
    21.      * @param args 
    22.      * @throws Exception 
    23.      */  
    24.     public static void main(String[] args) throws Exception{  
    25.     //  主动引用引起类的初始化一: new对象、读取或设置类的静态变量、调用类的静态方法。  
    26.     //  new InitClass();  
    27.     //  InitClass.a = "";  
    28.     //  String a = InitClass.a;  
    29.     //  InitClass.method();  
    30.           
    31.     //  主动引用引起类的初始化二:通过反射实例化对象、读取或设置类的静态变量、调用类的静态方法。  
    32.     //  Class cls = InitClass.class;  
    33.     //  cls.newInstance();  
    34.           
    35.     //  Field f = cls.getDeclaredField("a");  
    36.     //  f.get(null);  
    37.     //  f.set(null, "s");  
    38.       
    39.     //  Method md = cls.getDeclaredMethod("method");  
    40.     //  md.invoke(null, null);  
    41.               
    42.     //  主动引用引起类的初始化三:实例化子类,引起父类初始化。  
    43.     //  new SubInitClass();  
    44.   
    45.     }  
    46. }  

            上面的程序演示了主动引用触发类的初始化的四种情况。

     

            类的初始化过程是这样的:按照顺序自上而下运行类中的变量赋值语句和静态语句,如果有父类,则首先按照顺序运行父类中的变量赋值语句和静态语句。先看一个例子,首先建两个类用来显示赋值操作:

    [java]  view plain copy
    1. public class Field1{  
    2.     public Field1(){  
    3.         System.out.println("Field1构造方法");  
    4.     }  
    5. }  
    6. public class Field2{  
    7.     public Field2(){  
    8.         System.out.println("Field2构造方法");  
    9.     }  
    10. }  

    下面是演示初始化顺序的代码:

    [java]  view plain copy
    1. class InitClass2{  
    2.     static{  
    3.         System.out.println("运行父类静态代码");  
    4.     }  
    5.     public static Field1 f1 = new Field1();  
    6.     public static Field1 f2;   
    7. }  
    8.   
    9. class SubInitClass2 extends InitClass2{  
    10.     static{  
    11.         System.out.println("运行子类静态代码");  
    12.     }  
    13.     public static Field2 f2 = new Field2();  
    14. }  
    15.   
    16. public class Test2 {  
    17.     public static void main(String[] args) throws ClassNotFoundException{  
    18.         new SubInitClass2();  
    19.     }  
    20. }  

            上面的代码中,初始化的顺序是:第03行,第05行,第11行,第13行。第04行是声明操作,没有赋值,所以不会被运行。而下面的代码:

    [java]  view plain copy
    1. class InitClass2{  
    2.     public static Field1 f1 = new Field1();  
    3.     public static Field1 f2;  
    4.     static{  
    5.         System.out.println("运行父类静态代码");  
    6.     }  
    7. }  
    8.   
    9. class SubInitClass2 extends InitClass2{  
    10.     public static Field2 f2 = new Field2();  
    11.     static{  
    12.         System.out.println("运行子类静态代码");  
    13.     }  
    14. }  
    15.   
    16. public class Test2 {  
    17.     public static void main(String[] args) throws ClassNotFoundException{  
    18.         new SubInitClass2();  
    19.     }  
    20. }  

            初始化顺序为:第02行、第05行、第10行、第12行,各位可以运行程序查看结果。

           在类的初始化阶段,只会初始化与类相关的静态赋值语句和静态语句,也就是有static关键字修饰的信息,而没有static修饰的赋值语句和执行语句在实例化对象的时候才会运行。

     

    使用

           类的使用包括主动引用和被动引用,主动引用在初始化的章节中已经说过了,下面我们主要来说一下被动引用:

    • 引用父类的静态字段,只会引起父类的初始化,而不会引起子类的初始化。
    • 定义类数组,不会引起类的初始化。
    • 引用类的常量,不会引起类的初始化。

    被动引用的示例代码:

    [java]  view plain copy
    1. class InitClass{  
    2.     static {  
    3.         System.out.println("初始化InitClass");  
    4.     }  
    5.     public static String a = null;  
    6.     public final static String b = "b";  
    7.     public static void method(){}  
    8. }  
    9.   
    10. class SubInitClass extends InitClass{  
    11.     static {  
    12.         System.out.println("初始化SubInitClass");  
    13.     }  
    14. }  
    15.   
    16. public class Test4 {  
    17.   
    18.     public static void main(String[] args) throws Exception{  
    19.     //  String a = SubInitClass.a;// 引用父类的静态字段,只会引起父类初始化,而不会引起子类的初始化  
    20.     //  String b = InitClass.b;// 使用类的常量不会引起类的初始化  
    21.         SubInitClass[] sc = new SubInitClass[10];// 定义类数组不会引起类的初始化  
    22.     }  
    23. }  


            最后总结一下使用阶段:使用阶段包括主动引用和被动引用,主动饮用会引起类的初始化,而被动引用不会引起类的初始化。

            当使用阶段完成之后,java类就进入了卸载阶段。

     

    卸载

           关于类的卸载,笔者在单例模式讨论篇:单例模式与垃圾回收一文中有过描述,在类使用完之后,如果满足下面的情况,类就会被卸载:

    • 该类所有的实例都已经被回收,也就是java堆中不存在该类的任何实例。
    • 加载该类的ClassLoader已经被回收。
    • 该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法。

            如果以上三个条件全部满足,jvm就会在方法区垃圾回收的时候对类进行卸载,类的卸载过程其实就是在方法区中清空类信息,java类的整个生命周期就结束了。

     

    总结

            做java的朋友对于对象的生命周期可能都比较熟悉,对象基本上都是在jvm的堆区中创建,在创建对象之前,会触发类加载(加载、连接、初始化),当类初始化完成后,根据类信息在堆区中实例化类对象,初始化非静态变量、非静态代码以及默认构造方法,当对象使用完之后会在合适的时候被jvm垃圾收集器回收。读完本文后我们知道,对象的生命周期只是类的生命周期中使用阶段的主动引用的一种情况(即实例化类对象)。而类的整个生命周期则要比对象的生命周期长的多。


    展开全文
  • vue 生命周期 created到beforeMount详解

    万次阅读 多人点赞 2018-11-08 15:03:07
    vue 生命周期 Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程。 生命周期图示: 1. beforeCreate: vue实例中的el,data,...
  • 软件生存周期

    千次阅读 2016-09-22 17:26:05
    软件生存周期又称为软件生命期,生存期。是指从形成开发软件概念起,所开发的软件使用以后,直到失去使用价值消亡为止的整个过程。
  • React生命周期及事件详解

    万次阅读 2016-03-21 10:01:31
    一、组件的详细说明和生命周期...当通过调用 React.createClass() 来创建组件的时候,你应该提供一个包含 render 方法的对象,并且也可以包含其它的这里描述的生命周期方法。 render ReactComponent render
  • Fragment生命周期详解

    万次阅读 2016-05-14 12:59:35
    Fragment生命周期详解1. Fragment概述Fragment从Android v3.0版本开始引入随着界面布局的复杂化,处理起来也更加的复杂,引入Fragment可以把activity拆分成各个部分。每个Fragment都有它自己的布局和生命周期。方便...
  • 如何快速开发一个自己的微信小程序

    万次阅读 多人点赞 2018-07-18 01:15:24
    前面 1.为什么要学小程序开发? &nbsp; &nbsp; 对于前端开发而言,微信小程序因为其简单快速、开发成本低、用户流量巨大等特点,也就成了前端开发工程师必会的一个技能。 &nbsp; 2.先看看小程序...
  • java类和对象的生命周期

    万次阅读 多人点赞 2018-07-09 06:55:00
    Java 对象生命周期在JVM运行空间中,对象的整个生命周期大致可以分为7个阶段:创建阶段(Creation)、应用阶段(Using)、不可视阶段(Invisible)、不可到达阶段(Unreachable)、可收集阶段(Collected)、终结...
  • 会使用Vue的生命周期的钩子函数 会使用vue常见指令 会使用vue计算属性和watch监控 会编写Vue组件 掌握组件间通信 0.前言 前天我们已经对后端的技术栈有了初步的了解、并且已经搭建了整个后端微服务的平台。...
  • Android之activity的生命周期

    千次阅读 2015-11-18 09:01:33
    一、四大组件之一的Activity组件,应用中一个activity可用来表示一个界面,中文意思为“活动”,即一个活动 开始,代表activity组件启动,活动结束,activity的生命周期结束。一个android应用鼻血通过activity来...
  • Java 初中级程序员如何快速成长?

    万次阅读 多人点赞 2020-03-15 22:11:05
    入职后如何快速成长到 CTO 入职后三个月试用期要做的事 三法宝,处理同事关系 核心两点,处理好领导关系 每件事都是学习的机会 主动加班,试用期加班是学习的好机会 未通过试用期,如何应对? 前三年需要学的...
  • Angular 初学者快速上手教程

    万次阅读 多人点赞 2018-04-12 10:41:37
    课程介绍 本课程是一个系列基础教程,目标是带领读者...除了组件、路由、模块这 3 个核心小节具有很强的关联性之外,其它内容都是完全独立的,您可以用到的时候再翻阅。 认真读完这个系列文章之后,您会深入理解...
  • 快速傅里叶变换学习及C语言实现

    万次阅读 多人点赞 2018-11-29 22:50:21
    参考:《算法导论》30章 从头到尾彻底理解傅里叶变换算法、上 Cooley–Tukey FFT algorithm FFT(快速傅里叶) c语言版 一、引言 首先回顾信号与系统的知识,傅里叶变换是一种从时间域转换到频率域的变换,下面列出...
  • 小程序从入门到快速开发小程序项目

    万次阅读 多人点赞 2018-08-19 21:39:39
    作者:谭东 备注:小程序只是突发灵感兴趣弄的,并非专业研究小程序,其实小程序API并不多,不复杂,扩展无非就是JS了。 ... 然后有目标的进行实践,也就是要实现个你想要的小...所以后续天就开始小程序实践和学习...
  • 程序员C语言快速上手——高级篇(十)

    千次阅读 多人点赞 2019-07-23 01:39:35
    C语言程序加载到内存中,通常可人为划分为栈(stack)、堆(heap)、代码段(text)、数据段(data)、bss 段、常量存储区等区域部分,这个基础上,人们习惯逻辑上将C语言程序的内存模型归纳为四大区域。请注意,这四大...
  • 实例对象,生命周期,模板语法,计算属性,methods方法 Vue渲染: 列表渲染,条件渲染 Vue事件与表单: 事件处理,事件对象,事件委派,表单处理 MVX模式简介: MVX框架模式:MVC+MVP+MVVM MVC: Model模型+V...
  • 项目一个迭代周期内的开发流程

    千次阅读 2013-04-26 11:00:16
    软件项目开发,一般都会采用增量、迭代、(或者叫进化、演化、演进)的软件开发模型,众多的软件开发模型大多是以经典的瀑布模型为基础进行改进、变形,改进原则是:增加客户整个项目周期中的参与度,降低软件开发...
  • 偏向锁 锁对象一次被线程获取的时候,会将当前的锁标志设置为偏向锁01状态,并使用cas操作将当前线程的id记录markword当中,如果成功那么以后的操作当中不需进行任何操作就可以进入同步代码块,当有另外一个...
  • React 快速入门

    千次阅读 2018-01-21 13:45:19
    为了控制计时的生命周期,我们需要引入 2 个方法 componentDidMount() 和 componentWillUnmount(),前者渲染(render方法)完成时立即执行,后者该 render 的内容即将被移除前执行。 很明显,前者适合注册计时...
  • 论以建筑全生命周期管理建设公司大数据平台(初稿) 李万鸿 2018 一.引言大数据、云计算、物联网、人工智能、移动技术的迅猛发展,把世界带入崭新的时代,大数据时代背景下,传统的房地产评估行业发展思路和战略...
  • JVM运行空间中,对象的整个生命周期大致可以分为7个阶段:创建阶段(Creation)、应用阶段(Using)、不可视阶段(Invisible)、不可到达阶段(Unreachable)、可收集阶段(Collected)、终结阶段(Finalized)与...
  • 因图片较多,需要图片请到资源中下载,不需要资源分。 OpenJWeb(1.8) Java Web应用快速开发平台 产品白皮书 编者:OpenJWeb技术团队编写时间:2009-10-02Email:baozhengw@163.comQQ:29803446Msn:baozhengw9

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 60,417
精华内容 24,166
关键字:

怎么快速元素在第几周期