不是网络问题wwW等别的2288titienmae88旧首页还都是正常2288titienmae88旧首页com的

404 Not Founds404 Not FoundThe requested URL was not found on this server.您要找的内容已被删除穷游大洋洲
请多多关照
累计访问(33)
篇游记 | 个精华
个相册 | 张照片
0 / 500 字
回复 @rebekah93:刚刚才看到亲的留言呢,你是需要JO哥的微信吗?
亲爱的,我觉得你写的游记很好,对于我这种不开车的又想“抠门”过日子的女生会很管用,不知道方便加你微信吗?我下月去米国逛逛~~非常谢谢~~
回复 @TiTi魔TiTi:不好意思,最近忙,现在才回复你,我的微信名“李”
回复 @李娴嘎嘎:好滴!你加他微信吧,他的微信号是bangjingxu,你的微信名是啥,我告诉他一声。
亲,你能给我下洛杉矶那个司机的联系方式吗?
为者提供原创实用的、和交流平台
https://www.baidu.com/s?wd=Hi,这是的腾讯微博,立即登录并收听,新鲜动态尽收眼底!
(@nancytiti)
在他的广播中搜索
已为您隐藏部分来自游戏、活动、第三方应用等的营销和广告微博,您可查看
Copyright & 1998 - 2018 Tencent. All Rights Reserved&p&Windows软件千千万,你最需要的是哪一款?快来跟什么值得买生活家&a href=&//link.zhihu.com/?target=https%3A//zhiyou.smzdm.com/member//& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&晏苏先生&/a&一起了解一下~&/p&&h2&什么人适合了解本篇文章?&/h2&&p&1、无法忍受电脑无止境的弹窗及各种软件广告的骚扰。&/p&&p&2、不喜欢安装各种可能存在安全隐患的破解软件。&/p&&p&3、不想折腾,不喜欢安装一大堆插件、软件,只想要简简单单使用电脑的&b&小白用户&/b&。&/p&&p&4、电脑性能一般,却想要能够稳定、流畅使用的人。&br&&/p&&h2&本篇文章推荐的软件有什么特点?&/h2&&p&1、免费&/p&&p&2、正版&/p&&p&3、无广告、不打扰&/p&&p&4、系统资源占用低&br&&/p&&h2&一、魔方软件管家 &a href=&//link.zhihu.com/?target=http%3A//mofang.ruanmei.com/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&链接&/a&&/h2&&p&在看下面的软件之前,你需要一个干净清爽的卸载工具。因为在看完本篇文章后,你有可能会用到。&/p&&p&卸载工具有很多,相信很多人用的是360或者腾讯里的「软件管家」。虽然我认为魔方软件管家在卸载的干净程度上,与3Q两家的区别不大,但还是建议使用魔方家的 。因为足够干净不扰民。&/p&&p&直接点链接或者百度搜索「魔方」,就可以进入。记得点击红框里的绿色版来下载。&/p&&p&&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-7d10b88bbf019e2cc3201e6dfb964c75_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&566& data-rawheight=&558& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&566& data-original=&https://pic2.zhimg.com/v2-7d10b88bbf019e2cc3201e6dfb964c75_r.jpg&&&/figure&&p&&br&&/p&&p&下载下来的是一个压缩包,双击打开,下滑找到「softmaster」。你可以选择双击打开,或者直接拖出来,就可以使用了。&/p&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-064c9dd5d56dae_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&439& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic1.zhimg.com/v2-064c9dd5d56dae_r.jpg&&&/figure&&p&&br&&/p&&p&魔方软件管家的界面跟其他的软件管家基本上没区别。你可以按照你往常的操作来选择是下载还是卸载软件。若是不想要用了,直接点击右上角关掉,然后删除魔方压缩包或者是softmaster的exe文件即可。无残留,不伤手,ok不?&br&&/p&&p&&b&这里再说一个很多软件管家都有,但可能大部分小白用户不会用的功能:「智能卸载」&/b&&/p&&p&&br&&/p&&figure&&img src=&https://pic3.zhimg.com/v2-22be7ab55fcaeea76a453e_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&396& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic3.zhimg.com/v2-22be7ab55fcaeea76a453e_r.jpg&&&/figure&&p&&br&&/p&&p&如果说常规卸载是软件管家文明的请被删除软件离开的话,智能卸载就是软件管家采取暴力手段,把被删除软件赶出去了。真是一个非常符合国情的功能。&/p&&p&&br&&/p&&p&国内的部分软件会刻意躲避软件管家的扫描,或者是虚与委蛇,假装自己被卸载了,其实还留了一群子子孙孙在电脑里。这时候,软件管家的‘文明’卸载模式就不起作用了,只能动用暴力手段了。&/p&&p&智能卸载的使用方式很简单,点击”浏览“,找到你想要卸载的应用,点“打开”,然后点「智能分析」,分析完成后点击「开始卸载」即可。&/p&&p&&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-f20be8d313ef0e16b913ddf82e646dd9_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&321& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic2.zhimg.com/v2-f20be8d313ef0e16b913ddf82e646dd9_r.jpg&&&/figure&&p&&br&&/p&&p&&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-2cd73de7aaee0f17f79d5_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&396& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic2.zhimg.com/v2-2cd73de7aaee0f17f79d5_r.jpg&&&/figure&&p&&br&&/p&&h2&二、百分浏览器 &a href=&//link.zhihu.com/?target=http%3A//www.centbrowser.cn/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&链接&/a&&/h2&&p&张大妈文章里推荐windows软件的千千万,但推荐这款浏览器的,怕是不会太多。&/p&&p&市面上,类似这种基于Chromium内核修改的类&a href=&//link.zhihu.com/?target=http%3A//pinpai.smzdm.com/2047/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&谷歌&/a&浏览器有很多,但这款是我用着觉得最舒服的。怎么舒服呢,我先引用一段他人对其的评价。&/p&&blockquote&百分浏览器有啥特色?为啥最近很火?有些网友甚至称呼它是迄今为止全球最好用的第三方谷歌浏览器编译增强版。它内核内置了许多网友常用的实用功能,如:免插件自带关联迅雷、支持H5弹出播放、支持网页视频视下载、鼠标手势、超级拖拽、延迟加载、小号新标签、滚动标签栏、恢复关闭标签、多标签页选项、内存自动优化、隐私保护增强等等。它还可以在选项里设置自动更新Chrome内核及内置的Flash插件版本等。&/blockquote&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-cac43f42dd6dea9e0003_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&435& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic4.zhimg.com/v2-cac43f42dd6dea9e0003_r.jpg&&&/figure&&p&百分浏览器界面&/p&&p&&b&总结其特点有以下几点:&/b&&/p&&p&1、主流浏览器该有的功能都有。&/p&&p&2、跑得快,吃得少。无论是启动还是浏览网页都很快,对系统资源的占用也小。&/p&&p&3、本地化功能齐全。&b&鼠标手势、超级拖转、网页视频下载&/b&(这三个都是我比较常用的)。&/p&&p&4、没有夹带私货。没有捆绑软件,没有强制主页,没有弹窗广告,没有垃圾插件。&/p&&p&除此之外,百分浏览器还有很多可定制的地方,只不过我貌似基本都没有使用。(我懒)&/p&&p&&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-eb779bcab7bd4f5a13fba05_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&499& data-rawheight=&804& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&499& data-original=&https://pic2.zhimg.com/v2-eb779bcab7bd4f5a13fba05_r.jpg&&&/figure&&p&&br&&/p&&p&&b&当然,这样的浏览器也是有不足的。&/b&&/p&&p&1、保存书签很麻烦。&/p&&p&2、没有办法一键切换至IE内核,&b&或许&/b&对部分网银不友好。&/p&&p&3、没有去广告功能。&/p&&p&不过,2与3的不足,可以通过官网的扩展中心,通过插件的形式解决。&/p&&p&&br&&/p&&figure&&img src=&https://pic3.zhimg.com/v2-09c4f80bf5d7db6db83f2_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&225& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic3.zhimg.com/v2-09c4f80bf5d7db6db83f2_r.jpg&&&/figure&&p&官网扩展中心&/p&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-a_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&399& data-rawheight=&372& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&content_image& width=&399&&&/figure&&p&推荐安装的插件&/p&&h2&三、火绒安全软件 &a href=&//link.zhihu.com/?target=https%3A//www.huorong.cn/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&链接&/a&&/h2&&p&在知道火绒之前,我对任何打着电脑管家安全卫士旗号的软件(比如三流零、企鹅管家、摆毒之流)都是嗤之以鼻的。因为这类软件无非就是一个比小流氓软件更大的大流氓罢了。篡改主页,弹窗广告,后台刷点击,点淘宝给你先转移到淘宝客页面,扫描&a href=&//link.zhihu.com/?target=https%3A//www.smzdm.com/fenlei/yingpan/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&硬盘&/a&数据传到&a href=&//link.zhihu.com/?target=https%3A//www.smzdm.com/fenlei/fuwuqi/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&服务器&/a&的事情,你认为它们真的没干过吗?&/p&&p&我是不信的。所以我一直都是裸奔玩机,不装任何卫士跟杀毒软件。&/p&&p&但俗话说得好,常在河边站哪有不湿鞋。 &/p&&p&我电脑的主页被修改了。在网上找了一万种(夸张)方式,都没能解决问题。甚至我还把那些大流氓卫士们挨个下载试了一遍,也还是没能解决。就在我心生绝望,准备重装系统的时候,上被人安利了火绒。一下,一用,诶嘿嘿,解决了。&/p&&p&从此成为&b&我自愿&/b&成为火绒自来水,逢人必先安利,碰到亲朋好友的电脑都会免费帮忙安装火绒(搞得跟邪教似得)。&/p&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-531d5b0cafe3dd0811df8_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&386& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic1.zhimg.com/v2-531d5b0cafe3dd0811df8_r.jpg&&&/figure&&p&火绒主界面&/p&&p&&b&火绒的特点:&/b&&/p&&p&1、不打扰。安装完之后,你可能很长一段时间都不知道自己居然装了一款电脑管家安全卫士软件。&/p&&p&2、不占内存,运行起来不卡。什么?你不信,那你把你电脑的三流零删了,装上这个试试就知道了。&/p&&p&3、完善的HIPS系统+规则导入机制。火绒的看家本领。具体解释如下,非专业人士就不用了解啦:&/p&&blockquote&HIPS是一种能监控你电脑中文件的运行和文件运用了其他的文件以及文件对注册表的修改,并向你报告请求允许的的软件。如果你阻止了,那么它将无法运行或者更改。比如你双击了一个病毒程序,HIPS软件跳出来报告而你阻止了,那么病毒还是没有运行的。引用一句话:”病毒天天变种天天出新,使得杀软可能跟不上病毒的脚步,而HIPS能解决这些问题。&br&&/blockquote&&p&简单的说,HIPS能够让火绒给我们的电脑提供更多的保护,在我们犯错误(比如点了病毒软件or全家桶软件)的时候,及时阻止。(这技术其他安全卫士也有,但是火绒做得更出色罢了。)&/p&&p&此外,通过火绒论坛上其他人分享的HIPS规则包。还可以做到屏蔽广告、阻止全家桶安装、防止在桌面生成快捷方程式等操作即可。&/p&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-e2b71ebcaed2dd0e08ae68b_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&540& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic4.zhimg.com/v2-e2b71ebcaed2dd0e08ae68b_r.jpg&&&/figure&&p&&br&&/p&&p&4、弹窗拦截。这其实也是依靠hips系统做到的。只不过火绒把一些常用的功能提取了出来,放到了扩展工具里面。&b&这是一个我最喜欢的功能。&/b&通过这个,你可以知道你电脑里的软件都会给你推送什么内容,让你清楚的认识到它们的真面目,然后统统屏蔽掉!&/p&&p&&br&&/p&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-cf5a3e5ccbbf_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&444& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic4.zhimg.com/v2-cf5a3e5ccbbf_r.jpg&&&/figure&&p&&br&&/p&&p&&b&值得一提的是&/b&,&b&很多人可能都会遇到这个问题。回到家里的时候,帮长辈查看他们电脑的时候,会发现,他们的电脑是惨不忍睹,里面全家桶横行。&/b&&/p&&p&究其原因是因为软件及一些网页会通过弹窗的形式来诱导他们点击。一旦点击了会直接在系统后台下载安装软件,还会自动打开,并且默认开机自启动。接着就是一套组合拳(绑定默认浏览器,默认压缩软件,默认播放器,默认输入法,篡改主页……)把电脑能改的地方都给改了,等到你下班回到家,看到的就是一台已经面目全非,卡得飞起的电脑。&/p&&p&面对这种问题,除了一方面要跟长辈交代不要乱点击&a href=&//link.zhihu.com/?target=https%3A//www.smzdm.com/fenlei/xianshiqi/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&显示器&/a&里的弹窗外,就是要使用一些有弹窗过滤功能的浏览器(尽量不要直接使用IE,那玩意根本没有防护能力),有弹窗拦截的软件。&br&&/p&&p&对火绒只有一句话:&b&它的好,用过才知道。&/b&&/p&&p&&br&&/p&&h2&四、bandzip压缩软件 &a href=&//link.zhihu.com/?target=https%3A//www.bandisoft.com/bandizip/cn/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&链接&/a&&/h2&&p&在压缩软件上,凡是电脑里有360的,他们的压缩软件基本是360压缩或者是好压。(捆绑的,默默给你安装的&/p&&p&&br&&/p&&p&(题外话,不知道是360压缩还是好压哪款软件。通过它压缩的文件,无法在其他没有安装过它的电脑里使用。想解压?那你只能乖乖的安装人家的压缩软件才行。简直是流氓得不要不要的。)&/p&&p&还有一部分人是使用winrar这个老牌的压缩软件。&/p&&p&少部分人用7z。这个压缩能力很强大,但是若是想要从压缩包里单独提取文件的话,比较麻烦,需要整个解压文件包,才能提取。&/p&&p&我以前是用winrar的,但后来在网上找到了bandzip,从此路转粉。&/p&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-fbf54a9cbdc52cdfd7d4_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&439& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic1.zhimg.com/v2-fbf54a9cbdc52cdfd7d4_r.jpg&&&/figure&&p&&br&&/p&&p&&b&bandzip特点:&/b&&/p&&p&1、免费。不收费,没有广告,页面干净。&/p&&p&2、支持中文。解压无乱码。&/p&&p&3、兼容性好。基本的格式都支持。&/p&&p&4、支持图片预览。不压缩文件包,直接预览图片。这个功能,很实用,很打用户痛点。&/p&&p&5、5.21mb的文件包,不大,下起来飞快。&/p&&p&最后放一张官方跟其他压缩软件对比图。&/p&&p&&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-bd2f5e80cde51_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&452& data-rawheight=&303& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&452& data-original=&https://pic2.zhimg.com/v2-bd2f5e80cde51_r.jpg&&&/figure&&p&&br&&/p&&h2&五、honeyview看图软件 &a href=&//link.zhihu.com/?target=https%3A//www.bandisoft.com/honeyview/cn/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&链接&/a&&/h2&&p&honeyview跟bandzip是同一家的软件。足够轻量,同样免费、无广告,省心。搭配bandzip使用,可以做到不解压压缩包看完包内的全部图片。&/p&&p&当然,win系统自带的照片查看器也不错,只是不能够滑动滚轮切换下一页。而win10自带的图片在高速浏览的时候,动画效果有点难受,看多了头晕。&/p&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-3eeffe9f9c_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&593& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic1.zhimg.com/v2-3eeffe9f9c_r.jpg&&&/figure&&p&顺便一提,他们家的Honeycam也很好用,拿来截取视频里面的片段做gif,也是舒服得不要不要的。但是超过8s的gif要收费就是了。(我上一篇&a href=&//link.zhihu.com/?target=https%3A//www.smzdm.com/fenlei/saodijiqiren/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&扫地机器人&/a&文章里的gif就是这个软件截的)&/p&&a href=&//link.zhihu.com/?target=https%3A//post.smzdm.com/p/654572& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic4.zhimg.com/v2-bed3fd569db2b6e226bb329ee2e69cef_ipico.jpg& data-image-width=&200& data-image-height=&200& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&米家扫地机器人 & 360扫地机器人对比评测 | 扫地机器人哪个牌子好_什么值得买&/a&&p&&br&&/p&&h2&六、potplayer视频播放器
&a href=&//link.zhihu.com/?target=http%3A//potplayer.daum.net/%3Flang%3Dzh_CN& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&链接&/a&&/h2&&p&唉,为什么那么多好用的软件都是韩国的呢?bandzip、honeyview、还有现在推荐的potplayer都是韩国的。这款视频播放器想必不需要我进行太多描述了吧。免费、功能强大,没有广告,系统占用低,好用到飞起来。&/p&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-2efba524a1843e64abf55f4aa7dd5790_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&410& data-rawheight=&412& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&content_image& width=&410&&&/figure&&p&在正版的播放器里,播放列表会有一个在线推送视频,点击右下角播放列表键可以关闭。&/p&&h2&七、Tim商务版QQ &a href=&//link.zhihu.com/?target=https%3A//go.smzdm.com/176b314d61e9119b/ca_bb_yc_163__0_1641& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&链接&/a&&/h2&&p&前身是QQ轻聊版,后来改成TIM,是一个商务版QQ。界面整洁大方,没有广告,系统占用较低,QQ正常功能俱在。如果你想找一个工作用QQ的话,这个最为合适。&/p&&p&&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-c959f8bfaa185_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&524& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic2.zhimg.com/v2-c959f8bfaa185_r.jpg&&&/figure&&p&&br&&/p&&h2&八、手心输入法 &a href=&//link.zhihu.com/?target=http%3A//www.xinshuru.com/index.html%3Fp%3Dwin& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&链接&/a&&/h2&&p&这是一个360家的输入法,却主打无广告,不骚扰。&/p&&p&&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-079a6f8c0f06b062e977f077a62d03f1_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&317& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic2.zhimg.com/v2-079a6f8c0f06b062e977f077a62d03f1_r.jpg&&&/figure&&p&&br&&/p&&p&&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-f45021ed0ecca98c76cc7dd08caf8709_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&317& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic2.zhimg.com/v2-f45021ed0ecca98c76cc7dd08caf8709_r.jpg&&&/figure&&p&&br&&/p&&p&实际体验下来,词库准确,功能齐全,&b&居然!!&/b&没有发现任何流氓行为。&/p&&p&虽然它有一个流氓爹,但是我承认它确实是那个真善美的它。&/p&&p&&br&&/p&&p&想要有一个无广告、功能齐全,词库完整的输入法。我思来想去,还是只有手心输入法可以推荐。&b&因为,就目前来说,还是它最干净的那个。&/b& &/p&&h2&总结&/h2&&p&以上推荐的八款软件都是我每次刷完系统之后,必须第一时间安装的软件。这些软件基本上涵盖了日常的使用环境,可以适用于大部分对电脑不是很懂的小白用户。&b&若是你在看了本篇文章之后,觉得这些软件有帮助到你,请记得回来给我点赞,打赏,收藏。&/b&谢谢各位观众姥爷啦。&/p&&p&&br&&/p&&p&BY:&a href=&//link.zhihu.com/?target=https%3A//zhiyou.smzdm.com/member//& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&晏苏先生&/a&&/p&&p&&b&本内容来源于@什么值得买&a href=&//link.zhihu.com/?target=http%3A//SMZDM.COM& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&SMZDM.COM&/span&&span class=&invisible&&&/span&&/a&&/b&&/p&&p&&b&原文链接:&/b&&a href=&//link.zhihu.com/?target=https%3A//post.smzdm.com/p/671477/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&#剁主计划-厦门# 给小白用户推荐的Windows必装软件_购物攻略_什么值得买&/a&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-d86c3357518cff4b993cfce06f489ec1_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&720& data-rawheight=&400& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&720& data-original=&https://pic2.zhimg.com/v2-d86c3357518cff4b993cfce06f489ec1_r.jpg&&&/figure&
Windows软件千千万,你最需要的是哪一款?快来跟什么值得买生活家一起了解一下~什么人适合了解本篇文章?1、无法忍受电脑无止境的弹窗及各种软件广告的骚扰。2、不喜欢安装各种可能存在安全隐患的破解软件。3、不想折腾,不喜欢安装一大堆插件、软…
&figure&&img src=&https://pic2.zhimg.com/v2-c0b241cc7fb55f2bab9684c_b.jpg& data-rawwidth=&1422& data-rawheight=&800& class=&origin_image zh-lightbox-thumb& width=&1422& data-original=&https://pic2.zhimg.com/v2-c0b241cc7fb55f2bab9684c_r.jpg&&&/figure&&blockquote&Android基础面试常见的30个题目,答案均为本人撰写和整理,部分图片和资料可能来源于网络,有部分题目没有整理完全后面会陆续补上,如有错误请及时指出,部分资料整理于2017年,可能和现在有所出入,请大家谅解,如果需要下载请关注公众号&b&“IT大学生”&/b&回复“Android”进行下载。&/blockquote&&p&&b&1. Activity与Fragment的生命周期。 &/b&&/p&&p&答案:&/p&&p&Activity:&/p&&figure&&img src=&https://pic3.zhimg.com/v2-6c99a027cf9e_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&545& data-rawheight=&711& class=&origin_image zh-lightbox-thumb& width=&545& data-original=&https://pic3.zhimg.com/v2-6c99a027cf9e_r.jpg&&&/figure&&p&Activity生命周期须知:&/p&&p&(1)onStart和onResume的区别:onStart实际上表示Activity已经可见了,只是我们还看不到还不能交互而已,因为它还处在后台。而onResume表示Activity已经显示到前台可见了,并且可以进行交互。&/p&&p&(2)当用户按下home键,Activity经历onPause-onStop的过程,这时重新进入Activity经历onRestart-onStart-onResume过程;如果按下back键,经历onPause-onStop-onDestroy的过程。&/p&&p&(3)当在当前ActivityA中打开一个新的ActivityB,要注意的是只有A的onPause执行完成后B的onCreate-…过程才能开始,而A的onStop则是在之后才会进行的。所以不应该在onPause中做耗时的操作,应该尽快让B显示出来进行操作才行。&/p&&p&&br&&/p&&p&Fragment:&/p&&figure&&img src=&https://pic3.zhimg.com/v2-91b2bb0dc1854066dca2_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&317& data-rawheight=&847& class=&content_image& width=&317&&&/figure&&p&对比:&/p&&p&&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-619ad9dad_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&340& data-rawheight=&675& class=&content_image& width=&340&&&/figure&&p&&br&&/p&&ol&&li&onCreate过程
&/li&&li&01-22 15:30:28.091: E/HJJ(10315): Activity &&&& onCreate...
&/li&&li&01-22 15:30:28.091: E/HJJ(10315): ArrayListFragment **** onAttach...
&/li&&li&01-22 15:30:28.091: E/HJJ(10315): ArrayListFragment **** onCreate...
&/li&&li&01-22 15:30:28.115: E/HJJ(10315): ArrayListFragment **** onCreateView...
&/li&&li&01-22 15:30:28.123: E/HJJ(10315): ArrayListFragment **** onActivityCreated...
&/li&&li&onStart过程
&/li&&li&01-22 15:30:28.123: E/HJJ(10315): Activity &&&& onStart...
&/li&&li&01-22 15:30:28.123: E/HJJ(10315): ArrayListFragment **** onStart...
&/li&&li&onResume过程
&/li&&li&01-22 15:30:28.123: E/HJJ(10315): Activity &&&& onResume...
&/li&&li&01-22 15:30:28.123: E/HJJ(10315): ArrayListFragment **** onResume...
&/li&&li&onPause过程
&/li&&li&01-22 15:31:26.748: E/HJJ(10315): ArrayListFragment **** onPause...
&/li&&li&01-22 15:31:26.748: E/HJJ(10315): Activity &&&& onPause...
&/li&&li&onStop过程
&/li&&li&01-22 15:31:27.638: E/HJJ(10315): ArrayListFragment **** onStop...
&/li&&li&01-22 15:31:27.638: E/HJJ(10315): Activity &&&& onStop...
&/li&&li&onStart过程
&/li&&li&01-22 15:31:57.537: E/HJJ(10315): Activity &&&& onStart...
&/li&&li&01-22 15:31:57.537: E/HJJ(10315): ArrayListFragment **** onStart...
&/li&&li&onResume过程
&/li&&li&01-22 15:31:57.537: E/HJJ(10315): Activity &&&& onResume...
&/li&&li&01-22 15:31:57.537: E/HJJ(10315): ArrayListFragment **** onResume...
&/li&&li&onPause过程
&/li&&li&01-22 15:32:47.412: E/HJJ(10315): ArrayListFragment **** onPause...
&/li&&li&01-22 15:32:47.412: E/HJJ(10315): Activity &&&& onPause...
&/li&&li&onStop过程
&/li&&li&01-22 15:32:47.865: E/HJJ(10315): ArrayListFragment **** onStop...
&/li&&li&01-22 15:32:47.865: E/HJJ(10315): Activity &&&& onStop...
&/li&&li&onDestroy过程
&/li&&li&01-22 15:32:47.865: E/HJJ(10315): ArrayListFragment **** onDestroyView...
&/li&&li&01-22 15:32:47.865: E/HJJ(10315): ArrayListFragment **** onDestroy...
&/li&&li&01-22 15:32:47.865: E/HJJ(10315): ArrayListFragment **** onDetach...
&/li&&li&01-22 15:32:47.865: E/HJJ(10315): Activity &&&& onDestroy...
&/li&&/ol&&p&&br&&/p&&p&&b&2. Acitivty的四种启动模式与特点。 &/b&&/p&&p&(1)标准模式(Standard)&/p&&p&系统的默认模式,每次启动一个Activity都会重新创建一个新的Activity实例,不管是否已经存在。并且谁启动了这个Activity,那么这个Activity就会运行在启动它的那个Activity的任务栈中,如果我们用ApplicationContext来启动标准模式的Activity就会报错,因为它没有所谓的任务栈,必须给Activity添加FLAG_ACTIVITY_NEW_TASK标志位。&/p&&p&(2)栈顶复用模式(singleTop)&/p&&p&在这个模式中,Activity还是会创建在启动它的Activity的任务栈中,但是如果它已经位于栈顶,那么就不会重复创建,并且它的onNewIntent会被调用,但是要注意它的生命周期方法onCreate等等不会创建。并且如果它并不位于栈顶,如ABC,这时启动B,还是会创建一个新的实例。&/p&&p&&br&&/p&&p&(3)栈内复用模式(singleTask)&/p&&p&在这个模式中,比如启动Activity A,首先系统会寻找是否存在A想要的任务栈:&/p&&p&如果存在,就看任务栈中是否有A,如果有就有clearTop的效果,把A推到栈顶,并且调用onNewIntent,即CABD的任务栈,clearTop之后就是CA;如果没有A,就创建A在栈顶。并且要注意一点,如果存在A的任务栈,那么任务栈自动回切换到前台,如下图所示:&/p&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-b18adf7ed105d826d2dd2c_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&550& data-rawheight=&309& class=&origin_image zh-lightbox-thumb& width=&550& data-original=&https://pic1.zhimg.com/v2-b18adf7ed105d826d2dd2c_r.jpg&&&/figure&&p&&br&&/p&&p&Y的任务栈直接被切换到了前台,这点和微信的聊天界面是一样的。&/p&&p&如果不存在,就创建A所需要的任务栈并且创建A入栈。&/p&&p&&b&使用场景:&/b&&/p&&p&一般来说栈内复用适用于在一个应用里我们希望唯一存在的界面,比如聊天界面,比如微信的聊天界面,我们在一个聊天界面点击了头像进入了新的界面,这个时候来了一条新的消息并且用户点击了消息,这个时候如果是Standard模式就会创建一个新的实例,这样用户在新的界面点击back,用户期望回到的是主界面,而实际上回到了之前的头像界面,这就不符合常规了。如果把聊天设为栈内唯一模式,那么用户点击之后就会回到之前的聊天界面并且做一些改变,保证了聊天界面的唯一性。浏览器的例子也是这样,我们肯定希望浏览器浏览的界面是唯一的,也需要用到这个模式。&/p&&p&&br&&/p&&p&(4)单实例模式(singleInstance)&/p&&p& 启动时,无论从哪里启动都会给A创建一个唯一的任务栈,后续的创建都不会再创建新的A,除非A被销毁了。&/p&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-ab1ded99de8d48c8252f_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&497& data-rawheight=&267& class=&origin_image zh-lightbox-thumb& width=&497& data-original=&https://pic4.zhimg.com/v2-ab1ded99de8d48c8252f_r.jpg&&&/figure&&p&&br&&/p&&p&我们看到从MainActivity跳转到SecondActivity时,重新启用了一个新的栈结构,来放置SecondActivity实例,然后按下后退键,再次回到原始栈结构;图中下半部分显示的在SecondActivity中再次跳转到MainActivity,这个时候系统会在原始栈结构中生成一个MainActivity实例,这时点击back发现一个神奇的现象,回到的还是MainActivity,然后再点击一次,&b&注意,并没有退出,而是回到了SecondActivity&/b&,为什么呢?是因为从SecondActivity跳转到MainActivity的时候,在第一个返回栈中创建了新的实例,而Second所在的成为了后台栈,所以说singleInstance不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -& B (singleInstance) -& C,完全退出后,再次启动,首先打开的是B。&/p&&p&&b&使用情况:&/b&&/p&&p&假设,我们希望我们的应用能和另一个应用共享某个Activity的实例。&/p&&p&这样说,可能很难以理解,那么举例来说: &br&1.现在我们的手机上有“某某地图”以及我们自己的应用。 &br&2.我们希望在我们的应用里共享“某某地图”当中的地图功能界面。&/p&&p&那么,假定的操作就应该为,例如: &br&1.首先,假设我们在“某某地图”里已经做了一定操作,地图界面被我们定位到了成都市。 &br&2.我们返回了HOME界面,打开了自己的应用,在自己的应用里打开了”某某地图”的地图界面。 &br&3.那么,所谓共享该Activity实例,我们要达到的效果就是,当我们打开地图界面,此时地图上显示的位置就应该是我们之前定位到的成都市。而不是地图的初始化显示方位。&/p&&p&那么,显然,通过此前的3种启动模式,我们是实现不了的。因为: &br&我们最初在“某某地图”中进行定位时,activity是位于该应用的返回栈里的。 &br&当我们在自己的应用再次调用地图界面,系统的操作是,在我们自己的应用的返回栈里新建一个地图界面Activity的实例对象。 &br&所以实际上两个“地图界面”是位于两个不同应用的各自的返回栈里的,两个毫无关联的Activity实例。&/p&&p&MainActivity位于Task“8”当中,当我们在自己的应用MainActivity当中调用SecondActivity,系统新建了返回栈Task“9”,并在该返回栈中放入一个全新的SecondActivity的实例对象。 &br&此时,当我们再打开SecondActivity本身所在的应用,调用SecondActivity,系统则会复用Task“9”当中的对象,而不会去做其他操作了。 &br&从而,也就是实现了我们的目的,在两个应用间共享某个Activity。&/p&&p&&br&&/p&&p&&b&3. Activity缓存方法。 &/b&&/p&&p&Activity的 onSaveInstanceState() 和 onRestoreInstanceState()并不是生命周期方法,它们不同于 onCreate()、onPause()等生命周期方法,它们并不一定会被触发。当应用遇到意外情况(如:内存不足、用户直接按Home键)由系统销毁一个Activity,onSaveInstanceState() 会被调用。但是当用户主动去销毁一个Activity时,例如在应用中按返回键,onSaveInstanceState()就不会被调用。除非该activity是被用户主动销毁的,通常onSaveInstanceState()只适合用于保存一些临时性的状态,而onPause()适合用于数据的持久化保存。&/p&&p&&br&&/p&&p&&b&异常情况的出现分为两种可能:&/b&&/p&&p&(1)资源相关的系统配置发生改变导致Activity被杀死并重新创建&/p&&p& 这就是我们所说的横竖屏幕切换的情况,在横竖屏切换时由于系统配置发生了改变,Activity会被销毁,其onPause,onStop,onDestroy均被调用,同时onSaveInstanceState会被调用,它的调用时机发生在onStop之前,和onPause没有时间上的先后关系。&/p&&p&(2)内存不足导致低优先级的Activity被杀死&/p&&p& 这种情况onSaveInstanceState会起作用,但是调用的时机不是被杀死时,因为被杀死时怎么会有机会调用呢?注意点2介绍了这个情况。&/p&&p&&br&&/p&&p&&b&有两点需要注意:&/b&&/p&&p&(1)使用onRestoreInstanceState来进行之前状态的获取优于onCreate,因为onRestoreInstanceState只要被调用一定说明是有值的(之前已经调用过onSaveInstanceState),但是onCreate无论是否有值一定会调用,所以没有使用onRestoreInstanceState好。&/p&&p&(2)系统正常销毁时,onSaveInstanceState不会被调用,如用户按back键。但是如果Activity有机会重新显示出来,那么onSaveInstanceState一定会调用,因为系统也不知道它是否一定会被杀死。系统不知道你按下HOME后要运行多少其他的程序,&b&自然也不知道activity A是否会被销毁,因此系统都会调用onSaveInstanceState(),让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则&/b&&/p&&ol&&li&当用户按下HOME键时 &/li&&li&长按HOME键,选择运行其他的程序时 &/li&&li&锁屏时 &/li&&li&从activity A中启动一个新的activity时 &/li&&li&屏幕方向切换时 &/li&&/ol&&p&&br&&/p&&p&&b&4. Service的生命周期,两种启动方法,有什么区别。 &/b&&/p&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-284c641e8ededada94af6c3_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&675& data-rawheight=&552& class=&origin_image zh-lightbox-thumb& width=&675& data-original=&https://pic4.zhimg.com/v2-284c641e8ededada94af6c3_r.jpg&&&/figure&&p&&br&&/p&&p&&b&(1)A started service&/b&&/p&&p&  onCreate, onStartCommand, onBind 和 onDestroy。这几个方法都是回调方法,都是由Android操作系统在合适的时机调用的,并且需要注意的是这几个回调方法都是在主线程中被调用的。&/p&&p&&b&1、onCreate&/b&: 执行startService方法时,如果Service没有运行的时候会创建该Service并执行Service的onCreate回调方法;如果Service已经处于运行中,那么执行startService方法不会执行Service的onCreate方法。也就是说如果多次执行了Context的startService方法启动Service,&b&Service方法的onCreate方法只会在第一次创建Service的时候调用一次,以后均不会再次调用!!!!&/b&我们可以在onCreate方法中完成一些Service初始化相关的操作。&/p&&p&&b&2、onStartCommand&/b&: 在执行了startService方法之后,有可能会调用Service的onCreate方法,在这之后一定会执行Service的onStartCommand回调方法。也就是说,&b&如果多次执行了Context的startService方法,那么Service的onStartCommand方法也会相应的多次调用!!!&/b&onStartCommand方法很重要,我们在该方法中根据传入的Intent参数进行实际的操作,比如会在此处创建一个线程用于下载数据或播放音乐等。&/p&&p&&b&3、onBind&/b&: Service中的onBind方法是抽象方法,所以Service类本身就是抽象类,也就是onBind方法是必须重写的,即使我们用不到。在通过startService使用Service时,我们在重写onBind方法时,只需要将其返回null即可。onBind方法主要是用于给bindService方法调用Service时才会使用到。&/p&&p&&b&4、onDestroy&/b&: 通过startService方法启动的Service会无限期运行,只有当调用了Context的stopService或在Service内部调用stopSelf方法时,Service才会停止运行并销毁,在销毁的时候会执行Service回调函数。&/p&&p&&br&&/p&&p&&b&(2)A bound service&/b&&/p&&p&被绑定的service是当其他组件(一个客户)调用&a href=&http://link.zhihu.com/?target=http%3A//developer.android.com/reference/android/content/Context.html%23bindService%28android.content.Intent%2C%2520android.content.ServiceConnection%2C%2520int%29& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&bindService()&/a&来创建的。客户可以通过一个&a href=&http://link.zhihu.com/?target=http%3A//developer.android.com/reference/android/os/IBinder.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&IBinder&/a&接口和service进行通信。客户可以通过 &a href=&http://link.zhihu.com/?target=http%3A//developer.android.com/reference/android/content/Context.html%23unbindService%28android.content.ServiceConnection%29& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&unbindService()&/a&方法来关闭这种连接。一个service可以同时和多个客户绑定,当多个客户都解除绑定之后,系统会销毁service。context.bindService()-&onCreate()-&onBind()-&Service running--&onUnbind() -& onDestroy() -&Service stop,onBind将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service运行的状态或其他操作。这个时候把调用者(Context,例如Activity)会和Service绑定在一起,当解除绑定时,只有完全没有Client与它绑定时才会调用onUnbind和onDestroy,否则都不会调用。&/p&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-ba7bcdc516f8_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&572& data-rawheight=&531& class=&origin_image zh-lightbox-thumb& width=&572& data-original=&https://pic1.zhimg.com/v2-ba7bcdc516f8_r.jpg&&&/figure&&p&&br&&/p&&p&注意:由于TestService已经处于运行状态,所以ActivityB调用bindService时,不会重新创建TestService的实例,所以也不会执行TestService的onCreate回调方法,由于在ActivityA执行bindService的时候就已经执行了TestService的onBind回调方法而获取IBinder实例,&b&并且该IBinder实例在所有的client之间是共享的,所以当ActivityB执行bindService的时候,不会执行其onBind回调方法,而是直接获取上次已经获取到的IBinder实例!!!。&/b&并将其作为参数传入ActivityB的ServiceConnection的onServiceConnected方法中,标志着ActivityB与TestService建立了绑定连接,此时有两个客户单client(ActivityA和ActivityB)与TestService绑定。&/p&&p&&br&&/p&&p&&b&(3)注意点:&/b&&/p&&p&&b&第一:这两条路径并不是完全分开的。&/b&&/p&&p&  即是说,你可以和一个已经调用了 &a href=&http://link.zhihu.com/?target=http%3A//developer.android.com/reference/android/content/Context.html%23startService%28android.content.Intent%29& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&startService()&/a&而被开启的service进行绑定。&/p&&p&比如,一个后台音乐service可能因调用 &a href=&http://link.zhihu.com/?target=http%3A//developer.android.com/reference/android/content/Context.html%23startService%28android.content.Intent%29& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&startService()&/a&方法而被开启了,稍后,可能用户想要控制播放器或者得到一些当前歌曲的信息,可以通过&a href=&http://link.zhihu.com/?target=http%3A//developer.android.com/reference/android/content/Context.html%23bindService%28android.content.Intent%2C%2520android.content.ServiceConnection%2C%2520int%29& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&bindService()&/a&将一个activity和service绑定。这种情况下,&b&&a href=&http://link.zhihu.com/?target=http%3A//developer.android.com/reference/android/content/Context.html%23stopService%28android.content.Intent%29& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&stopService()&/a&或 &a href=&http://link.zhihu.com/?target=http%3A//developer.android.com/reference/android/app/Service.html%23stopSelf%28%29& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&stopSelf()&/a&实际上并不能停止这个service,除非所有的客户都解除绑定。同样,如果是startService开启的服务及时所有客户解除绑定,如果不调用stopService,也不能停止。&/b&&/p&&p&&b&第二:除了onStartCommand可以多次调用,其他都不能&/b&&/p&&p&在Service每一次的开启关闭过程中,只有onStart可被多次调用(通过多次startService调用),其他&b&onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次!!!!&/b&&/p&&p&&br&&/p&&p&&b&5. 怎么保证service不被杀死。 &/b&&/p&&p&&b&(1)进程生命周期:&/b&&/p&&p&官方文档告诉我们,Android系统会尽量保持拥有service的进程运行,只要在该service已经被启动(start)或者客户端连接(bindService)到它。当内存不足时,需要保持,拥有service的进程具有较高的优先级。&/p&&p&1. 如果service正在调用onCreate,onStartCommand或者onDestory方法,那么用于当前service的进程则变为前台进程以避免被killed。&br&2. 如果当前service已经被启动(start),拥有它的进程则比那些用户可见的进程优先级低一些,但是比那些不可见的进程更重要,这就意味着service一般不会被killed.&br&3. &b&如果客户端已经连接到service (bindService),那么拥有Service的进程则拥有最高的优先级,可以认为service是可见的。&/b&&br&4. 如果service可以使用startForeground(int, Notification)方法来将service设置为前台状态,那么系统就认为是对用户可见的,并不会在内存不足时killed。&br&5. 如果有其他的应用组件作为Service,Activity等运行在相同的进程中,那么将会增加该进程的重要性。&/p&&p&&br&&/p&&p&(2)&/p&&p&&b&方法一:&/b&onStartCommand中返回START_STICKY,如果内存不足被杀死,那么等内存足够是系统会自动重启Service;&/p&&p&&b&方法二:&/b&提升service优先级,只是降低了被杀死的概率,但如果被杀死不会重启;&/p&&p&&b&方法三:&/b&Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收。Android将进程分为6个等级,它们按优先级顺序由高到低依次是:&/p&&p& 1.前台进程( FOREGROUND_APP)&br&
2.可视进程(VISIBLE_APP )&br&
3. 次要服务进程(SECONDARY_SERVER )&br&
4.后台进程 (HIDDEN_APP)&br&
5.内容供应节点(CONTENT_PROVIDER)&br&
6.空进程(EMPTY_APP)&/p&&p&当service运行在低内存的环境时,将会kill掉一些存在的进程。因此进程的优先级将会很重要,可以使用startForeground将service放到前台状态。这样在低内存时被kill的几率会低一些。&/p&&p& 白色方法:放一个可见的Notification,使用startForeground,如网易云音乐。&/p&&p&&b&灰色方法:&/b&它是利用系统的漏洞来启动一个前台的Service进程,与普通的启动方式区别在于,它不会在系统通知栏处出现一个Notification,看起来就如同运行着一个后台Service进程一样。这样做带来的好处就是,用户无法察觉到你运行着一个前台进程(因为看不到Notification),但你的进程优先级又是高于普通后台进程的。&/p&&p&&b&方法四:&/b&监听锁屏事件或者主Activity被关闭时,显示一个1像素的透明Activity,让进程成为前台进程。&/p&&p&&b&方法五:&/b&守护进程(Native层或者Java层),互相监听。&/p&&p&&br&&/p&&p&&b&6. 广播的两种注册方法,有什么区别。 &/b&&/p&&p&(1)两种注册方法&/p&&p&BroadcastReceiver分为两类:&/p&&ul&&li&静态广播接收者:通过AndroidManifest.xml的标签来申明的BroadcastReceiver。&/li&&li&动态广播接收者:通过AMS.registerReceiver()方式注册的BroadcastReceiver,动态注册更为灵活,可在不需要时通过unregisterReceiver()取消注册。&/li&&/ul&&p&(2)区别&/p&&p&1)静态注册:在AndroidManifest.xml注册,android不能自动销毁广播接收器,&b&也就是说当应用程序关闭后,还是会接收广播。 &br&&/b&2)动态注册:在代码中通过registerReceiver()手工注册.当程序关闭时,该接收器也会随之销毁。当然,&b&也可手工调用unregisterReceiver()进行销毁&/b&。&/p&&p&&br&&/p&&p&&b&7. Intent的使用方法,可以传递哪些数据类型。 &/b&&/p&&p&(1)使用方法&/p&&p&显示Intent比较简单,传入类即可,不再赘述。隐式Intent则需要能够匹配目标组件IntentFilter所设置的过滤信息,不匹配则无法进行调用。IntentFilter中的过滤信息有action,category,data。只有这三个都匹配成功才算完全匹配,只有完全匹配才能成功启动。并且一个Activity可以有多个IntentFilter,只需要匹配成功任何一组就可以启动。&/p&&p&&b&1、action的匹配规则&/b&&/p&&p&action的要求是必须存在,action也是我们创建Intent是传入构造函数的值。action只需要与过滤规则中的任意一个action相同即可,字符串必须完全一样(大小写也要一致)。&/p&&p&&b&2、category的匹配规则&/b&&/p&&p&也是只需要与其中一个category相同即可,如果不手动添加则默认为DEFAULT,那么想要启动成功IntentFilter中必须要加DEFAULT。&/p&&p&&b&3、data匹配规则&/b&&/p&&p&data的匹配规则与action类似,如果IntentFilter中定义了data,那么Intent也必须定义可以匹配的data。data由两部分组成,mimeType与URI,mimeType指的是媒体类型,比如image/jpeg等,而URI的组成就是它所定义的结构,分为scheme,host,port以及路径信息。只有mimeType相同并且URI匹配才行,而URI本身是有默认值的,默认值为content和file。&/p&&p&&br&&/p&&p&(2)可以传递的数据类型&/p&&p&&b&1.基本类型&/b&&/p&&p&&b&2.可序列化的类型(自定义类型需要实现序列化接口)&/b&&/p&&p&&br&&/p&&p&&b&8. ContentProvider使用方法。 &/b&&/p&&p&ContentProvider主要是用于给外界提供数据访问的方式,用于在应用间传递数据。使用方式并不复杂,只需要根据需求实现CRUD操作,然后注册在mainfest中即可。主要注意点如下:&/p&&p&(1)如果要通过uri访问不同数据,要做uri的解析工作;&/p&&p&(2)对于更新操作,要使用同步机制防止并发问题&/p&&p&(3)权限控制、防止sql注入等技术&/p&&p&&br&&/p&&p&&b&9. Thread、AsycTask、IntentService的使用场景与特点。 &/b&&/p&&p&答案:&/p&&p&&b&(1)AsyncTask&/b&&/p&&p&&b&介绍:&/b&&/p&&p&AsyncTask是一种轻量级的异步任务类,可以在后台线程池中执行后台的任务,然后把执行的进度和最终的结果传递给主线程并在主线程中更新UI。从实现上来说,AsyncTask封装了Thread和Handler。但它并不适合特别耗时的任务,对于特别耗时的任务应该使用线程池。&/p&&p&它是一个泛型抽象类,Params表示参数的类型,Progress表示后台任务进度的类型,而Result表示结果的返回类。 &/p&&p&&br&&/p&&p&&b&使用特点:&/b&&/p&&p&(1)它必须在主线程中创建,execute方法必须在主线程中调用&/p&&p& (2)execute方法只能执行一次,虽然可以传很多个参数(任务)&/p&&p&&br&&/p&&p&&b&工作原理:&/b&&/p&&p& AsyncTask实际上是对线程池和Handler进行了封装。&/p&&p&&b&(1)任务执行:&/b&&/p&&p& 3.0之前,AsyncTask是并行执行的,而3.0之后就变为了串行执行,并且开发者可以选择进行并行执行。原理是什么呢?实际上它内部有两个线程池,sDefaultExecutor是一个自己实现的串行的线程池,&b&它是static的,说明一个进程内的所有任务都是它来执行&/b&,它的任务很简单,就是把任务放进一个队列中,然后提醒另一个并行的线程池THREAD_POOL_EXECUTOR来取出执行,如果有可取的&b&并且当前没有任务在执行&/b&就会被这个并行的线程池来执行。如果有任务在执行自然不会执行,当这个任务执行完之后又会重新提醒并行的线程池THREAD_POOL_EXECUTOR来取出队列中的任务进行执行。所以从这个原理我们看出来它是串行执行的,原因就是老版本是串行的并且很多代码依赖于这个逻辑。&/p&&p&&b&(2)任务结果分发&/b&&/p&&p& 它的内部有一个static的handler,所以这也是它必须在UI线程中进行初始化的原因,这样可以保证Handler被正常的初始化。当任务执行完成后,就会将结果发送给Handler,使得其在主线程被执行。&/p&&p&&br&&/p&&p&&b&(2)IntentService&/b&&/p&&p&&b&介绍:&/b&&/p&&p&仅仅是一个封装了HandlerThread的Service而已,由于Service正常来说也是执行在主线程的,所以不能执行耗时的操作。而IntentService在内部维护有个HandlerThread,它拥有自身的Handler,对应于HandlerThread的Looper。当收到一个Intent时,它将Intent包装到Message中直接发送给Handler来处理,从而避免了在主线程中进行操作。&/p&&p&&br&&/p&&p&&b&使用:&/b&&/p&&p&重写onHandleIntent,在其中处理Intent,并且这个是不在主线程中运行的。&/p&&p&&br&&/p&&p&10. 五种布局: FrameLayout 、 LinearLayout 、 AbsoluteLayout 、 RelativeLayout 、 TableLayout 各自特点及绘制效率对比。 &/p&&p&&br&&/p&&p&11. Android的数据存储形式。 &/p&&p&(1)使用SharedPreferences存储数据&/p&&p&&b&特点:&/b&使用简单,应用内数据共享,但只支持基本数据类型。&/p&&p&(2)使用文件存储&/p&&p&(3)SQLite数据库存储&/p&&p&(4)使用ContentProvider存储数据(原理还是123中的一种,只是可以对外共享)&/p&&p&&br&&/p&&p&12. Sqlite的基本操作。 &/p&&p&&br&&/p&&p&&b&13. Android中的MVC模式以及与MVP的对比。&/b&&/p&&p&(1)Android中的MVC模式&/p&&p&传统的MVC如下图所示:&/p&&p&&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-c08ed81d5e79f912f9f64d_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&475& data-rawheight=&284& class=&origin_image zh-lightbox-thumb& width=&475& data-original=&https://pic2.zhimg.com/v2-c08ed81d5e79f912f9f64d_r.jpg&&&/figure&&p&&br&&/p&&p&当用户出发事件的时候,view层会发送指令到controller层,接着controller去通知model层更新数据,model层更新完数据以后直接显示在view层上,这就是MVC的工作原理。&/p&&p&对于原生的Android项目来说,layout.xml里面的xml文件就对应于MVC的view层,里面都是一些view的布局代码,而各种java bean,还有一些类似repository类就对应于model层,至于controller层嘛,当然就是各种activity咯。比如你的界面有一个按钮,按下这个按钮去网络上下载一个文件,这个按钮是view层的,是使用xml来写的,而那些和网络连接相关的代码写在其他类里,比如你可以写一个专门的networkHelper类,这个就是model层,那怎么连接这两层呢?是通过button.setOnClickListener()这个函数,这个函数就写在了activity中,对应于controller层。相较于传统的MVC模式,model层应该要通知View来更新数据才对,而Android中由于View层的控制能力实在太弱,通知view的代码全部放在了activity中,导致activity既算controller又算view,这样activity的代码行数太多,维护起来太过于麻烦。MVC还有一个重要的缺陷,大家看上面那幅图,view层和model层是相互可知的,这意味着两层之间存在耦合,耦合对于一个大型程序来说是非常致命的,因为这表示开发,测试,维护都需要花大量的精力。&/p&&p&&br&&/p&&p&(2)Android中的MVP模式&/p&&p&&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-a30e0e20b36e88daf6f2c5_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&514& data-rawheight=&324& class=&origin_image zh-lightbox-thumb& width=&514& data-original=&https://pic2.zhimg.com/v2-a30e0e20b36e88daf6f2c5_r.jpg&&&/figure&&p&&br&&/p&&p&MVP模式中完全把fragment看做是View层,它负责界面的更新和显示操作,而Presenter层则负责了逻辑的实现,从图中就可以看出,最明显的差别就是view层和model层不再相互可知,完全的解耦,取而代之的presenter层充当了桥梁的作用,用于操作view层发出的事件传递到presenter层中,presenter层去操作model层,并且将数据返回给view层,整个过程中view层和model层完全没有联系。一个典型的事件就是点击事件产生,view交由presenter来进行处理,处理完成之后再调用view的界面更新接口进行界面更新。Activity只是作为一个控制器来进行一些全局的控制(因为android的很多操作终究还是依赖于activity的),创建界面的时候activity对view和presenter进行相应的初始化。&/p&&p&看到这里大家可能会问,虽然view层和model层解耦了,但是view层和presenter层不是耦合在一起了吗?其实不是的,对于view层和presenter层的通信,我们是可以通过接口实现的,具体的意思就是说我们的activity,fragment可以去实现实现定义好的接口,而在对应的presenter中通过接口调用方法。不仅如此,我们还可以编写测试用的View,模拟用户的各种操作,从而实现对Presenter的测试。这就解决了MVC模式中测试,维护难的问题。&/p&&p&MVP还有一个巨大优势就是使用面向业务的方式来进行代码编写,代码架构比较清晰。&/p&&p&&br&&/p&&p&14. Merge、ViewStub的作用。 &/p&&p&&br&&/p&&p&15. Json有什么优劣势。&/p&&p&&br&&/p&&p&&b&16. 动画有哪两类,各有什么特点? &/b&&/p&&p&&b&(1)View动画(补间动画)&/b&&/p&&p&View动画的作用对象是View本身,支持四种动画效果,分别是平移动画、缩放动画、旋转动画和透明度动画。除了这四种,帧动画也属于View动画,是一种特殊的View动画。View动画可以使用xml或者代码来创建,使用set就可以把多个动画组合在一起,调用startAnimation来进行动画的调用。而帧动画就好比是把动画分为许多帧,使用xml来定义一个AnimationDrawable来进行帧动画的使用,&b&帧动画的问题时图片太多时——OOM。&/b&&/p&&p&View动画的常见作用就是ListView的item的动画,以及Activity之间变换的动画,都是有View动画实现的。而针对View动画的自定义较难,涉及到矩阵变换等知识。&/p&&p&&br&&/p&&p&&b&(2)属性动画&/b&&/p&&p& 属性动画相较于View,更加的灵活和多样。属性动画完成的效果其实就是在一个事件间隔内完成对象从一个属性值到另一个属性值的改变,效果更佳更自由。&/p&&p&1、使用注意点&/p&&p&属性动画要求提供属性的get和set方法,可是如果一个控件没有怎么办?最简单的方法就是使用包装类,继承自原始类并重写相对应属性的set和get方法,这是最简单的一种实现方式。&/p&&p&2、原理分析&/p&&p&ObjectAnimator实际上继承自ValueAnimator,主要细节如下:&/p&&p&(1)属性值的设置:使用的是反射来调用,进行属性值的获取和设置,插值器和估值器的作用就在设置之前进行计算,用来确定属性值。&/p&&p&(2)动画效果类似于我们用post实现动画一样,animationHandler实际上是一个Runnable对象,存储在当前线程的ThreadLocal中,start的时候开始执行scheduleAnimation函数, animationHandler一个线程只有一个,用于执行此线程的所有动画。而一个动画过程则是以ValueAnimator的形式存储在animationHandler自己的一个队列Animations中的。当对动画完成了设置只有调用animationHandler的start函数,它里面使用了native的方法来保证UI系统每帧都会执行自己的run函数一次(发送给Looper执行run),run中它取出自己的队列Animations中的ValueAnimator并且执行其中的doAnimationFrame。这就是真正执行动画效果的地方,并且run中有一个FrameTime是当前动画运行的时间,由native函数计算。&/p&&p&(3)doAnimationFrame的作用:它将传入的FrameTime和mStartTime进行比较,因为有可能还未开始执行。之后根据他们的差值,加上插值器和估值器的使用来计算当前应该得到的值,之后利用反射来进行动画的变化调用。&/p&&p&&br&&/p&&p&&b&17. Handler、Looper消息队列模型,各部分的作用。 &/b&&/p&&p&答案:&/p&&p&一、消息机制的角色分析 &br&首先我们介绍一下消息机制的几位主人公,正是有它们的通力合作,消息机制才能正常的运行: &br&1、Handler:处理器,负责的内容是消息的发送和具体处理流程,一般使用时由开发者重写handleMessage函数,根据自定义的不同message做不同的UI更新操作; &br&2、Message:消息对象,代表一个消息实体,存放消息的基本内容; &br&3、MessageQueue:消息队列,按顺序存放消息实体,由单链表实现,被Looper(4)所使用(一个Looper具有一个消息队列); &br&4、Looper:循环器,也是我们的消息机制的主角,一个线程至多具有一个并且与线程一一对应(如何理解等会来说),负责的内容是不断从消息队列取出放入的消息并且交由消息对应的Handler进行处理(Handler的具体handleMessage操作); &br&5、ThreadLocal:线程本地数据,是一个线程内部的数据存储类,为每个线程存储属于自己的独立的数据。&/p&&p&二、消息机制总览 &br&我们来用最简短的语言说明一下消息循环的整个过程,有个整体性的认识,之后再进行逐一的进行源码分析。 &br&1、首先,我们知道ThreadLocal是线程内部的数据存储类,一个线程对应一个自己独一无二的数据,而我们的主角Looper就是这样一个对象,每个线程都可以有自己独一无二的Looper,而Looper自己具有一个属于自己的MessageQueue,它不断地从MessageQueue中取Message(注意,Looper的代码是运行在自己对应的线程中的),如果MessageQueue中没有消息,Looper只会不断地循环尝试取消息(阻塞)。 &br&2、这时,我们在主线程创建了Handler对象,它需要它所在的线程(这里是主线程)所拥有的Looper对象(也就是说,没有Looper的线程创建不了Handler,后面我们也会看到具体代码),一旦我们用Handler发送了消息(可以在别的线程中,这里假设在某个子线程中),Handler就会把这个消息放入自己拥有的Looper对象的属于这个Looper对象的MessageQueue中(这句有点拗口,就是放入Looper的MessageQueue中)。 &br&3、我们已经知道Looper会不断地尝试从自己的MessageQueue中取出消息,我们刚刚放入的消息立刻被Looper取出来了,它得到了消息就执行了发出消息的Handler(也就是2过程我们所创建的)的消息处理函数handleMessage,我们编写的UI更新操作就在Looper对象的代码中执行了,而我们刚才也说了这个Looper运行在我们创建Handler的线程中的,也就是主线程(UI线程),那这样一来就达到了我们的目标,成功的把代码执行从子线程切换到了主线程中,这个过程我们也就有个总览了,&/p&&p&&br&&/p&&p&&b&18. 怎样退出终止App。 &/b&&/p&&p&建立一个基类Activity,在Activity创建时添加到全局表中,在Activity销毁时移除全局表,调用全局退出时,对全局表Activity进行全部退出,达到完全退出的效果。&/p&&p&&br&&/p&&p&&b&19. Assets目录与res目录的区别。 &/b&&/p&&p&assets目录与res下的raw、drawable目录一样,也可用来存放资源文件,但它们三者有区别,对比总结如下表:&/p&&figure&&img src=&https://pic2.zhimg.com/v2-08d63532a49dbd79ef018d_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&996& data-rawheight=&336& class=&origin_image zh-lightbox-thumb& width=&996& data-original=&https://pic2.zhimg.com/v2-08d63532a49dbd79ef018d_r.jpg&&&/figure&&p&(1)res/raw和asset中的文件不会被编译成2进制文件,而是原样复制到设备上,可以用文件流来读取原始文件,所以可以用来存放通用的静态文件,比如视频等;&/p&&p&(2)与res/raw不同点在于,Assets支持任意深度的子目录,这是它们的主要区别。这些文件不会生成任何资源ID,必须使用/assets开始(不包含它)的相对路径名,而res中的所有文件都会生成索引来直接访问。&/p&&p&&br&&/p&&p&20. Android怎么加速启动Activity。 &/p&&p&&br&&/p&&p&&b&21. Android内存优化方法:ListView优化,及时关闭资源,图片缓存等等。 &/b&&/p&&p&&b&(1)Bitmap的高效加载&/b&&/p&&p& 核心是利用BitmapFactory加载一个图片时(从文件系统、资源、输入流以及字节数组)中加载一个Bitmap对象的时候,选择合适的采样率进行加载,即Options参数的采样率参数对要加载的图片进行缩放,变成合适ImageView的大小的图片。缩放率是1/采样率的平方。具体做法如下:&/p&&p&&b&第一:&/b&首先设置Options的inJustDecodeBounds为true并加载图片,这样只会获取图片的参数(长宽)&/p&&p&&b&第二:&/b&根据需要的长宽对图片的长宽不停做/2操作,计算合适的采样率&/p&&p&&b&第三:&/b&根据新的采样率,重新加载图片&/p&&p&&br&&/p&&p&&b&(2)ListView(RecyclerView)的优化&/b&&/p&&p&&b&1、ListView的基础优化方式&/b&&/p&&p&(1)优化加载布局——convertView&/p&&p&通过在getView方法中使用convertView从而来避免View的重复加载,原理是复用已经离开屏幕的View,避免了View的重新加载。&/p&&p&(2)优化加载控件——ViewHolder&/p&&p& 通过给复用的view设置Tag,实际上就是避免了重新find控件的过程,将控件的引用提前设置给ViewHolder,让其持有,这样重新设置数据复用是的速度更快。&/p&&p&&br&&/p&&p&&b&2、ListView的加载优化方式&/b&&/p&&p&(1)加载图片时使用压缩方式——Bitmap的高效加载&/p&&p&(2)异步加载过程&/p&&p&(3)缓存加载,利用缓存避免重复加载&/p&&p&优化详情见优化方法整理。&/p&&p&&br&&/p&&p&&b&22. Android中弱引用与软引用的应用场景。 &/b&&/p&&p&&b&(1)弱引用&/b&&/p&&p&主要作用:防止内存泄漏。&/p&&p&使用场景:全局Map用于保存某种映射的时候一定一定使用弱引用来保存对象,因为全局变量一般是static的,它的声明周期一定长于单个对象,如果用弱引用保存对象,当对象被回收时,如果使用强引用,对象就会发生内存泄漏问题。&/p&&p&&b&(2)软引用&/b&&/p&&p&主要作用:缓存&/p&&p&使用场景:对于Bitmap的加载,非常耗费时间,我们希望把加载过的Bitmap做缓存来节省加载时间,可是Bitmap非常吃内存,我们又不希望发生OOM的问题,所以应该使用软引用来做缓存,这样在系统内存不足时,此部分内存又会重新被回收,避免OOM的问题、&/p&&p&&br&&/p&&p&23. Bitmap的四种属性,与每种属性队形的大小。&/p&&p&&br&&/p&&p&&b&24. View与View Group分类。自定义View过程:onMeasure()、onLayout()、onDraw()。 &/b&&/p&&p&&b&View的总体绘制过程:&/b&&/p&&p&当Activity对象被创建完成,会将DecorView添加到Window中(显示),同时创建ViewRoot的实现对象ViewRootImpl与之关联。ViewRootImpl会调用performTraversals来进行View的绘制过程。经过measure,layout,draw三个流程才能完成一个View的绘制过程,分别是用于测量宽、高;确定在父容器中的位置;绘制在屏幕上三个过程。而measure方法会调用onMeasure函数,这其中又会调用子元素的measure函数,如此反复就能完成整个View树的遍历过程。其他两个流程也同样如此。&/p&&p& measure决定了View的宽和高,测量之后就可以根据getMeasuredWidth和getMeasuredHeight来获取View测量后的宽和高,几乎等于最终的宽和高,但有例外;layout过程决定了View四个顶点的位置和实际的宽和高,完成之后可以根据getTop,getBottom,getLeft,getRight来获得四个顶点的位置,并且可以使用getWidth和getHeight来获取实际的宽和高;draw过程就决定了View的显示,完成draw才能真正显示出来。&/p&&p&&br&&/p&&p&&b&1.测量Measure过程:&/b&&/p&&p& MeasureSpec是测量规格,它是系统将View的参数根据父容器的规则转换而成的,之后根据它来测量出View的宽和高。它实际上是一个32位的int值,高二位表示SpecMode,就是测量的模式;低30位表示SpecSize,即在某种测量模式下的规格大小。&/p&&p& MeausureSpec有三种模式,常用的由两种:EXACTLY和AT_MOST。EXACTLY表示父容器已经检测出View所需要的精确大小(即父容器根据View的参数已经可以确定View的大小了),这时View的最终大小就是SpecSize的值,它对应于View参数中的match_parent和具体大小数值这两种模式;AT_MOST表示父容器指定了一个可用大小的数值,记录在SpecSize中,View的大小不能大于它,但具体的值还是看View的具体实现。它对应于View参数中的wrap_content。&/p&&p& DecorView(顶级View)的测量由窗口的大小和自身的LayoutParams决定,具体逻辑由getRootMeasureSpec决定,如果是具体值或者是match_parent,就是精确模式;如果是wrap_content就是最大模式;普通View的measure实际上是由父元素进行调用的(遍历),父元素调用child的measure之前使用getChildMeasureSpec来转换得到子元素的MeasureSpec(具体代码:艺术探索P180-181),总结而来就是与自身的参数以及父元素的SpecMode有关:1、如果View的参数是具体值,那么不管父元素的Mode是什么,子元素的Mode都是精确模式并且大小就是参数的大小;2、如果View的参数是match_parent,如果父元素的mode是精确模式那么View也是精确模式并且大小是父元素剩余的大小;如果父元素的mode是最大模式,那么View也是最大模式;3、如果View的参数是wrap_content,那么View的模式一定是最大化模式,并且不能超过父容器的剩余空间。&/p&&p&&b&View的measure过程:&/b&&/p&&p& View自身的onMeasure方法就是把MeasureSpec的Size设为最终的测量结果,这样的测量问题就是match_parent和wrap_content是一样的结果(因为wrap_content的Size是最大可用Size),所以如果自定义View直接继承自View,就需要对wrap_content进行处理,ImageView等都对wrap_content进行了特殊处理。&/p&&p&&b&ViewGroup的measure过程:&/b&&/p&&p& ViewGroup不同于View,它是一个抽象类,没有实现onMeasure方法(因为具体的Layout布局特性各不相同),但它measure时会遍历children调用measureChild,执行getChildMeasureSpec进行子元素的MeasureSpec创建,创建过程之前已经了解了,就是利用自身的Spec与子元素参数进行创建。&/p&&p&&br&&/p&&p&&b&2.确定位置Layout过程:&/b&&/p&&p& Layout的作用是ViewGroup来确定子元素的位置,当ViewGroup的位置被确定了之后,它就在自己的onLayout函数中遍历所有的子元素并调用其layout方法,确定子元素的位置,对于子元素View,layout中又会调用其onLayout函数。View和ViewGroup中都没有真正实现onLayout方法。但View和ViewGroup的layout方法是一致的,作用都是用于确定自己的位置,layout方法会调用setFrame方法来设定View的四个顶点的位置,即初始化mLeft,mRight,mTop,mBottom四个值,这样就确定了View在父元素中的位置。&/p&&p&&b&问题:getMeasuredHeight和getHeight有什么区别(同Width)?&/b&&/p&&p&在measure之后就可以使用getMeasuredHeight来进行获取测量的宽和高,而layout过程是晚于measure的,ViewGroup的setChildFrame会调用child的layout来确定child的真实位置,源代码中也可以看出layout的bottom和top就是利用getMeasuredHeight和getMeasuredWidth来计算的,所以说如果child的layout不重写,那么就是一样的!如果child的layout函数被重写,就会有不一样的结果。&/p&&p&&br&&/p&&p&&b&3.绘制draw过程:&/b&&/p&&p& OnDraw中进行绘制自己的操作。使用canvas进行绘制等等,简单来说就是利用代码画自己需要的图形。&/p&&p&&br&&/p&&p&&b&绘制过程中的旋转以及save和restore&/b&&/p&&p& Android中的旋转rotate旋转的是坐标系,也就是说旋转画布实际上画布本身的内容是不动的,不会直接把画布上已经存在的内容进行移动,只是旋转坐标系,这样旋转之后的操作全部是针对这个新的坐标系的。&/p&&p& save就是保存当前的的坐标系,之后再调用restore时,坐标系复原到save保存的状态,这两个函数restore的次数不能大于save,否则会引发异常。&/p&&p&&br&&/p&&p&&b&25. Touch事件分发机制以及滑动冲突的解决。 &/b&&/p&&p&答案:&/p&&p&&b&一、View的事件分发机制&/b&&/p&&p&事件分发机制传递的就是MotionEvent,也就是点击事件,这个传递过程就是分发的过程。&/p&&p&(1)点击事件的传递规则&/p&&p&三大函数:&/p&&p&&b&public boolean dispatchTouchEvent(MotionEvent ev)&/b&&/p&&p&这个函数用于进行事件的分发,如果这个时间能够传递给当前的View,那么这个方法一定会调用,返回的结果表示是否消耗当前事件,返回的结果受onInterceptTouchEvent和下级View的影响。&/p&&p&&b&public boolean onInterceptTouchEvent(MotionEvent ev)&/b&&/p&&p&这个函数内部调用,用于判断是否拦截某个事件,如果当前View拦截了某个事件,那么同一事件序列中,此方法不会被再次调用。&/p&&p&&b&public boolean onTouchEvent(MotionEvent ev)&/b&&/p&&p&在&b&dispatchTouchEvent&/b&中调用,用于处理点击事件,其返回结果表示是否消耗当前事件,如果不消耗,那么同一事件序列中,当前View无法再接收到事件。&/p&&p&&br&&/p&&p&伪代码:&/p&&p&public boolean dispatchTouchEvent(MotionEvent ev){&/p&&p& boolean consume =&/p&&p& if(&b&onInterceptTouchEvent(ev)&/b&){&/p&&p&
consume = &b&onTouchEvent&/b&(ev);&/p&&p&} else {&/p&&p& consume = child.&b& dispatchTouchEvent(ev);&/b&&/p&&p&}&/p&&p&&br&&/p&&p&&/p&&p&}&/p&&p&通过上述伪代码,我们可以大致得出传递的规则:&/p&&p&(1)对于一个根ViewGroup来说,点击事件产生后,首先会传递给它自己,如果它的&b&onInterceptTouchEvent&/b&返回true,那么就表示它要拦截当前事件,那么它的&b&onTouchEvent&/b&函数就会被调用;如果返回false,那么就传递给子元素,直到事件被处理。&/p&&p&(2)当一个View需要进行事件处理时,如果它设置了OnTouchListener,那么它的onTouch方法就会被调用,&b&这时事件如何处理还要看onTouch的返回值,如果返回false,那么当前View的onTouchEvent就会被调用;如果返回true,那么onTouchEvent方法将不会调用!!!!!!。&/b&由此可见,OnTouchListener的优先级高于onTouchEvent。在onTouchEvent方法中,如果当前设置有OnClickListener,那么它的onClick会被调用,其优先级最低,处于调用的末端。&/p&&p&(3)如果一个事件传递到View,如果此View的onTouchEvent返回false,就是不消耗事件,那么此View的父容器的onTouchEvent就会被调用,也就是说如果事件最终没有View处理,那么处理的人就是Activity,也就是责任链模式。&/p&&p&&br&&/p&&p&一些结论:&/p&&p&(1)同一个事件序列指的是从手指接触屏幕开始,到手指离开屏幕的过程,也就是DOWN—MOVE…MOVE—UP,这是一个事件序列。&/p&&p&(2)同一个事件序列只能被同一个View所消耗,因为一旦一个View拦截了某个事件,那么同一序列内的所有事件都会直接交给他处理。但是要注意,如果事件在之前又被别人拦截,根本不交给它处理的情况也会发生——事件拦截。&/p&&p&(3)某个View一旦开始处理事件,如果它不消耗ACTION_DOWN事件(onTouchEvent返回了false),那么同一事件序列中的其他事件都不会再交给他处理,即父元素的onTouchEvent会被调用,交给父元素来处理(责任链模式)。&/p&&p&如果某个View不处理除了ACTION_DOWN之外的其他事件,那么这个点击事件就会消失,并且当前View可以持续接收到后续事件(无论你选择不选择处理),最终消失的会被Activity处理。&/p&&p&(4)ViewGroup的onInterceptTouchEvent方法默认返回false,即不拦截任何事件,而View没有onInterceptTouchEvent函数,即不能选择是否拦截,必须拦截,但可以不处理。&/p&&p&(5)View的onTouchEvent默认都会消耗事件,返回true,除非它是不可点击的。&/p&&p&(6)对于onTouch和onClick的总结&/p&&p&&b&规律(总结):&/b&&/p&&p&(1)首先没有设置OnClickListener的情况下,onTouch的返回值表示的就是View对点击事件是否消耗,如果在DOWN事件传递过来时返回false,那么剩下的MOVE直到UP的事件都不会被onTouch接收到;如果在DOWN事件返回true,那么剩下的直到UP的事件都会接受到,无论你之后的返回值。 &br&(2)在同时设置了OnTouchListener与OnClickListener之后,情况就有些复杂了: &br&&b&情况1:&/b&如果onTouch在DOWN时返回了true,那么onTouch就和(1)一样收到剩下的所有事件,但onClick就不会被执行; &br&&b&情况2:&/b&如果onTouch在DOWN时返回了false,与(1)不同的是,onTouch尽管在DOWN时返回了false,但之后的所有事件仍能接受到,并且onClick会在之后被调用。&/p&&p&public boolean dispatchTouchEvent(MotionEvent event){
&/p&&p& ... ...
&/p&&p& if(onFilterTouchEventForSecurity(event)){
ListenerInfo li = mListenerI
if(li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
//(1)onTouch调用&/p&&p&
if(onTouchEvent(event)){
//(2)onTouchEvent调用&/p&&p&
&/p&&p& ... ...
&/p&&p&分析:&/p&&p&(1)如果没有设置OnClickListener,只设置了OnTouchListener,那么在代码(1)处就会调用onTouch,如果DOWN事件时返回了true,那么剩下的事件都会交由此View进行处理;如果返回了false,那么就会执行代码(2)处的onTouchEvent函数,如果设置了OnClickListener,就会在其中进行调用,如果没有设置,dispatchTouchEvent就会返回false,那么剩下的事件都不会交由此View进行处理; &br&(2)如果同时设置了OnTouchListener与OnClickListener,那么我们再按上面的两种情况进行分析: &br&&b&情况1:&/b&onTouch在DOWN时返回了true,那么代码(1)处就得到了真的结果,直接就返回了true,可以知道后面代码(2)处的onTouchEvent函数不会被执行,那么自然你的OnClickListener就不起作用了,onClick就不会被执行; &b&&br&情况2:&/b&onTouch在DOWN时返回了false,那么当DOWN事件传递来的时候,代码(1)处就不会得到真的结果,也就是说onTouch中你表示自己不会处理这个事件序列了,后面代码(2)处的onTouchEvent函数就会得到执行,而如果你设置了OnClickListener,View就会处于CLICKABLE状态,那么onTouchEvent函数就会返回true,又表示你可以处理这个点击事件序列了,dispatchTouchEvent就会返回true,那么这时后面的事件由于DOWN时返回true,就会统统交由此View进行处理,自然你的onTouch中也能够监听到后面的所有事件!这样上面的情况就能够得到解释了。&/p&&p&&br&&/p&&p&&b&二、滑动冲突的解决方法&/b&&/p&&p&(1)滑动冲突的类型&/p&&p&滑动冲突分为三种类型,第一类是外部和内部滑动方向不一致,第二类是外部和内部滑动方向一致,第三类是前两种嵌套的模式。&/p&&p&处理这三种类型的规则分为两类,对于第一种类型,我们可以根据滑动方向来处理,符合处理方向的分配给对应的控件;对于2、3种类型,必须根据业务上的区别来处理,某种状态的处理时间分发给对应的控件来处理。&/p&&p&(2)滑动冲突的解决方式&/p&&p&&b&解决方式一:外部拦截法&/b&&/p&&p&外部拦截法指点击事件首先都会经过父容器的拦截处理,父容器如果需要此事件就进行拦截,如果不需要此事件就不进行拦截,这样就可以解决滑动冲突问题。外部拦截法主要就是重写父容器的onInterceptTouchEvent方法,但是要注意,父容器拦截不能在ACTION_DOWN中返回true,否则之后的所有事件序列都会交给它处理,无论返回什么,因为不会再调用它的onInterceptTouchEvent函数了。所以父控件应该在ACTION_MOVE中选择是否拦截。但是这种拦截的问题是,如果拦截了,那么子控件的onClick事件将无法再出发了。&/p&&p&伪代码如下:&/p&&p&public boolean onInterceptTouchEvent(MotionEvent ev) {&br&
boolean intercepted =&br&
switch (ev.getAction()){&br&
case MotionEvent.&i&ACTION_DOWN&/i&:&br&
intercepted =&br&&br&
case MotionEvent.&i&ACTION_MOVE&/i&:&br&
if(父控件需要处理){&br&
intercepted =&br&
} else{&br&
intercepted =&br&
case MotionEvent.&i&ACTION_UP&/i&:&br&
intercepted =&br&&br&
&br&}&/p&&p&&br&&/p&&p&&br&&/p&&p&&b&解决方法二:内部拦截法&/b&&/p&&p& 内部拦截法指的是父容器不拦截任何事件,所有事件全部传递给子元素,如果子元素需要就进行消耗,否则交由父容器进行处理。这种方式需要配合ViewGroup的FLAG_DISALLOW_INTERCEPT标志位来使用。设置此标志为可以通过requestDisallowIntercept TouchEvent函数来设置,如果设置了此标志位,那么ViewGroup就无法拦截除了ACTION_DOWN之外的任何事件。这样首先我们保证ViewGroup的onInterceptTouchEvent方法除了DOWN其他都返回true,DOWN返回false,这样保证了不会拦截DOWN事件,交给它的子View进行处理;重写View的dispatchTouchEvent函数,在DOWN中设置parent.requestDisallowInterceptTouchEvent(true),这样父控件在默认的情况下DOWN之后的所有事件它都拦截不到,交由子View来处理,View在MOVE中判断父控件需要时,调用parent.requestDisallow InterceptTouchEvent(false),这样父控件的拦截又起作用了,相应的事件交给了父控件进行处理。伪代码如下:&/p&

我要回帖

更多关于 半夏titi 的文章

 

随机推荐