华为有限公司招聘2017校招待遇怎样

腾讯/华为/网易 2017年秋季校招面试经历!滴滴/乐视/涂鸦已拿offer - 知乎专栏
{"debug":false,"apiRoot":"","paySDK":"/api/js","wechatConfigAPI":"/api/wechat/jssdkconfig","name":"production","instance":"column","tokens":{"X-XSRF-TOKEN":null,"X-UDID":null,"Authorization":"oauth c3cef7c66aa9e6a1e3160e20"}}
{"database":{"Post":{"":{"contributes":[{"sourceColumn":{"lastUpdated":,"description":"一个专注互联网相关技术的专栏","permission":"COLUMN_PUBLIC","memberId":,"contributePermission":"COLUMN_PUBLIC","translatedCommentPermission":"all","canManage":true,"intro":"高效的中文IT技术平台","urlToken":"dreawer","id":21254,"imagePath":"v2-def9c21d9ca33ad157f4208.jpg","slug":"dreawer","applyReason":"0","name":"极乐科技","title":"极乐科技","url":"/dreawer","commentPermission":"COLUMN_ALL_CAN_COMMENT","canPost":true,"created":,"state":"COLUMN_NORMAL","followers":23609,"avatar":{"id":"v2-def9c21d9ca33ad157f4208","template":"/{id}_{size}.jpg"},"activateAuthorRequested":false,"following":false,"imageUrl":"/v2-def9c21d9ca33ad157f4208_l.jpg","articlesCount":513},"state":"accepted","targetPost":{"titleImage":"/v2-5f0f2b888652dcfc1aac_r.jpg","lastUpdated":,"imagePath":"v2-5f0f2b888652dcfc1aac.jpg","permission":"ARTICLE_PUBLIC","topics":[,4329],"summary":"文章来源:作者:huachao1001 华为 腾讯奇虎360网易滴滴(已拿offer)乐视(已拿offer)涂鸦(已拿offer) 好久没有写博客了,这篇文章本应该在国庆期间发表的,十月份一直要写开题报告,拖到现在。这篇文章记录的是2017年8月中旬至9月下…","copyPermission":"ARTICLE_COPYABLE","translatedCommentPermission":"all","likes":0,"origAuthorId":0,"publishedTime":"T17:32:43+08:00","sourceUrl":"","urlToken":,"id":1624093,"withContent":false,"slug":,"bigTitleImage":false,"title":"腾讯/华为/网易 2017年秋季校招面试经历!滴滴/乐视/涂鸦已拿offer","url":"/p/","commentPermission":"ARTICLE_ALL_CAN_COMMENT","snapshotUrl":"","created":,"comments":0,"columnId":21254,"content":"","parentId":0,"state":"ARTICLE_PUBLISHED","imageUrl":"/v2-5f0f2b888652dcfc1aac_r.jpg","author":{"bio":"极乐小程序商店(/)","isFollowing":false,"hash":"4b43cf6f3d97f480b3ca2c13e5b12752","uid":563500,"isOrg":false,"slug":"Dreawer","isFollowed":false,"description":"知乎专栏 && /dreawer \n极乐小程序商店 && /\n极乐科技
&& /","name":"极乐君","profileUrl":"/people/Dreawer","avatar":{"id":"v2-8cb80f97b7d5f74c7a8997cbc4089e1f","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false},"memberId":,"excerptTitle":"","voteType":"ARTICLE_VOTE_CLEAR"},"id":470287}],"title":"腾讯/华为/网易 2017年秋季校招面试经历!滴滴/乐视/涂鸦已拿offer","author":"Dreawer","content":"文章来源:作者:huachao1001华为腾讯奇虎360网易滴滴(已拿offer)乐视(已拿offer)涂鸦(已拿offer)好久没有写博客了,这篇文章本应该在国庆期间发表的,十月份一直要写开题报告,拖到现在。这篇文章记录的是2017年8月中旬至9月下旬期间博主参加的校招,记录下来给需要的人看。另外,在准备校招前期,博主将校招复习笔记整理成了电子档,下一篇文章我会把它发布出来,希望能帮助到大家。注意:本人记忆力确实不太好,很多问题都忘记了,只能挑记住的记录下来,希望大家能谅解1. 华为提前批(跪在性格测试) 一面:介绍我的项目,针对我的项目中的点询问是如何实现的Activity生命周期?为什么Activity要这么设计?这样设计有什么好处?Android与iOS运行机制上有哪些不同?为什么Android用起来没有iOS流畅?为了让Android系统更流畅,应该从哪些方面做好?如何让Service不被杀死?Android系统分层?Library层起什么作用?如果一个应用要升级需要注意哪些方面?(我回答服务端api要兼容,如果只是小bug就通过补丁方式,但是貌似面试官不满意,就引导我说数据方面的,我才知道原来是想要我说本地数据的兼容)问我有什么要问他的?还有其他的一些问题,记不太清了…. 二面:二面是一个中年男人,一开始很严肃,聊了几句后它就笑嘻嘻了。首先叫我介绍自己本科在哪读的(普通二本)家里有多少人,是农村的还是城市的,家里生活水平怎么样?有没有女朋友、女朋友是哪里人、女朋友有没有工作?为什么不留武汉(我简历填杭州),不留武汉你女朋友同意吗?选一个你收获最大的项目来谈谈?(后面就是针对我的项目一直聊~)二面大概30分钟左右,后面说我的性格测试没通过,让我重新再做一次。然而,第二次性格测试还是没通过,最终我还是因为性格测试没通过的原因,与华为无缘。。。。2. 腾讯内推TST(已拿到offer) 一面:自我介绍 跟我提简历里面的项目,如何实现的?具体原理?如果出现XXX情况,会不会出现XXX问题? Android 消息机制,Looper、消息队列等 Android事件分发机制 自定义过View吗?回答有自定义过,然后谈了下(普通View)onMeasure、onDraw。针对ViewGroup谈了下onLayout,然后还有就是需要注意onDraw不要做过于耗时的任务,防止卡顿。 Java中的多线程:Thread、Runnable Java中的同步问题?Lock、Synchronized 类的加载过程?五步 TCP与UDP区别 10万个整数中找出排序后的前10个数(Top N 问题),及其对应算法复杂度 10万个整数中,每个整数取值[0,99],找出排序后的中间位置的数(中位数) 堆排序的算法复杂度 面试官说,大概就这些了。紧接着想要挂电话的样子,我赶紧说,我可以问您几个问题吗?面试官说当然可以。我就问了以我当前的水平能否符合您们的要求?面试官说我觉得你还不错。紧接着问了一下大概等多久才能进入下一场面试,面试官说会尽快安排,可能会再周末。 上午 现场二面面试官非常nice,整个过程很挺顺利。 针对项目询问 TCP拥塞机制 手写代码,针对Top k问题 如何做到多个线程访问同一个数组,既要线程安全,同时提高读写效率(我是通过分段锁的思想,说了一下自己的想法),后面还让我手写代码实现。 还有很多内容,忘记了。。。 下午 现场三面三面面试官据说是总监,反正我是被打压的抬不起头。不得不说,总监级的人物技术确实牛逼。首先看了我的简历,然后说简历里面的项目经验太简单了。。。。 什么是内存对齐? C++内存分为几种类型?(我对C++不熟,就说了JVM中的内存分类) 如何压缩一篇文章? Java类加载过程?(这个我很熟,里面滔滔不绝,然而,得到的回应是:背的倒是挺熟) Java那些类是final?(除了String,我真的不知道还有哪些),只回答了String,面试官说,还有呢?(回答不出来了。。。)后面查了下,其实Math类也是final,面试官说日期类有很多,但是我回头查了下,还是没查到哪个日期类是final。 快结束时,面试官说,就到这里吧,你很幸运,我没有让你现场手写代码。因为我当时觉得这次面试面的很差,我就回答,我愿意尝试手写代码。然后面试官出了2道题:如何逆转字符串?如何实现“ I am Student”转为“Student am I”?两道题都很简单,剑指offer里面都有。我一听到这个问题心里就呵呵一笑了,立马说出如何实现。然后,面试官说行,就到这了。虽然炮轰式的提问,但是我的记忆力确实很差。。。目前只记得这些。。。后面想到再补充。二面完了之后,我觉得直接都挂了,因为好多跟C++相关问题我都回答不出来(毕竟我只搞Java 、Android),在面试官面前,自己确实很菜。 下午 现场HR面家在哪? 本科是哪个学校? 有没有亲戚在腾讯? 有没有女朋友? 你来深圳了,女朋友怎么办?(回答跟我一起来) 你实习过吗?回答实验室不允许我们实习,然后HR说,那相比那些实习过的人,你的优势是什么? 你有什么问题问我吗?3.
奇虎360,今天下午2:00开始,到4:30,一共面了3面:一面、二面、HR面。不得不说,360办事效率真的很高,觉得你OK,就立马给你安排下一面。360整体感觉比较偏向询问项目中的问题,所以有好的项目经验比较重要。一面:其实之前有整理一面的问题,但是是写在纸上,然后那张纸被我一不小心当垃圾扔了。。。。所以现在回想的起来的问题很少。。。手写ListView(可能是考我会不会想到ViewHolder)记性真的很差。。。想不起来了。。。总之,一面一般问的比较基础,大部分人都能通过。二面:你知道B树吗?B树用到哪些场景?用过JNI吗?生活中有没有遇到一些事情,你通过程序来解决的?针对项目问了很多问题….其他很多问题忘记了。。。。HR面:先是自我介绍。大致介绍了一些后,居然发现不知道该说什么了。有点尴尬!HR姐姐就一直看着我。。。实在看不下去了,就说,那你介绍下你做的项目吧~。大致说一下做过的项目本科学校是哪里?我回答桂电,数学专业!然后HR姐姐就说,你学数学的跟我们学计算机的枪饭碗啊!我回答第一台计算机是数学家发明的,所以不能说我是抢计算机饭碗~为什么要来北京?(其实我并不想去北京,只是360没其他地方可选~)你了解360的产品吗?用过哪些产品?你觉得360靠什么盈利?假设一个场景,你正在做一个app,deadline快到了,但是产品设计提出新的需求你会怎么办?新功能到底加不加?(加的话可能有新BUG,不加的会如何跟产品设计解释?)其他问题忘记了。。。。后面得到通知,成功称为360的备胎。。。4.
下午 网易吐个槽,原本安排5:20开始面的,想着那么晚,提前过去看看能不能提前面试。从2:30就赶过去,结果直到6点才轮到我。硬是坐了一下午!一面如何让Service不被KillVolley框架原理?除了Volley你还了解哪些框架?点击事件机制?简单的算法:打印100以内的所有质数(PS:没有比这个更简单的面试手写算法题了)热补丁技术?插件化技术?如何判断对象的生死?垃圾回收算法?新生代,老年代?http与https区别?加密算法你学过哪些?hashcode与equals区别?HashMap里面的hash映射?如何实现根据Key的hashcode找到下标?HashMap做了哪些优化?二面二面的面试官基本没有准备问题,都是拿着简历对着问,所以不同人的简历可能问的差别很大。把你所知道的设计模式说出来C语言中的编译和链接过程?Java NIO是啥?进程和线程区别?其他问题基本是围绕项目问的。HR面总结3个你的性格缺点如何看待阿里抢月饼事件?如果是你你也会去写插件抢吗?如何看待百度贴吧事件?家庭情况?本科是什么专业?为什么当初会考研?为什么会选择考武汉大学?有女朋友吗? 女朋友是做什么的?最让你有成就感的事情是什么?后面还有其他公司的面试吗?现在手上有其他公司的offer吗?网易最后还是跪了,主要是二面没面好。二面面试官从我刚进门就没有给好脸色,聊不到一块去,后面我回答问题时,面试官没有正眼看过我。所以找工作这件事,运气也很重要,遇到聊得来的面试官,一切都好办。5. 滴滴(已拿offer)一面一开始一面面试官没正眼看我一眼,瞬间我就觉得,糟了,这肯定要跪了!刚开始问了几个简单的问题,我回答了后,他依然没有重视我。然后他就让我说说binder机制,我把《简单明了,彻底地理解Binder》 这篇文章跟面试官说了一遍,瞬间面试官眼睛亮了!他突然好激动,他说,今天我面了一天了,你是我面的最好的,然后立马加了我微信。后面面试官说,二面你不用面了,直接去综面。二面因为一面面试官说二面免了,所以直接去综面了。综面综面面试官没有问android相关问题,就是一直问算法、考算法。算法题目我忘记了,大致记得就是一个数组,只有2个数是相同的,其他各个数是不同的,找出这个相同的数,并且要求时间复杂度和空间复杂度都是O(n)。还有其他算法题,记不住了。6. 乐视(已拿offer)一面:相隔时间比较久,记忆的内容也不多,乐视一面面的挺久,大概1个小时。跟面试官讨论的主要问题是Binder跨进程问题,其实也就是我把我写的《简单明了,彻底地理解Binder》 这篇文章跟面试官说了一遍。然后再一起讨论设计模式什么的,当然了,面试内容也不仅仅这点,大部分问题跟前面重复,具体我也想不起来了。二面:二面面试官是负责乐视的基于webkit浏览器开发。能记下的内容不多,我记得的问题有:你觉得浏览器难点在那?然后还有就是问了一下项目相关的问题。最后给了个智力题:在平面上画线,最多能将屏幕划分为多少个区域,比如一条直线能将平面分为2个区域,2条直线最多分为4个区域,那么n条直线最多分为多少区域?HR面:拿了哪些公司offer了呀?为什么选择乐视呀?去北京离你家那么远,你能接受吗?你都拿到其他公司offer了,怎么还来面乐视呢?其他问题。。。乐视后面还给我加面了,专门打电话让我去加面。加面的面试官居然不知道我是加面的,以为我是来二面,我特意提醒了下后,他才知道。后面简单聊了下后,就让我回去了。很遗憾,虽然加面了,我最终拿到的乐视薪资依然是白菜价。7. 涂鸦(已拿offer)涂鸦是全程算法题。一面:如何判断二维坐标系中的圆和三角形是否有重叠区域?给一个二维数组,告诉你哪些坐标位置是不能行走的,计算从左上到右下有多少种走法。其他问题记不住。。。。我已经尽力了。。。。二面:二面也就几个算法题,不说了。记不住。写在最后:虽然好多问题我都忘记了,但是其实各个公司面试官问的android基础问题就那些。二面基本上都是问项目,所以建议大家一定要准备好项目,要不然二面就很难通过。另外有些二面面试官喜欢问算法,问智力题。大部分二面面试官不会问android基础。最后,我后面会把我准备校招期间的所有笔记公开给大家,敬请期待!楼主建立的交流群:Android开发交流群 —————————————————————————————————————————在学习过程如果有任何疑问,请来极乐网()提问,或者扫描下方二维码,关注极乐官方微信,在平台下方留言~","updated":"T09:32:43.000Z","canComment":false,"commentPermission":"anyone","commentCount":17,"collapsedCount":0,"likeCount":70,"state":"published","isLiked":false,"slug":"","lastestTipjarors":[{"isFollowed":false,"name":"许佳佳","headline":"博客地址:http://blog.csdn.net/double2hao","avatarUrl":"/aa317b5b0f51eb8d357dea_s.jpg","isFollowing":false,"type":"people","slug":"xu-jia-jia-5-28","bio":"心有猛虎,细嗅蔷薇。","hash":"b18e8adcd4918","uid":582200,"isOrg":false,"description":"博客地址:http://blog.csdn.net/double2hao","profileUrl":"/people/xu-jia-jia-5-28","avatar":{"id":"aa317b5b0f51eb8d357dea","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false}],"isTitleImageFullScreen":false,"rating":"none","titleImage":"/v2-5f0f2b888652dcfc1aac_r.jpg","links":{"comments":"/api/posts//comments"},"reviewers":[],"topics":[{"url":"/topic/","id":"","name":"面试经历"},{"url":"/topic/","id":"","name":"程序员面试"},{"url":"/topic/","id":"","name":"校园招聘"}],"adminClosedComment":false,"titleImageSize":{"width":800,"height":450},"href":"/api/posts/","excerptTitle":"","column":{"slug":"dreawer","name":"极乐科技"},"tipjarState":"activated","tipjarTagLine":"所有赞赏将转给原作者 极乐网鼓励优质原创","sourceUrl":"","pageCommentsCount":17,"tipjarorCount":1,"annotationAction":[],"hasPublishingDraft":false,"snapshotUrl":"","publishedTime":"T17:32:43+08:00","url":"/p/","lastestLikers":[{"bio":"Dota2 本科在读 独居","isFollowing":false,"hash":"dc2fbb9031dcd867add5f","uid":56,"isOrg":false,"slug":"xu-zhi-jian-44","isFollowed":false,"description":"","name":"稻香路哲人","profileUrl":"/people/xu-zhi-jian-44","avatar":{"id":"cbbbd96e33e4","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false},{"bio":"绝不文艺小清新","isFollowing":false,"hash":"c2bb","uid":28,"isOrg":false,"slug":"yan-ru-yu-97-90","isFollowed":false,"description":"无业游民","name":"颜如玉","profileUrl":"/people/yan-ru-yu-97-90","avatar":{"id":"v2-687a3198f24abc90ec739","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false},{"bio":"hello,world","isFollowing":false,"hash":"5844d05bcaa8be151dbaaec579fc12be","uid":398100,"isOrg":false,"slug":"sun-qi-feng-84","isFollowed":false,"description":"独立之人格,自由之思想。","name":"Linux 体育生","profileUrl":"/people/sun-qi-feng-84","avatar":{"id":"v2-b5ec6bebbb48ff07519fb62","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false},{"bio":"完美和不完美都是我","isFollowing":false,"hash":"bbe24c750d695c8c2fd0c","uid":36,"isOrg":false,"slug":"gu-xiao-feng-94","isFollowed":false,"description":"让人想念,总比想念别人好。","name":"十年猎心","profileUrl":"/people/gu-xiao-feng-94","avatar":{"id":"v2-9dafe00a0ee3efb1f7ab71fdbcf5a04f","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false},{"bio":"工业设计","isFollowing":false,"hash":"9d3fbc78192afddbdd63","uid":695700,"isOrg":false,"slug":"mu-ya-nan-49","isFollowed":false,"description":"","name":"holly-21","profileUrl":"/people/mu-ya-nan-49","avatar":{"id":"v2-ad9d873fbffc09dd4143f1","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false}],"summary":"文章来源:作者:huachao1001 华为 腾讯奇虎360网易滴滴(已拿offer)乐视(已拿offer)涂鸦(已拿offer) 好久没有写博客了,这篇文章本应该在国庆期间发表的,十月份一直要写开题报告,拖到现在。这篇文章记录的是2017年8月中旬至9月下…","reviewingCommentsCount":0,"meta":{"previous":{"isTitleImageFullScreen":true,"rating":"none","titleImage":"/50/v2-d6ef4ac5b957aa02bb463ef_xl.jpg","links":{"comments":"/api/posts//comments"},"topics":[{"url":"/topic/","id":"","name":"RxJava"},{"url":"/topic/","id":"","name":"Java"}],"adminClosedComment":false,"href":"/api/posts/","excerptTitle":"","author":{"bio":"极乐小程序商店(/)","isFollowing":false,"hash":"4b43cf6f3d97f480b3ca2c13e5b12752","uid":563500,"isOrg":false,"slug":"Dreawer","isFollowed":false,"description":"知乎专栏 && /dreawer \n极乐小程序商店 && /\n极乐科技
&& /","name":"极乐君","profileUrl":"/people/Dreawer","avatar":{"id":"v2-8cb80f97b7d5f74c7a8997cbc4089e1f","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false},"column":{"slug":"dreawer","name":"极乐科技"},"content":"来源:作者:拉丁吴前言之前就写过一篇,反响很不错,由于那篇文章的定位就是简单友好,因此尽可能的摒弃复杂的概念,只抓住关键的东西来讲,以保证大家都能看懂。不过那篇文章写完之后,我就觉得应该还得有一篇文章给RxJava做一个深入的讲解才算完美,于是就有了今天的进阶篇。因为一个团队里可能大家都会用RxJava,但是必须要有一个人很懂这个,不然碰到问题可就麻烦了。在前一篇文章中的最后,我们得出结论:RxJava就是在观察者模式的骨架下,通过丰富的操作符和便捷的异步操作来完成对于复杂业务的处理。今天我们还是就结论中的观察者模式和操作符来做深入的拓展。在进入正题之前,还是希望大家先去看看。关于观察者模式前一篇文章首先就重点谈到了观察者模式,我们认为观察者模式RxJava的骨架*。在这里不是要推翻之前的结论,而是希望从深入它的内部的去了解它的实现。依然使用之前文章中关于开关和台灯的代码//创建一个被观察者(开关)\n Observable switcher=Observable.create(new Observable.OnSubscribe&String&(){\n\n
@Override\n
public void call(Subscriber&? super String& subscriber) {\n
subscriber.onNext(\"On\");\n
subscriber.onNext(\"Off\");\n
subscriber.onNext(\"On\");\n
subscriber.onNext(\"On\");\n
subscriber.onCompleted();\n
});\n//创建一个观察者(台灯)\n Subscriber light=new Subscriber&String&() {\n
@Override\n
public void onCompleted() {\n
//被观察者的onCompleted()事件会走到这里;\n
Log.d(\"DDDDDD\",\"结束观察...\\n\");\n
@Override\n
public void onError(Throwable e) {\n
//出现错误会调用这个方法\n
@Override\n
public void onNext(String s) {\n
//处理传过来的onNext事件\n
Log.d(\"DDDDD\",\"handle this---\"+s)\n
}\n//订阅\nswitcher.subscribe(light);\n以上就是一个RxJava观察者架构,看到这样的代码不知道你会不会有一些疑惑:被观察者中的Observable.OnSubscribe是什么,有什么用?call(subscriber)方法中,subscriber哪里来的?为什么只有在订阅之后,被观察者才会开始发送消息?其实,这些问题都可以通过了解OnSubscribe来解决。那我们先来看看关于OnSubscribe的定义//上一篇文章也提到Acton1这个接口,内部只有一个待实现call()方法\n//没啥特别,人畜无害\npublic interface Action1&T& extends Action {\n
void call(T t);\n}\n//OnSubscribe继承了这个Action1接口\npublic interface OnSubscribe&T& extends Action1&Subscriber&? super T&& {\n
// OnSubscribe仍然是个接口\n
}\n那么也就是说,OnSubscribe本质上也是和 Action1一样的接口,只不过它专门用于Observable内部。而在Observable观察者的类中,OnSubscribe是它唯一的属性,同时也是Observable构造函数中唯一必须传入的参数,也就是说,只要创建了Observable,那么内部也一定有一个OnSubscribe对象。当然,Observable是没有办法直接new的,我们只能通过create(),just()等等方法创建,当然,这些方法背后去调用了new Observable(onSubscribe)public class Observable&T& {\n
//唯一的属性\n
final OnSubscribe&T& onSubscribe;\n
//构造函数,因为protected,我们只能使用create函数\n
protected Observable(OnSubscribe&T& f) {\n
this.onSubscribe = f;\n
//create(onSubscribe) 内部调用构造函数。\n
public static &T& Observable&T& create(OnSubscribe&T& f) {\n
return new Observable&T&(RxJavaHooks.onCreate(f));\n
}\n当创建了Observable和Subscribe之后,调用subscribe(subscriber)方法时,发生了什么呢?
//传入了观察者对象\n
public final Subscription subscribe(final Observer&? super T& observer) {\n
//往下调用\n
return subscribe(new ObserverSubscriber&T&(observer));\n
public final Subscription subscribe(Subscriber&? super T& subscriber) {\n
//往下调用\n
return Observable.subscribe(subscriber, this);\n
//调用到这个函数\n static &T& Subscription subscribe(Subscriber&? super T& subscriber, Observable&T& observable) {\n
// new Subscriber so onStart it\n
subscriber.onStart();\n\n
// add a significant depth to already huge call stacks.\n
// 在这里简单讲,对onSubscribe进行封装,不必紧张。\n
OnSubscribe onSubscribe=RxJavaHooks.onObservableStart(observable, observable.onSubscribe);\n\n
//这个才是重点!!!\n
//这个调用的具体实现方法就是我们创建观察者时\n
//写在Observable.create()中的call()呀\n
//而调用了那个call(),就意味着事件开始发送了\n
onSubscribe.call(subscriber);\n
//不信你往回看\n\n
return RxJavaHooks.onObservableReturn(subscriber);\n
} catch (Throwable e) {\n
return Subscriptions.unsubscribed();\n
}\n代码看到这里,我们就可以对上面三个问题做统一的回答了:onSubscribe是Observable内部唯一属性,是连接Observable和subscriber的关键,相当于连接台灯和开关的那根电线call(Subscriber&? super String& subscriber)中的subscriber,就是我们自己创建的那个观察者只有在订阅的时候,才会发生onSubscribe.call(subscriber),进而才会开始调用onNext(),onComplete()等。到这里,你是不是对于RxJava的观察者模式了解更加清晰了呢?我们用流程图复习一下刚才的过程。了解了上面这些,我们就可以更进一步做以下总结:订阅这个动作,实际上是观察者(subscriber)对象把自己传递给被观察者(observable)内部的onSubscribe。onSubscribe的工作就是调用call(subscriber)来通知被观察者发送消息给这个subscriber。以上的结论对于下面我们理解操作符的原理十分有帮助,因此一定要看明白。观察者模式介绍到这里,才敢说讲完了。关于操作符上一篇文章讲了一些操作符,并且在github上放了很多其他的操作符使用范例给大家,因此在这里不会介绍更多操作符的用法,而是讲解操作符的实现原理。他是如何拦截事件,然后变换处理之后,最后传递到观察者手中的呢?相信了解相关内容的人可能会想到lift()操作符,它本来是其他操作符做变换的基础,不过那已经是好几个版本以前的事情了。但是目前版本中RxJava已经不一样了了,直接把lift()的工作下放到每个操作符中,把lift的弱化了(但是依然保留了lift()操作符)。因此,我们在这里不必讲解lift,直接拿一个操作符做例子,来了解它的原理即可,因为基本上操作符的实现原理都是一样的。以map()为例,依然拿之前文章里面的例子:
Observable.create(new Observable.just(getFilePath())\n
//使用map操作来完成类型转换\n
.map(new Func1&String, Bitmap&() {\n
@Override\n
public Bitmap call(String s) {\n
//显然自定义的createBitmapFromPath(s)方法,是一个极其耗时的操作\n
return createBitmapFromPath(s);\n
.subscribe(\n
//创建观察者,作为事件传递的终点处理事件
new Subscriber&Bitmap&() {\n
@Override\n
public void onCompleted() {\n
Log.d(\"DDDDDD\",\"结束观察...\\n\");\n
@Override\n
public void onError(Throwable e) {\n
//出现错误会调用这个方法\n
@Override\n
public void onNext(Bitmap s) {\n
//处理事件\n
showBitmap(s)\n
);\n看看map背后到底做了什么 public final &R& Observable&R& map(Func1&? super T, ? extends R& func) {\n
//创建了全新代理的的Observable,构造函数传入的参数是OnSubscribe\n
//OnSubscribeMap显然是OnSubscribe的一个实现类,\n
//也就是说,OnSubscribeMap需要实现call()方法\n
//构造函数传入了真实的Observable对象\n
//和一个开发者自己实现的Func1的实例\n
return create(new OnSubscribeMap&T, R&(this, func));\n
}\n看OnSubscribeMap的具体实现:public final class OnSubscribeMap&T, R& implements OnSubscribe&R& {\n
//用于保存真实的Observable对象\n
final Observable&T& source;\n
//还有我们传入的那个Func1的实例\n
final Func1&? super T, ? extends R& transformer;\n\n
public OnSubscribeMap(Observable&T& source, Func1&? super T, ? extends R& transformer) {\n
this.source = source;\n
this.transformer = transformer;\n
//实现了call方法,我们知道call方法传入的Subscriber\n
//就是订阅之后,外部传入真实的的观察者\n
@Override\n
public void call(final Subscriber&? super R& o) {\n
//把外部传入的真实观察者传入到MapSubscriber,构造一个代理的观察者\n
MapSubscriber&T, R& parent = new MapSubscriber&T, R&(o, transformer);\n
o.add(parent);\n
//让外部的Observable去订阅这个代理的观察者\n
source.unsafeSubscribe(parent);\n
//Subscriber的子类,用于构造一个代理的观察者\n
static final class MapSubscriber&T, R& extends Subscriber&T& {\n
//这个Subscriber保存了真实的观察者\n
final Subscriber&? super R& actual;\n
//我们自己在外部自己定义的Func1\n
final Func1&? super T, ? extends R& mapper;\n\n
boolean done;\n\n
public MapSubscriber(Subscriber&? super R& actual, Func1&? super T, ? extends R& mapper) {\n
this.actual = actual;\n
this.mapper = mapper;\n
//外部的Observable发送的onNext()等事件\n
//都会首先传递到代理观察者这里\n
@Override\n
public void onNext(T t) {\n
R result;\n\n
//mapper其实就是开发者自己创建的Func1,\n
//call()开始变换数据\n
result = mapper.call(t);\n
} catch (Throwable ex) {\n
Exceptions.throwIfFatal(ex);\n
unsubscribe();\n
onError(OnErrorThrowable.addValueAsLastCause(ex, t));\n
//调用真实的观察者的onNext()\n
//从而在变换数据之后,把数据送到真实的观察者手中\n
actual.onNext(result);\n
//onError()方法也是一样\n
@Override\n
public void onError(Throwable e) {\n
if (done) {\n
RxJavaHooks.onError(e);\n
done = true;\n\n
actual.onError(e);\n
@Override\n
public void onCompleted() {\n
if (done) {\n
actual.onCompleted();\n
@Override\n
public void setProducer(Producer p) {\n
actual.setProducer(p);\n
}\n}\nmap操作符的原理基本上就讲完了,其他的操作符和map在原理上是一致的。假如你想创建自定义的操作符(这其实是不建议的),你应该按照上面的步骤创建一个代理的被观察者实现被观察者中onSubscribe的call方法在call方法中创建一个代理的观察者,让真实的被观察者订阅它。我知道你会有点晕,没关系,我后面会写一个自定义操作符放在上,可以关注下。下面,我们先通过一个流程图巩固一下前面学习的成果。下次你使用操作符时,心里应该清楚,每使用一个操作符,都会创建一个代理观察者和一个代理被观察者,以及他们之间是如何相互调用的。相信有了这一层的理解,今后使用RxJava应该会更加得心应手。不过最后,我想给大家留一个思考题:使用一个操作符时,流程图是这样的,那么使用多个操作符呢?勘误暂无后记到这里,关于RxJava的讲解就基本可以告一段落了,我相信,两篇文章读下来,对于RxJava的理解应该已经到了比较高的一个层次了,我的目标也就达到了。接下来....因为RxJava是一个事件的异步处理框架,理论上,他可以封装任何其他的库,那么.....—————————————————————————————————————————在学习过程如果有任何疑问,请来极乐网()提问,或者扫描下方二维码,关注极乐官方微信,在平台下方留言~","state":"published","sourceUrl":"","pageCommentsCount":0,"canComment":false,"snapshotUrl":"","slug":,"publishedTime":"T12:02:21+08:00","url":"/p/","title":"关于RxJava最友好的文章(进阶篇)","summary":"来源:作者:拉丁吴 前言之前就写过一篇,反响很不错,由于那篇文章的定位就是简单友好,因此尽可能的摒弃复杂的概念,只抓住关键的东西来讲,以保证大家都能看懂。不过那篇文章写完之后,我就觉得应该…","reviewingCommentsCount":0,"meta":{"previous":null,"next":null},"commentPermission":"anyone","commentsCount":1,"likesCount":15},"next":{"isTitleImageFullScreen":true,"rating":"none","titleImage":"/50/v2-e5a23fe3_xl.jpg","links":{"comments":"/api/posts//comments"},"topics":[{"url":"/topic/","id":"","name":"前端开发"},{"url":"/topic/","id":"","name":"JavaScript"},{"url":"/topic/","id":"","name":"Web 开发"}],"adminClosedComment":false,"href":"/api/posts/","excerptTitle":"","author":{"bio":"极乐小程序商店(/)","isFollowing":false,"hash":"4b43cf6f3d97f480b3ca2c13e5b12752","uid":563500,"isOrg":false,"slug":"Dreawer","isFollowed":false,"description":"知乎专栏 && /dreawer \n极乐小程序商店 && /\n极乐科技
&& /","name":"极乐君","profileUrl":"/people/Dreawer","avatar":{"id":"v2-8cb80f97b7d5f74c7a8997cbc4089e1f","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false},"column":{"slug":"dreawer","name":"极乐科技"},"content":"来源:问题描述这段时间在做PM的需求的时候突然发现一个问题,产品上的图片来自多个第三方,具体的尺寸无法确定,如果直接在样式中写死图片的尺寸大小就会出现图片拉伸的现象,十分影响产品的美观,因此希望可以找到一个比较好的解决方案。自己先做了一个简单的demo来展示问题。&html&\n&head&\n\t&meta http-equiv=\"Content-Type\" content=\"text/ charset=UTF-8\"&\n\t&script src=\"./js/jquery-1.11.1.min.js\"&&/script&\n\t&style&\n\t\t.img1{width:200height:200border: 1px solid #000;overflow:margin: 10}\n\t\t.img2{width:200height:90border: 1px solid #000;overflow:margin: 10}\t\n\t&/style&\n&/head&\t\n&body&\n\t&div class=\"img1\" style=\"width:\"&\n\t\t&img id=\"img1\" src=\"./img/1.jpg\" height=\"100%\" width=\"100%\"&\n\t&/div&\n\t&div class=\"img2\" style=\"width:\"&\n\t\t&img id=\"img2\" src=\"./img/1.jpg\" height=\"100%\" width=\"100%\"&\n\t&/div&\n&/body&\n&/html&\n上述这种情况还是挺影响美观的,是否可以考虑动态的设置图片的尺寸呢?解决思路是否可以在浏览器加载图片资源后,获取图片的真实尺寸和图片容器的大小,然后动态地设置图片的width、height属性。获取图片的真实尺寸 html5下已经提供了相应的方法来返回图片的真实尺寸大小(img.naturalWidth、img.naturalHeight),针对IE6/7/8也可以通过以下方法来获取真实尺寸的大小。var imgae = new Image();\n\t\timage.src = img.src;\n\t\timage.onload = function() {\n\t
\tvar w = image.width;\n\t
\tvar h = image.height;\n}\n下面就编写对应的JS方法获取图片的真实尺寸已经图片容器的尺寸大小。setImgSize : function(img, callback) {\n\tif (img.naturalWidth) { //html5\n\t\tcallback(img, img.naturalWidth, img.naturalHeight, img.width, img.height);\n\t} else { // IE 6 7 8\n\t\tvar imgae = new Image();\n\t\timage.src = img.\n\t\timage.onload = function() {\n
callback(img, image.width, image.height, img.width, img.height);\n
}\n\t}\n}\n重新设置图片尺寸在获取图片真实尺寸已经容器尺寸之后,我们需要重新设置图片的尺寸大小。这里先简单的介绍下处理目标:如果设置后的尺寸超过展示区域,则展示图片的中间部分,如果展示区域大于图片尺寸,则图片居中显示。用图简单说明下,黑色实线为图片的显示区域,绿色部分为图片的大小。下面我们提供三种方法来处理图片,分别实现上部两种(宽度一致)、下部两种(高度一致)、右侧两种(铺满显示区域),下面就分别介绍这三种方法:一、保证宽度一致//原始宽度 原始高度 容器宽度 容器高度\n//保证宽度一致\nresetImgSizeW : function(img, nw, nh, w, h) {\n\tnwh = nw / nh;\n\twh = w / h;\n\tif (nwh & wh) {\n\t\timg.width = w;\n\t\tvar height = parseInt(1 / nwh * w);\n\t\timg.height = height;\n\t\tvar top = parseInt((h - height) / 2);\n\t\timg.style.marginTop = top + \"px\";\n\t} else if (nwh & wh) {\n\t\timg.width = w;\n\t\tvar height = parseInt(1 / nwh * w);\n\t\timg.height = height;\n\t\tvar top = parseInt((height - h) / 2) * -1;\n\t\timg.style.marginTop = top + \"px\";\n\t} else {\n\t\timg.height = h;\n\t\timg.width = w;\n\t}\n},\n在这里我们需要判断图片原始尺寸的长宽比例以及容器的长宽比例之间的关系,如果高度富裕,那就相应将图片往上移动一定的像素,如果高度不足,就将图片往下移动相应的像素,至于其他的两种情况也是同样的逻辑,先看下处理后的效果:二、保证高度一致//原始宽度 原始高度 容器宽度 容器高度\n//保证高度一致\nresetImgSizeH : function(img, nw, nh, w, h) {\n\tnwh = nw / nh;\n\twh = w / h;\n\tif (nwh & wh) {\n\t\timg.height = h;\n\t\tvar width = parseInt(nwh * h);\n\t\timg.width = width;\n\t\tvar left = parseInt((width - w) / 2) * -1;\n\t\timg.style.marginLeft = left + \"px\";\n\t} else if (nwh & wh) {\n\t\timg.height = h;\n\t\tvar width = parseInt(nwh * h);\n\t\timg.width = width;\n\t\tvar left = parseInt((w - width) / 2);\n\t\timg.style.marginLeft = left + \"px\";\n\t} else {\n\t\timg.height = h;\n\t\timg.width = w;\n\t}\n}\n三、铺满显示区域//原始宽度 原始高度 容器宽度 容器高度\n//铺满全屏\nresetImgSizeWH : function(img, nw, nh, w, h) {\n\tnwh = nw / nh;\n\twh = w / h;\n\tif (nwh & wh) {\n\t\timg.height = h;\n\t\tvar width = parseInt(nwh * h);\n\t\timg.width = width;\n\t\tvar left = parseInt((width - w) / 2) * -1;\n\t\timg.style.marginLeft = left + \"px\";\n\t} else if (nwh & wh) {\n\t\timg.width = w;\n\t\tvar height = parseInt(1 / nwh * w);\n\t\timg.height = height;\n\t\tvar top = parseInt((height - h) / 2) * -1;\n\t\timg.style.marginTop = top + \"px\";\n\t} else {\n\t\timg.height = h;\n\t\timg.width = w;\n\t}\n},\n如何使用JS上面对实现的逻辑以及最终的效果做了简单的介绍,下面就介绍下如何使用。&!-- 引用js脚本 --&\n&script src=\"./js/imageLoad.js\"&&/script&\n&script&\n\tvar imageLoad = new ImageLoad();\n\t//处理网站上所有的图片,下面三种只能使用一种\n\t//imageLoad.initImg(\"w\");//保证宽度一致\n\t//imageLoad.initImg(\"h\");//保证高度一致\n\t//imageLoad.initImg(\"wh\");//铺满显示区域\n\t//处理单个图片,对于多个自己可以写循环语句来实现\n\timageLoad.setImgSize(document.getElementById(\"img1\"), imageLoad.resetImgSizeW);\n\timageLoad.setImgSize(document.getElementById(\"img2\"), imageLoad.resetImgSizeW);\n\timageLoad.setImgSize(document.getElementById(\"img3\"), imageLoad.resetImgSizeH);\n\timageLoad.setImgSize(document.getElementById(\"img4\"), imageLoad.resetImgSizeH);\n\timageLoad.setImgSize(document.getElementById(\"img5\"), imageLoad.resetImgSizeWH);\n\timageLoad.setImgSize(document.getElementById(\"img6\"), imageLoad.resetImgSizeWH);\n&/script&\nImageLoad源码$(document).ready(function() { \n\tnew ImageLoad();\n});\n\nImageLoad = function(){\n\tthis.init();\n};\n\nImageLoad.prototype = {\n\tinit : function () {\n//\t\tthis.initImg(\"w\");\n\t},\n\tinitImg : function(type) {\n\t\tvar _this = this;\n\t\tvar imgs = document.getElementsByTagName('img');\n\t\tfor (var i=0; i&imgs.length; i++) {\n\t\t\ttry {\n\t\t\t\tvar img = imgs[i];\n\t\t\t\tif (\"w\" == type) {\n\t\t\t\t\t$(img).onload = _this.setImgSize(img, _this.resetImgSizeW);\n\t\t\t\t} else if (\"h\" == type) {\n\t\t\t\t\t$(img).onload = _this.setImgSize(img, _this.resetImgSizeH);\n\t\t\t\t} else if (\"wh\" == type) {\n\t\t\t\t\t$(img).onload = _this.setImgSize(img, _this.resetImgSizeWH);\n\t\t\t\t} \n\t\t\t} catch(e) {\n\t\t\t}\n\t\t}\n\t},\n\t//原始宽度 原始高度 容器宽度 容器高度\n\t//保证高度一致\n\tresetImgSizeH : function(img, nw, nh, w, h) {\n\t\tnwh = nw / nh;\n\t\twh = w / h;\n\t\tif (nwh & wh) {\n\t\t\timg.height = h;\n\t\t\tvar width = parseInt(nwh * h);\n\t\t\timg.width = width;\n\t\t\tvar left = parseInt((width - w) / 2) * -1;\n\t\t\timg.style.marginLeft = left + \"px\";\n\t\t} else if (nwh & wh) {\n\t\t\timg.height = h;\n\t\t\tvar width = parseInt(nwh * h);\n\t\t\timg.width = width;\n\t\t\tvar left = parseInt((w - width) / 2);\n\t\t\timg.style.marginLeft = left + \"px\";\n\t\t} else {\n\t\t\timg.height = h;\n\t\t\timg.width = w;\n\t\t}\n\t},\n\t//原始宽度 原始高度 容器宽度 容器高度\n\t//保证宽度一致\n\tresetImgSizeW : function(img, nw, nh, w, h) {\n\t\tnwh = nw / nh;\n\t\twh = w / h;\n\t\tif (nwh & wh) {\n\t\t\timg.width = w;\n\t\t\tvar height = parseInt(1 / nwh * w);\n\t\t\timg.height = height;\n\t\t\tvar top = parseInt((h - height) / 2);\n\t\t\timg.style.marginTop = top + \"px\";\n\t\t} else if (nwh & wh) {\n\t\t\timg.width = w;\n\t\t\tvar height = parseInt(1 / nwh * w);\n\t\t\timg.height = height;\n\t\t\tvar top = parseInt((height - h) / 2) * -1;\n\t\t\timg.style.marginTop = top + \"px\";\n\t\t} else {\n\t\t\timg.height = h;\n\t\t\timg.width = w;\n\t\t}\n\t},\n\t//原始宽度 原始高度 容器宽度 容器高度\n\t//铺满全屏\n\tresetImgSizeWH : function(img, nw, nh, w, h) {\n\t\tnwh = nw / nh;\n\t\twh = w / h;\n\t\tif (nwh & wh) {\n\t\t\timg.height = h;\n\t\t\tvar width = parseInt(nwh * h);\n\t\t\timg.width = width;\n\t\t\tvar left = parseInt((width - w) / 2) * -1;\n\t\t\timg.style.marginLeft = left + \"px\";\n\t\t} else if (nwh & wh) {\n\t\t\timg.width = w;\n\t\t\tvar height = parseInt(1 / nwh * w);\n\t\t\timg.height = height;\n\t\t\tvar top = parseInt((height - h) / 2) * -1;\n\t\t\timg.style.marginTop = top + \"px\";\n\t\t} else {\n\t\t\timg.height = h;\n\t\t\timg.width = w;\n\t\t}\n\t},\n\t//获取图片真实尺寸以及容器尺寸\n\tsetImgSize : function(img, callback) {\n\t\tif (img.naturalWidth) { //html5\n\t\t\tcallback(img, img.naturalWidth, img.naturalHeight, img.width, img.height);\n\t\t} else { // IE 6 7 8\n\t\t\tvar imgae = new Image();\n\t\t\timage.src = img.src;\n\t\t\timage.onload = function() {\n\t
callback(img, image.width, image.height, img.width, img.height);\n\t
}\n\t\t}\n\t},\n}\n 上面代码还有很多可以优化的地方,欢迎大家在评论区留言交流—————————————————————————————————————————在学习过程如果有任何疑问,请来极乐网()提问,或者扫描下方二维码,关注极乐官方微信,在平台下方留言~","state":"published","sourceUrl":"","pageCommentsCount":0,"canComment":false,"snapshotUrl":"","slug":,"publishedTime":"T16:21:36+08:00","url":"/p/","title":"使用JavaScript解决网页图片拉伸问题","summary":"来源: 问题描述这段时间在做PM的需求的时候突然发现一个问题,产品上的图片来自多个第三方,具体的尺寸无法确定,如果直接在样式中写死图片的尺寸大小就会出现图片拉伸的现象,十分影响产品的美观,因此希望可以找到一…","reviewingCommentsCount":0,"meta":{"previous":null,"next":null},"commentPermission":"anyone","commentsCount":39,"likesCount":76}},"annotationDetail":null,"commentsCount":17,"likesCount":70,"FULLINFO":true}},"User":{"Dreawer":{"isFollowed":false,"name":"极乐君","headline":"知乎专栏 && /dreawer \n极乐小程序商店 && /\n极乐科技
&& /","avatarUrl":"/v2-8cb80f97b7d5f74c7a8997cbc4089e1f_s.jpg","isFollowing":false,"type":"people","slug":"Dreawer","bio":"极乐小程序商店(/)","hash":"4b43cf6f3d97f480b3ca2c13e5b12752","uid":563500,"isOrg":false,"description":"知乎专栏 && /dreawer \n极乐小程序商店 && /\n极乐科技
&& /","profileUrl":"/people/Dreawer","avatar":{"id":"v2-8cb80f97b7d5f74c7a8997cbc4089e1f","template":"/{id}_{size}.jpg"},"isOrgWhiteList":false,"badge":{"identity":null,"bestAnswerer":null}}},"Comment":{},"favlists":{}},"me":{},"global":{"experimentFeatures":{"ge3":"ge3_9","ge2":"ge2_1","nwebStickySidebar":"sticky","nwebAnswerRecommendLive":"newVersion","newMore":"new","sendZaMonitor":"true","liveReviewBuyBar":"live_review_buy_bar_2","liveStore":"ls_a2_b2_c1_f2","homeUi2":"default","answerRelatedReadings":"qa_recommend_by_algo_related_with_article","qrcodeLogin":"qrcode","newBuyBar":"liveoldbuy","newMobileColumnAppheader":"new_header","zcmLighting":"zcm","favAct":"default","appStoreRateDialog":"close","mobileQaPageProxyHeifetz":"m_qa_page_nweb","iOSNewestVersion":"4.2.0","default":"None","wechatShareModal":"wechat_share_modal_show","qaStickySidebar":"sticky_sidebar","androidProfilePanel":"panel_b"}},"columns":{"next":{},"dreawer":{"following":false,"canManage":false,"href":"/api/columns/dreawer","name":"极乐科技","creator":{"slug":"Dreawer"},"url":"/dreawer","slug":"dreawer","avatar":{"id":"v2-def9c21d9ca33ad157f4208","template":"/{id}_{size}.jpg"}}},"columnPosts":{},"columnSettings":{"colomnAuthor":[],"uploadAvatarDetails":"","contributeRequests":[],"contributeRequestsTotalCount":0,"inviteAuthor":""},"postComments":{},"postReviewComments":{"comments":[],"newComments":[],"hasMore":true},"favlistsByUser":{},"favlistRelations":{},"promotions":{},"switches":{"couldAddVideo":false},"draft":{"titleImage":"","titleImageSize":{},"isTitleImageFullScreen":false,"canTitleImageFullScreen":false,"title":"","titleImageUploading":false,"error":"","content":"","draftLoading":false,"globalLoading":false,"pendingVideo":{"resource":null,"error":null}},"drafts":{"draftsList":[],"next":{}},"config":{"userNotBindPhoneTipString":{}},"recommendPosts":{"articleRecommendations":[],"columnRecommendations":[]},"env":{"edition":{},"isAppView":false,"appViewConfig":{"content_padding_top":128,"content_padding_bottom":56,"content_padding_left":16,"content_padding_right":16,"title_font_size":22,"body_font_size":16,"is_dark_theme":false,"can_auto_load_image":true,"app_info":"OS=iOS"},"isApp":false},"sys":{},"message":{"newCount":0},"pushNotification":{"newCount":0}}

我要回帖

更多关于 华为软件工程师待遇 的文章

 

随机推荐