环信助力九个秘书打造全国中小企业人才共享管家

   九个秘书APP(北京九秘科技有限公司)是国内领先的人才共享企业级SAAS服务互联网科技公司。公司创立于2015年,总部坐落于北京市中关村,河南九秘科技有限公司为其全资子公司,主要承担城市联营、市场孵化、区域经营等职能,地址位于郑州市中原区泰隆大厦。公司于2016年10月26日获得了天明集团1000万元战略投资。
TIM截图20170915151952.png

 
九个秘书-中小企业人才共享管家
遇到的挑战:
   九个秘书APP技术总监卢志涛表示:“九个秘书调研期间技术团队对于聊天功能评估了很久,当时考虑是自己编写还是使用第三方的sdk。对于初创公司来讲,IM这一块由自己来开发不仅时间不允许,技术沉淀也不够,即便开发出来稳定性也很难保证。所以当时在相对于比较成熟的几款IM服务中,通过服务质量,稳定性,开发团队以及和业务需求进行匹配,技术部门进行了评断,在第三方sdk中精心筛选出了环信。”
 
环信解决方案:
  九个秘书作为环信早期的用户,从15年就开始接入环信聊天功能,环信聊天能实现消息及时到达以及可扩展性良好,在接入时也遇到些问题,环信成立单独的项目技术支持的QQ群,来帮助九个秘书解决集成中遇到的问题,环信在帮助用户集成sdk时真的很尽心尽力,大大缩短了项目开发周期,为能用上这样贴心的服务点赞!”
 
价值体现:
  九个秘书使用环信IM实现客户之间的相互聊天功能,以及群功能,同时为了丰富聊天的互动性,以及环信的可扩展性,在聊天中实现了收发红包,以及打赏用户的功能。”
 
关于九个秘书:
   公司积极响应国家主席习近平提出的“推动互联网和实体经济深度融合”网络强国战略,立足全球共享经济大风口,探索城乡人才结构失衡、资源配置不均的互联网解决方案,成功研发人才共享企业级SAAS服务平台——九个秘书,让海量专业人才汇聚平台,通过远程协同智能办公作业模式,实现人才与企业按需雇佣,主要将一二线城市高端人才共享给四五线城市中小企业,解决一二线城市人才集中、四五线城市人才匮乏的差异化需求。

   公司旗下拥有“九个秘书、九秘微城、九秘商城”三大产品线,将围绕“人才共享、本地生活、特产直营”三大核心业务,为生产、地产、酒店、餐饮、健康、旅游、休闲、娱乐、教育等行业,提供“品牌策划、商务直播、产品分销、品牌推广、品牌投资”一站式项目众包解决方案,深度解决企业“产品销售难、品牌推广难、渠道建设难、人才招聘难、成本降低难”五大难题,为企业的日常经营和可持续发展打通上下游云服务生态链,全方位推动中国实体经济互联网+转型!
继续阅读 »
   九个秘书APP(北京九秘科技有限公司)是国内领先的人才共享企业级SAAS服务互联网科技公司。公司创立于2015年,总部坐落于北京市中关村,河南九秘科技有限公司为其全资子公司,主要承担城市联营、市场孵化、区域经营等职能,地址位于郑州市中原区泰隆大厦。公司于2016年10月26日获得了天明集团1000万元战略投资。
TIM截图20170915151952.png

 
九个秘书-中小企业人才共享管家
遇到的挑战:
   九个秘书APP技术总监卢志涛表示:“九个秘书调研期间技术团队对于聊天功能评估了很久,当时考虑是自己编写还是使用第三方的sdk。对于初创公司来讲,IM这一块由自己来开发不仅时间不允许,技术沉淀也不够,即便开发出来稳定性也很难保证。所以当时在相对于比较成熟的几款IM服务中,通过服务质量,稳定性,开发团队以及和业务需求进行匹配,技术部门进行了评断,在第三方sdk中精心筛选出了环信。”
 
环信解决方案:
  九个秘书作为环信早期的用户,从15年就开始接入环信聊天功能,环信聊天能实现消息及时到达以及可扩展性良好,在接入时也遇到些问题,环信成立单独的项目技术支持的QQ群,来帮助九个秘书解决集成中遇到的问题,环信在帮助用户集成sdk时真的很尽心尽力,大大缩短了项目开发周期,为能用上这样贴心的服务点赞!”
 
价值体现:
  九个秘书使用环信IM实现客户之间的相互聊天功能,以及群功能,同时为了丰富聊天的互动性,以及环信的可扩展性,在聊天中实现了收发红包,以及打赏用户的功能。”
 
关于九个秘书:
   公司积极响应国家主席习近平提出的“推动互联网和实体经济深度融合”网络强国战略,立足全球共享经济大风口,探索城乡人才结构失衡、资源配置不均的互联网解决方案,成功研发人才共享企业级SAAS服务平台——九个秘书,让海量专业人才汇聚平台,通过远程协同智能办公作业模式,实现人才与企业按需雇佣,主要将一二线城市高端人才共享给四五线城市中小企业,解决一二线城市人才集中、四五线城市人才匮乏的差异化需求。

   公司旗下拥有“九个秘书、九秘微城、九秘商城”三大产品线,将围绕“人才共享、本地生活、特产直营”三大核心业务,为生产、地产、酒店、餐饮、健康、旅游、休闲、娱乐、教育等行业,提供“品牌策划、商务直播、产品分销、品牌推广、品牌投资”一站式项目众包解决方案,深度解决企业“产品销售难、品牌推广难、渠道建设难、人才招聘难、成本降低难”五大难题,为企业的日常经营和可持续发展打通上下游云服务生态链,全方位推动中国实体经济互联网+转型! 收起阅读 »

环信客户互动云荣获2017年度全媒体智能客服最佳解决方案奖

 
1505358834689837.jpg

 2017年9月10日下午14时,由中国电子商会呼叫中心与客户关系管理专业委员会主办、北京易训天下咨询服务有限公司承办、贵阳市服务外包及呼叫中心产业发展办公室联合承办的“2017年度(第十三届)中国最佳呼叫中心颁奖暨行业大会”表彰活动之“2017年度中国呼叫中心产业交流峰会”在人民大会堂成功举办。本次峰会有来自电信、银行、保险、证券、汽车、旅游、电子商务、服务外包等不同行业的近400位中高层领导参会。本次大会重点表彰了国内呼叫中心产业优秀单位及个人,树立卓越行业形象,深度激活呼叫中心产业内上下游优秀企业与品牌,促使产业内部积极跨界融合及健康持续发展。


1505358843352383.jpg

 峰会期间,北京易掌云峰科技有限公司(环信)CEO刘俊彦先生以一家软件供应商的视角,将看到的行业最新趋势、最新变革与在座嘉宾共享,并提出三个趋势:从语音和电话座席向全媒体座席的升级趋势、服务座席向我们的营销座席升级的趋势、人工座席向人工智能座席的趋势。演讲围绕以上三个趋势提出问题、解答问题,引发现场在座嘉宾阵阵掌声。
155584684647789014.jpg

环信荣获2017年度全媒体智能客服最佳解决方案奖
 
环信客户互动云(Customer Engagement Cloud)支持全媒体接入,包括网页在线客服、社交媒体客服(微博、微信)、APP内置客服和呼叫中心等多种渠道均可一键接入。基于环信业界领先的IM长连接技术保证消息必达,并通过智能客服机器人技术降低人工客服工作量。同时,基于人工智能和大数据挖掘的客户旅程透析产品"环信客户声音"能够帮助企业优化运营,提高跨渠道客服体验。环信CEC为企业提供了从客户互动渠道、到客户服务、再到精准营销的一体化全流程客户互动解决方案。
继续阅读 »
 
1505358834689837.jpg

 2017年9月10日下午14时,由中国电子商会呼叫中心与客户关系管理专业委员会主办、北京易训天下咨询服务有限公司承办、贵阳市服务外包及呼叫中心产业发展办公室联合承办的“2017年度(第十三届)中国最佳呼叫中心颁奖暨行业大会”表彰活动之“2017年度中国呼叫中心产业交流峰会”在人民大会堂成功举办。本次峰会有来自电信、银行、保险、证券、汽车、旅游、电子商务、服务外包等不同行业的近400位中高层领导参会。本次大会重点表彰了国内呼叫中心产业优秀单位及个人,树立卓越行业形象,深度激活呼叫中心产业内上下游优秀企业与品牌,促使产业内部积极跨界融合及健康持续发展。


1505358843352383.jpg

 峰会期间,北京易掌云峰科技有限公司(环信)CEO刘俊彦先生以一家软件供应商的视角,将看到的行业最新趋势、最新变革与在座嘉宾共享,并提出三个趋势:从语音和电话座席向全媒体座席的升级趋势、服务座席向我们的营销座席升级的趋势、人工座席向人工智能座席的趋势。演讲围绕以上三个趋势提出问题、解答问题,引发现场在座嘉宾阵阵掌声。
155584684647789014.jpg

环信荣获2017年度全媒体智能客服最佳解决方案奖
 
环信客户互动云(Customer Engagement Cloud)支持全媒体接入,包括网页在线客服、社交媒体客服(微博、微信)、APP内置客服和呼叫中心等多种渠道均可一键接入。基于环信业界领先的IM长连接技术保证消息必达,并通过智能客服机器人技术降低人工客服工作量。同时,基于人工智能和大数据挖掘的客户旅程透析产品"环信客户声音"能够帮助企业优化运营,提高跨渠道客服体验。环信CEC为企业提供了从客户互动渠道、到客户服务、再到精准营销的一体化全流程客户互动解决方案。 收起阅读 »

【环信征文】祭天时不同程序员的不同杀法

这两天一张“还杀了一个程序员祭天”的截图火了,很多同行在纷纷谴责这位无良老板的同时把矛头也指向了我,已经遇到好几个人问我:“作为程序员和一个杀程序员祭天的老板做校友是什么体验?”

在此我想帮我的校友洗一次地,你们注意这个更新文案中只说“还杀了一个程序员祭天”没说是怎么杀的,为啥你们就脑补出砍头、活埋、六马分尸(女程序员可能是五马分尸)这些血腥的杀法了呢?为啥不觉得是老板奖励了程序员一辈子无福消受的酒肉烟钱把程序员的造化瞬间耗尽了呢?

喝酒醉死

诗云:李白当年水底眠,惟留诗篇万口传。码农入坑捞大饼,只给别人做笑谈。

程序员健康的第一大杀手是酒。

杭州有位程序员,虽然技术牛B,酒瘾也大。他荣升CTO之际恰逢母校80周年校庆,在收到了“欢迎杰出校友出席庆典”的邀请函后,坐上了开往合肥的动车,不料当动车开到当涂的时候,肝癌、酒精肝、胃穿孔同时发病,程序员被酒杀死了。

程序员死后,开启了上帝视角。他看到了祖师爷李白——我且问你,诗人怎么成了程序员的祖师爷?原来李白在醉酒之后,于采石矶低头看见水中月亮的倒影,便纵身一跃,跳进了一万里扬子大江捞月亮,从此李白变成了当涂县太白镇的衣冠冢,虽然尸骨无存,万幸香火不断。然后程序员又看见了建国后,上海美术电影制片厂拍了一个一群Monkey跳进小河里捞月亮的动画片。最后程序员看见了当代,老板在臭水坑里画了一个大饼,在项目上线后,用酒把一群Code Monkey灌醉,然后让Code Monkey争先恐后入坑捞大饼的故事。李白就这样成了Code Monkey的祖师爷。

有诗为证:天上月亮只一个,举杯对影便成三。醉生梦死伤身体,诗人一醉变诗仙。

程序员明白了喝酒有害健康的道理之后就复活了,从此粉碎了老板想让他喝酒醉死祭天的阴谋。

吃肉撑死

诗云:反式脂肪胆固醇,催肥激素更无伦。工作午餐多吃素,青山怕葬黑发人。

程序员健康的第二大杀手是肉。

北京有位程序员,虽然技术牛B,烟瘾也大。他荣升CTO之际恰逢母校80周年校庆,在收到了“欢迎杰出校友出席庆典”的邀请函后,坐上了开往合肥的动车,不料当动车开到淮南的时候,高血压、脂肪肝、直肠癌同时发病,程序员被肉杀死了。

程序员死后,开启了上帝视角。他看到赵王中了秦国的反间计,逼走了廉颇,因此长平之战赵国惨败。于是“赵王思复得廉颇,廉颇亦思复用于赵”,赵王派使者来到魏国问廉颇“尚能饭否?”廉颇非常高兴,一顿饭吃了十斤肉,披甲上马,不料因为肉吃得太多坏了肚子,和使者谈话的时候连上三次厕所。于是赵王没有重新重用廉颇,廉颇又从魏国流亡到了楚国,最终在八公山逝世,赵国不久也就成了《阿房宫赋》里轻描淡写的一句“燕赵之收藏,……,输来其间”。

有诗为证:廉颇在魏思邯郸,星落淮南八公山。吃肉太多伤身体,收藏不该来其间。

程序员明白了吃肉有害健康的道理之后就复活了,从此粉碎了老板想让他吃肉撑死祭天的阴谋。

抽烟呛死

诗云:八旗守城似金汤,为何英军入镇江。皆因大烟未烧尽,留下祸根毒四方。

程序员健康的第三大杀手是烟。

厦门有位程序员,虽然技术牛B,烟瘾也大。他荣升CTO之际恰逢母校80周年校庆,在收到了“欢迎杰出校友出席庆典”的邀请函后,坐上了开往合肥的动车,不料当动车开到镇江的时候,肺癌、肺气肿、口腔癌同时发病,程序员被烟杀死了。

程序员死后,开启了上帝视角。他看到古代镇江是长江门户,自古便是兵家必争之地。民族英雄郑成功三次从厦门誓师北伐,每一次都势如破竹,但无一例外在镇江败北。镇江之所以易守难攻,不完全依赖长江天险,更靠八旗子弟骁勇善战。不料后来在鸦片战争中镇江被英军轻而易举攻破,原来两广总督林则徐虎门销烟的时候有一箱子烟忘了销毁,流传到了镇江,八旗子弟吸烟之后“头痛头晕加恶心,眼花耳响不认人。脸色苍白出虚汗,浑身乱颤腿抽筋”,导致镇江“几无可以御敌之兵”。

有诗为证:编程早知世事艰,码农为何气如山。吞云吐雾伤身体,总督岂能不销烟。

程序员明白了吸烟有害健康的道理之后就复活了,从此粉碎了老板想让他抽烟呛死祭天的阴谋。

拿钱砸死

诗云:劝君莫要聚宝盆,富可敌国害死人。若是贪财能保命,周庄沈厅可不焚。

程序员健康的第四大杀手是钱。

上海有位程序员,虽然技术牛B,钱瘾也大。他荣升CTO之际恰逢母校80周年校庆,在收到了“欢迎杰出校友出席庆典”的邀请函后,坐上了开往合肥的动车,不料当动车开到苏州的时候,失眠、抑郁症、谋财害命同时发病,程序员被钱杀死了。

程序员死后,开启了上帝视角。他看到古代周庄有个大财主沈万三,家里有个聚宝盆,全国的金银财宝都会流到他的手里,导致了朱元璋的嫉恨。朱元璋没收了沈万三的粮食,烧毁了沈万三的房子,给他一个金碗,还给他盖了一座金屋子。让他白天拿着金碗讨饭,夜里睡在金屋子里。因为没人设施捧金碗的乞丐,黄金的导热能力强比热容又小,沈万三死于饥寒交迫。

有诗为证:但愿有头生白发,何忧无地觅青蚨。贪财无厌伤身体,拿命卖钱太糊涂。

程序员明白了贪财有害健康的道理之后就复活了,从此粉碎了老板想让他拿钱砸死祭天的阴谋。
继续阅读 »
这两天一张“还杀了一个程序员祭天”的截图火了,很多同行在纷纷谴责这位无良老板的同时把矛头也指向了我,已经遇到好几个人问我:“作为程序员和一个杀程序员祭天的老板做校友是什么体验?”

在此我想帮我的校友洗一次地,你们注意这个更新文案中只说“还杀了一个程序员祭天”没说是怎么杀的,为啥你们就脑补出砍头、活埋、六马分尸(女程序员可能是五马分尸)这些血腥的杀法了呢?为啥不觉得是老板奖励了程序员一辈子无福消受的酒肉烟钱把程序员的造化瞬间耗尽了呢?

喝酒醉死

诗云:李白当年水底眠,惟留诗篇万口传。码农入坑捞大饼,只给别人做笑谈。

程序员健康的第一大杀手是酒。

杭州有位程序员,虽然技术牛B,酒瘾也大。他荣升CTO之际恰逢母校80周年校庆,在收到了“欢迎杰出校友出席庆典”的邀请函后,坐上了开往合肥的动车,不料当动车开到当涂的时候,肝癌、酒精肝、胃穿孔同时发病,程序员被酒杀死了。

程序员死后,开启了上帝视角。他看到了祖师爷李白——我且问你,诗人怎么成了程序员的祖师爷?原来李白在醉酒之后,于采石矶低头看见水中月亮的倒影,便纵身一跃,跳进了一万里扬子大江捞月亮,从此李白变成了当涂县太白镇的衣冠冢,虽然尸骨无存,万幸香火不断。然后程序员又看见了建国后,上海美术电影制片厂拍了一个一群Monkey跳进小河里捞月亮的动画片。最后程序员看见了当代,老板在臭水坑里画了一个大饼,在项目上线后,用酒把一群Code Monkey灌醉,然后让Code Monkey争先恐后入坑捞大饼的故事。李白就这样成了Code Monkey的祖师爷。

有诗为证:天上月亮只一个,举杯对影便成三。醉生梦死伤身体,诗人一醉变诗仙。

程序员明白了喝酒有害健康的道理之后就复活了,从此粉碎了老板想让他喝酒醉死祭天的阴谋。

吃肉撑死

诗云:反式脂肪胆固醇,催肥激素更无伦。工作午餐多吃素,青山怕葬黑发人。

程序员健康的第二大杀手是肉。

北京有位程序员,虽然技术牛B,烟瘾也大。他荣升CTO之际恰逢母校80周年校庆,在收到了“欢迎杰出校友出席庆典”的邀请函后,坐上了开往合肥的动车,不料当动车开到淮南的时候,高血压、脂肪肝、直肠癌同时发病,程序员被肉杀死了。

程序员死后,开启了上帝视角。他看到赵王中了秦国的反间计,逼走了廉颇,因此长平之战赵国惨败。于是“赵王思复得廉颇,廉颇亦思复用于赵”,赵王派使者来到魏国问廉颇“尚能饭否?”廉颇非常高兴,一顿饭吃了十斤肉,披甲上马,不料因为肉吃得太多坏了肚子,和使者谈话的时候连上三次厕所。于是赵王没有重新重用廉颇,廉颇又从魏国流亡到了楚国,最终在八公山逝世,赵国不久也就成了《阿房宫赋》里轻描淡写的一句“燕赵之收藏,……,输来其间”。

有诗为证:廉颇在魏思邯郸,星落淮南八公山。吃肉太多伤身体,收藏不该来其间。

程序员明白了吃肉有害健康的道理之后就复活了,从此粉碎了老板想让他吃肉撑死祭天的阴谋。

抽烟呛死

诗云:八旗守城似金汤,为何英军入镇江。皆因大烟未烧尽,留下祸根毒四方。

程序员健康的第三大杀手是烟。

厦门有位程序员,虽然技术牛B,烟瘾也大。他荣升CTO之际恰逢母校80周年校庆,在收到了“欢迎杰出校友出席庆典”的邀请函后,坐上了开往合肥的动车,不料当动车开到镇江的时候,肺癌、肺气肿、口腔癌同时发病,程序员被烟杀死了。

程序员死后,开启了上帝视角。他看到古代镇江是长江门户,自古便是兵家必争之地。民族英雄郑成功三次从厦门誓师北伐,每一次都势如破竹,但无一例外在镇江败北。镇江之所以易守难攻,不完全依赖长江天险,更靠八旗子弟骁勇善战。不料后来在鸦片战争中镇江被英军轻而易举攻破,原来两广总督林则徐虎门销烟的时候有一箱子烟忘了销毁,流传到了镇江,八旗子弟吸烟之后“头痛头晕加恶心,眼花耳响不认人。脸色苍白出虚汗,浑身乱颤腿抽筋”,导致镇江“几无可以御敌之兵”。

有诗为证:编程早知世事艰,码农为何气如山。吞云吐雾伤身体,总督岂能不销烟。

程序员明白了吸烟有害健康的道理之后就复活了,从此粉碎了老板想让他抽烟呛死祭天的阴谋。

拿钱砸死

诗云:劝君莫要聚宝盆,富可敌国害死人。若是贪财能保命,周庄沈厅可不焚。

程序员健康的第四大杀手是钱。

上海有位程序员,虽然技术牛B,钱瘾也大。他荣升CTO之际恰逢母校80周年校庆,在收到了“欢迎杰出校友出席庆典”的邀请函后,坐上了开往合肥的动车,不料当动车开到苏州的时候,失眠、抑郁症、谋财害命同时发病,程序员被钱杀死了。

程序员死后,开启了上帝视角。他看到古代周庄有个大财主沈万三,家里有个聚宝盆,全国的金银财宝都会流到他的手里,导致了朱元璋的嫉恨。朱元璋没收了沈万三的粮食,烧毁了沈万三的房子,给他一个金碗,还给他盖了一座金屋子。让他白天拿着金碗讨饭,夜里睡在金屋子里。因为没人设施捧金碗的乞丐,黄金的导热能力强比热容又小,沈万三死于饥寒交迫。

有诗为证:但愿有头生白发,何忧无地觅青蚨。贪财无厌伤身体,拿命卖钱太糊涂。

程序员明白了贪财有害健康的道理之后就复活了,从此粉碎了老板想让他拿钱砸死祭天的阴谋。 收起阅读 »

【环信征文】集成环信,并实现消息免打扰

现在大多数社交app都有消息免打扰功能,因为环信SDK主要是对即时通讯模块进行封装,因此如果要实现消息免打扰功能则需要开发者自己对此功能逻辑进行处理。
先解释一下,本人项目中对消息免打扰功能的定义:正常情况下,我们收到的每一条聊天消息都会收到小红点、声音、震动的提示。如果对某个好友设置消息免打扰功能,则只提示小红点,声音和震动则不再提示。

下面简述结合环信SDK时,此功能的实现方法。
环信将即时聊天的所有功能分为四大模块进行管理:
//聊天模块:
[EMClient sharedClient].chatManager
//好友模块 :
[EMClient sharedClient].contactManager
//群组模块 :
[EMClient sharedClient].groupManager
//聊天室模块:
[EMClient sharedClient].roomManager
消息免打扰的功能借助聊天模块[EMClient sharedClient].chatManager的API就能实现。
一般来说,在app内不管当前在哪个界面,只要收到消息都需要被判断是否需要免打扰,因此可以在appdelegate里写如下代码,app通常都有tabBarController,那么也可以让tabBarController来实现如下代码。
首先让控制器tabBarController遵守代理EMChatManagerDelegate
然后成为代理
[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];

EMChatManagerDelegate中有一个代理方法
- (void)didReceiveMessages:(NSArray *)aMessages;
实现此代理方法
- (void)didReceiveMessages:(NSArray *)aMessages{
[self setupUnreadMessageCount];
EMMessage *message = aMessages[0];
NSString *sendPerson = message.from;
BHNavigatiomController *imNaviCV = self.viewControllers[1];
BHConversationListController *converCV = imNaviCV.viewControllers[0];
[converCV refreshDataSource];//只要收到消息就从服务器拿
UIApplicationState state = [[UIApplication sharedApplication] applicationState];
for (NSString *hx_name in AppEngine.IMDataCent.data_ExcuseFriendsData) {
if ([hx_name isEqualToString:sendPerson]) {
return;
}
}
switch (state) {
case UIApplicationStateActive:
[self playSoundAndVibration];
break;
case UIApplicationStateInactive:
[self playSoundAndVibration];
break;
case UIApplicationStateBackground:
[self showNotificationWithMessage:message];
break;
default:
break;
}
}
方法中有一个aMessages参数。这个参数是一个消息组,每一个元素都是EMMessage类型的实例。
因为通常都只有一条信息。因此只需要取出EMMessage *message = aMessages[0];
EMMessage类中有许多属性,因此根据一条信息基本可以获取想知道的所有信息。这里我们只需要知道此消息的发送方即可,也就是发送方的环信idNSString *sendPerson = message.from;下面代码中有一AppEngine.IMDataCent.data_ExcuseFriendsData,这个数组里面装的都是已经被设置消息免打扰的好友的环信id,是请求自己服务器获得的,获取的代码最好在一打开app时,就及时获取到。然后根据对好友免打扰设置的操作,访问后台接口进行增删,并刷新数组与后端保持一致即可。
通过[hx_name isEqualToString:sendPerson],遍历免打扰数组与当前消息的发送方环信id,就可以知道是否需要免打扰了。
 
下面附上完整代码
 

// // BHTabBarController.m // xxxxxxx // // Created by LiBohan on 2017/8/24. // Copyright © 2017年 xxxxxx. All rights reserved. // //两次提示的默认间隔 static const CGFloat kDefaultPlaySoundInterval = 3.0; static NSString *kMessageType = @"MessageType"; static NSString *kConversationChatter = @"ConversationChatter"; static NSString *kGroupName = @"GroupName"; #import "BHTabBarController.h" #import <UserNotifications/UserNotifications.h> #import "BHConversationListController.h" @interface BHTabBarController ()<EMChatManagerDelegate> @property (strong, nonatomic) NSDate *lastPlaySoundDate; @end @implementation BHTabBarController - (void)viewDidLoad { [super viewDidLoad]; [DemoCallManager sharedManager].mainController = self; [[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setupUnreadMessageCount) name:@"setupUnreadMessageCount" object:nil]; } // 统计未读消息数 -(void)setupUnreadMessageCount { NSArray *conversations = [[EMClient sharedClient].chatManager getAllConversations]; NSInteger unreadCount = 0; for (EMConversation *conversation in conversations) { unreadCount += conversation.unreadMessagesCount; } NSArray *tabBarItems = self.tabBar.items; UITabBarItem *conlistTabBarItem = [tabBarItems objectAtIndex:1]; if (unreadCount > 0) { conlistTabBarItem.badgeValue = [NSString stringWithFormat:@"%i",(int)unreadCount]; }else{ conlistTabBarItem.badgeValue = nil; } // UIApplication *application = [UIApplication sharedApplication]; // [application setApplicationIconBadgeNumber:unreadCount]; } - (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages { for (EMMessage *message in aCmdMessages) { EMCmdMessageBody *body = (EMCmdMessageBody *)message.body; NSLog(@"收到的action是 -- %@",body.action); if (body.action == nil) { return; } NSData *jsonData = [body.action dataUsingEncoding:NSUTF8StringEncoding]; NSError *err; NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&err]; if(err) { NSLog(@"json解析失败:%@",err); return; } NSNumber *num = dic[@"count"]; NSString *str = [num stringValue]; [AppEngine.IMDataCent requestUpdateUnreadNumberWithUnreadNumber:str]; } } - (void)didReceiveMessages:(NSArray *)aMessages{ // [self refresh]; [self setupUnreadMessageCount]; EMMessage *message = aMessages[0]; NSString *sendPerson = message.from; BHNavigatiomController *imNaviCV = self.viewControllers[1]; BHConversationListController *converCV = imNaviCV.viewControllers[0]; // [converCV refresh]; [converCV refreshDataSource];//只要收到消息就从服务器拿 UIApplicationState state = [[UIApplication sharedApplication] applicationState]; for (NSString *hx_name in AppEngine.IMDataCent.data_ExcuseFriendsData) { if ([hx_name isEqualToString:sendPerson]) { return; } } switch (state) { case UIApplicationStateActive: [self playSoundAndVibration]; break; case UIApplicationStateInactive: [self playSoundAndVibration]; break; case UIApplicationStateBackground: [self showNotificationWithMessage:message]; break; default: break; } } - (void)playSoundAndVibration{ NSTimeInterval timeInterval = [[NSDate date] timeIntervalSinceDate:self.lastPlaySoundDate]; if (timeInterval < kDefaultPlaySoundInterval) { //如果距离上次响铃和震动时间太短, 则跳过响铃 NSLog(@"skip ringing & vibration %@, %@", [NSDate date], self.lastPlaySoundDate); return; } //保存最后一次响铃时间 self.lastPlaySoundDate = [NSDate date]; // 收到消息时,播放音频 [[EMCDDeviceManager sharedInstance] playNewMessageSound]; // 收到消息时,震动 [[EMCDDeviceManager sharedInstance] playVibration]; } - (void)showNotificationWithMessage:(EMMessage *)message { EMPushOptions *options = [[EMClient sharedClient] pushOptions]; NSString *alertBody = nil; if (options.displayStyle == EMPushDisplayStyleMessageSummary) { EMMessageBody *messageBody = message.body; NSString *messageStr = nil; switch (messageBody.type) { case EMMessageBodyTypeText: { messageStr = ((EMTextMessageBody *)messageBody).text; } break; case EMMessageBodyTypeImage: { messageStr = NSLocalizedString(@"message.image", @"Image"); } break; case EMMessageBodyTypeLocation: { messageStr = NSLocalizedString(@"message.location", @"Location"); } break; case EMMessageBodyTypeVoice: { messageStr = NSLocalizedString(@"message.voice", @"Voice"); } break; case EMMessageBodyTypeVideo:{ messageStr = NSLocalizedString(@"message.video", @"Video"); } break; default: break; } do { // NSString *title = [[UserProfileManager sharedInstance] getNickNameWithUsername:message.from]; NSString *title = @"大佬"; if (message.chatType == EMChatTypeGroupChat) { NSDictionary *ext = message.ext; if (ext && ext[kGroupMessageAtList]) { id target = ext[kGroupMessageAtList]; if ([target isKindOfClass:[NSString class]]) { if ([kGroupMessageAtAll compare:target options:NSCaseInsensitiveSearch] == NSOrderedSame) { alertBody = [NSString stringWithFormat:@"%@%@", title, NSLocalizedString(@"group.atPushTitle", @" @ me in the group")]; break; } } else if ([target isKindOfClass:[NSArray class]]) { NSArray *atTargets = (NSArray*)target; if ([atTargets containsObject:[EMClient sharedClient].currentUsername]) { alertBody = [NSString stringWithFormat:@"%@%@", title, NSLocalizedString(@"group.atPushTitle", @" @ me in the group")]; break; } } } NSArray *groupArray = [[EMClient sharedClient].groupManager getJoinedGroups]; for (EMGroup *group in groupArray) { if ([group.groupId isEqualToString:message.conversationId]) { title = [NSString stringWithFormat:@"%@(%@)", message.from, group.subject]; break; } } } else if (message.chatType == EMChatTypeChatRoom) { NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; NSString *key = [NSString stringWithFormat:@"OnceJoinedChatrooms_%@", [[EMClient sharedClient] currentUsername]]; NSMutableDictionary *chatrooms = [NSMutableDictionary dictionaryWithDictionary:[ud objectForKey:key]]; NSString *chatroomName = [chatrooms objectForKey:message.conversationId]; if (chatroomName) { title = [NSString stringWithFormat:@"%@(%@)", message.from, chatroomName]; } } alertBody = [NSString stringWithFormat:@"%@:%@", title, messageStr]; } while (0); } else{ // alertBody = NSLocalizedString(@"receiveMessage", @"you have a new message"); alertBody = @"您有一条消息"; } NSTimeInterval timeInterval = [[NSDate date] timeIntervalSinceDate:self.lastPlaySoundDate]; BOOL playSound = NO; if (!self.lastPlaySoundDate || timeInterval >= kDefaultPlaySoundInterval) { self.lastPlaySoundDate = [NSDate date]; playSound = YES; } NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; [userInfo setObject:[NSNumber numberWithInt:message.chatType] forKey:kMessageType]; [userInfo setObject:message.conversationId forKey:kConversationChatter]; //发送本地推送 if (NSClassFromString(@"UNUserNotificationCenter")) { UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:0.01 repeats:NO]; UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init]; if (playSound) { content.sound = [UNNotificationSound defaultSound]; } content.body =alertBody; content.userInfo = userInfo; UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:message.messageId content:content trigger:trigger]; [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:nil]; } else { UILocalNotification *notification = [[UILocalNotification alloc] init]; notification.fireDate = [NSDate date]; //触发通知的时间 notification.alertBody = alertBody; notification.alertAction = NSLocalizedString(@"open", @"Open"); notification.timeZone = [NSTimeZone defaultTimeZone]; if (playSound) { notification.soundName = UILocalNotificationDefaultSoundName; } notification.userInfo = userInfo; //发送通知 [[UIApplication sharedApplication] scheduleLocalNotification:notification]; } } - (void)messagesDidDeliver:(NSArray *)aMessages{ NSLog(@"sf"); } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } /* #pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller. } */ @end
 
 
本人github:https://github.com/BHAreslee
本人简书:http://www.jianshu.com/u/bb53043aaa00
以上就是集成环信时暂时发现的问题,欢迎大家分享你们遇到的问题,也欢迎加入QQ群:372251359,一起讨论交流即时通讯的问题。
本人微信公众号:放心安慰剂

qrcode_for_gh_bc92a063b4a2_430.jpg

 
继续阅读 »
现在大多数社交app都有消息免打扰功能,因为环信SDK主要是对即时通讯模块进行封装,因此如果要实现消息免打扰功能则需要开发者自己对此功能逻辑进行处理。
先解释一下,本人项目中对消息免打扰功能的定义:正常情况下,我们收到的每一条聊天消息都会收到小红点、声音、震动的提示。如果对某个好友设置消息免打扰功能,则只提示小红点,声音和震动则不再提示。

下面简述结合环信SDK时,此功能的实现方法。
环信将即时聊天的所有功能分为四大模块进行管理:
//聊天模块:
[EMClient sharedClient].chatManager
//好友模块 :
[EMClient sharedClient].contactManager
//群组模块 :
[EMClient sharedClient].groupManager
//聊天室模块:
[EMClient sharedClient].roomManager
消息免打扰的功能借助聊天模块[EMClient sharedClient].chatManager的API就能实现。
一般来说,在app内不管当前在哪个界面,只要收到消息都需要被判断是否需要免打扰,因此可以在appdelegate里写如下代码,app通常都有tabBarController,那么也可以让tabBarController来实现如下代码。
首先让控制器tabBarController遵守代理EMChatManagerDelegate
然后成为代理
[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];

EMChatManagerDelegate中有一个代理方法
- (void)didReceiveMessages:(NSArray *)aMessages;
实现此代理方法
- (void)didReceiveMessages:(NSArray *)aMessages{
[self setupUnreadMessageCount];
EMMessage *message = aMessages[0];
NSString *sendPerson = message.from;
BHNavigatiomController *imNaviCV = self.viewControllers[1];
BHConversationListController *converCV = imNaviCV.viewControllers[0];
[converCV refreshDataSource];//只要收到消息就从服务器拿
UIApplicationState state = [[UIApplication sharedApplication] applicationState];
for (NSString *hx_name in AppEngine.IMDataCent.data_ExcuseFriendsData) {
if ([hx_name isEqualToString:sendPerson]) {
return;
}
}
switch (state) {
case UIApplicationStateActive:
[self playSoundAndVibration];
break;
case UIApplicationStateInactive:
[self playSoundAndVibration];
break;
case UIApplicationStateBackground:
[self showNotificationWithMessage:message];
break;
default:
break;
}
}
方法中有一个aMessages参数。这个参数是一个消息组,每一个元素都是EMMessage类型的实例。
因为通常都只有一条信息。因此只需要取出EMMessage *message = aMessages[0];
EMMessage类中有许多属性,因此根据一条信息基本可以获取想知道的所有信息。这里我们只需要知道此消息的发送方即可,也就是发送方的环信idNSString *sendPerson = message.from;下面代码中有一AppEngine.IMDataCent.data_ExcuseFriendsData,这个数组里面装的都是已经被设置消息免打扰的好友的环信id,是请求自己服务器获得的,获取的代码最好在一打开app时,就及时获取到。然后根据对好友免打扰设置的操作,访问后台接口进行增删,并刷新数组与后端保持一致即可。
通过[hx_name isEqualToString:sendPerson],遍历免打扰数组与当前消息的发送方环信id,就可以知道是否需要免打扰了。
 
下面附上完整代码
 

// // BHTabBarController.m // xxxxxxx // // Created by LiBohan on 2017/8/24. // Copyright © 2017年 xxxxxx. All rights reserved. // //两次提示的默认间隔 static const CGFloat kDefaultPlaySoundInterval = 3.0; static NSString *kMessageType = @"MessageType"; static NSString *kConversationChatter = @"ConversationChatter"; static NSString *kGroupName = @"GroupName"; #import "BHTabBarController.h" #import <UserNotifications/UserNotifications.h> #import "BHConversationListController.h" @interface BHTabBarController ()<EMChatManagerDelegate> @property (strong, nonatomic) NSDate *lastPlaySoundDate; @end @implementation BHTabBarController - (void)viewDidLoad { [super viewDidLoad]; [DemoCallManager sharedManager].mainController = self; [[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setupUnreadMessageCount) name:@"setupUnreadMessageCount" object:nil]; } // 统计未读消息数 -(void)setupUnreadMessageCount { NSArray *conversations = [[EMClient sharedClient].chatManager getAllConversations]; NSInteger unreadCount = 0; for (EMConversation *conversation in conversations) { unreadCount += conversation.unreadMessagesCount; } NSArray *tabBarItems = self.tabBar.items; UITabBarItem *conlistTabBarItem = [tabBarItems objectAtIndex:1]; if (unreadCount > 0) { conlistTabBarItem.badgeValue = [NSString stringWithFormat:@"%i",(int)unreadCount]; }else{ conlistTabBarItem.badgeValue = nil; } // UIApplication *application = [UIApplication sharedApplication]; // [application setApplicationIconBadgeNumber:unreadCount]; } - (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages { for (EMMessage *message in aCmdMessages) { EMCmdMessageBody *body = (EMCmdMessageBody *)message.body; NSLog(@"收到的action是 -- %@",body.action); if (body.action == nil) { return; } NSData *jsonData = [body.action dataUsingEncoding:NSUTF8StringEncoding]; NSError *err; NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&err]; if(err) { NSLog(@"json解析失败:%@",err); return; } NSNumber *num = dic[@"count"]; NSString *str = [num stringValue]; [AppEngine.IMDataCent requestUpdateUnreadNumberWithUnreadNumber:str]; } } - (void)didReceiveMessages:(NSArray *)aMessages{ // [self refresh]; [self setupUnreadMessageCount]; EMMessage *message = aMessages[0]; NSString *sendPerson = message.from; BHNavigatiomController *imNaviCV = self.viewControllers[1]; BHConversationListController *converCV = imNaviCV.viewControllers[0]; // [converCV refresh]; [converCV refreshDataSource];//只要收到消息就从服务器拿 UIApplicationState state = [[UIApplication sharedApplication] applicationState]; for (NSString *hx_name in AppEngine.IMDataCent.data_ExcuseFriendsData) { if ([hx_name isEqualToString:sendPerson]) { return; } } switch (state) { case UIApplicationStateActive: [self playSoundAndVibration]; break; case UIApplicationStateInactive: [self playSoundAndVibration]; break; case UIApplicationStateBackground: [self showNotificationWithMessage:message]; break; default: break; } } - (void)playSoundAndVibration{ NSTimeInterval timeInterval = [[NSDate date] timeIntervalSinceDate:self.lastPlaySoundDate]; if (timeInterval < kDefaultPlaySoundInterval) { //如果距离上次响铃和震动时间太短, 则跳过响铃 NSLog(@"skip ringing & vibration %@, %@", [NSDate date], self.lastPlaySoundDate); return; } //保存最后一次响铃时间 self.lastPlaySoundDate = [NSDate date]; // 收到消息时,播放音频 [[EMCDDeviceManager sharedInstance] playNewMessageSound]; // 收到消息时,震动 [[EMCDDeviceManager sharedInstance] playVibration]; } - (void)showNotificationWithMessage:(EMMessage *)message { EMPushOptions *options = [[EMClient sharedClient] pushOptions]; NSString *alertBody = nil; if (options.displayStyle == EMPushDisplayStyleMessageSummary) { EMMessageBody *messageBody = message.body; NSString *messageStr = nil; switch (messageBody.type) { case EMMessageBodyTypeText: { messageStr = ((EMTextMessageBody *)messageBody).text; } break; case EMMessageBodyTypeImage: { messageStr = NSLocalizedString(@"message.image", @"Image"); } break; case EMMessageBodyTypeLocation: { messageStr = NSLocalizedString(@"message.location", @"Location"); } break; case EMMessageBodyTypeVoice: { messageStr = NSLocalizedString(@"message.voice", @"Voice"); } break; case EMMessageBodyTypeVideo:{ messageStr = NSLocalizedString(@"message.video", @"Video"); } break; default: break; } do { // NSString *title = [[UserProfileManager sharedInstance] getNickNameWithUsername:message.from]; NSString *title = @"大佬"; if (message.chatType == EMChatTypeGroupChat) { NSDictionary *ext = message.ext; if (ext && ext[kGroupMessageAtList]) { id target = ext[kGroupMessageAtList]; if ([target isKindOfClass:[NSString class]]) { if ([kGroupMessageAtAll compare:target options:NSCaseInsensitiveSearch] == NSOrderedSame) { alertBody = [NSString stringWithFormat:@"%@%@", title, NSLocalizedString(@"group.atPushTitle", @" @ me in the group")]; break; } } else if ([target isKindOfClass:[NSArray class]]) { NSArray *atTargets = (NSArray*)target; if ([atTargets containsObject:[EMClient sharedClient].currentUsername]) { alertBody = [NSString stringWithFormat:@"%@%@", title, NSLocalizedString(@"group.atPushTitle", @" @ me in the group")]; break; } } } NSArray *groupArray = [[EMClient sharedClient].groupManager getJoinedGroups]; for (EMGroup *group in groupArray) { if ([group.groupId isEqualToString:message.conversationId]) { title = [NSString stringWithFormat:@"%@(%@)", message.from, group.subject]; break; } } } else if (message.chatType == EMChatTypeChatRoom) { NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; NSString *key = [NSString stringWithFormat:@"OnceJoinedChatrooms_%@", [[EMClient sharedClient] currentUsername]]; NSMutableDictionary *chatrooms = [NSMutableDictionary dictionaryWithDictionary:[ud objectForKey:key]]; NSString *chatroomName = [chatrooms objectForKey:message.conversationId]; if (chatroomName) { title = [NSString stringWithFormat:@"%@(%@)", message.from, chatroomName]; } } alertBody = [NSString stringWithFormat:@"%@:%@", title, messageStr]; } while (0); } else{ // alertBody = NSLocalizedString(@"receiveMessage", @"you have a new message"); alertBody = @"您有一条消息"; } NSTimeInterval timeInterval = [[NSDate date] timeIntervalSinceDate:self.lastPlaySoundDate]; BOOL playSound = NO; if (!self.lastPlaySoundDate || timeInterval >= kDefaultPlaySoundInterval) { self.lastPlaySoundDate = [NSDate date]; playSound = YES; } NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; [userInfo setObject:[NSNumber numberWithInt:message.chatType] forKey:kMessageType]; [userInfo setObject:message.conversationId forKey:kConversationChatter]; //发送本地推送 if (NSClassFromString(@"UNUserNotificationCenter")) { UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:0.01 repeats:NO]; UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init]; if (playSound) { content.sound = [UNNotificationSound defaultSound]; } content.body =alertBody; content.userInfo = userInfo; UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:message.messageId content:content trigger:trigger]; [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:nil]; } else { UILocalNotification *notification = [[UILocalNotification alloc] init]; notification.fireDate = [NSDate date]; //触发通知的时间 notification.alertBody = alertBody; notification.alertAction = NSLocalizedString(@"open", @"Open"); notification.timeZone = [NSTimeZone defaultTimeZone]; if (playSound) { notification.soundName = UILocalNotificationDefaultSoundName; } notification.userInfo = userInfo; //发送通知 [[UIApplication sharedApplication] scheduleLocalNotification:notification]; } } - (void)messagesDidDeliver:(NSArray *)aMessages{ NSLog(@"sf"); } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } /* #pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller. } */ @end
 
 
本人github:https://github.com/BHAreslee
本人简书:http://www.jianshu.com/u/bb53043aaa00
以上就是集成环信时暂时发现的问题,欢迎大家分享你们遇到的问题,也欢迎加入QQ群:372251359,一起讨论交流即时通讯的问题。
本人微信公众号:放心安慰剂

qrcode_for_gh_bc92a063b4a2_430.jpg

  收起阅读 »

【环信招聘】Android、ios、H5前端、后台工程师快到碗里来!

这里的每一项技术都会直接帮助平台上的App开发者,并在真正的应用里得到实践检验。

我们不仅是技术的研发者,也是技术的输出方。

这里的每一项技术都在改变世界!

欢迎加入!我们支持开源运动!

来环信,和我们一起用技术改变世界!

 以下职位工作地点是在河南郑州开发,小伙伴们简历赶紧砸过来吧!内推邮箱地址duc@easemob.com
 
iOS工程师

岗位职责:
1. 负责IM SDK开发与相关应用的开发;
2. 对客户提供解决方案和必要的技术支持;

任职资格:
1. 熟悉iOS开发环境、iOS App开发规范和App开发流程;
2. 熟练使用iOS开发核心库,有一定的文档编写能力;
3. 熟悉iOS SDK中布局、网络、数据库、HTTP协议、XML/JSON解析等;
4. 掌握iOS平台的模块化设计架构,能够设计出恰当的应用方案;
5. 熟悉iOS平台的内存管理机制,懂得内存优化技术;
6. 能够与产品经理、设计师、用户进行深入的沟通和交流;
7. 有即时通讯平台开发经验者优先考虑;
8. 两年以上开发经验,其中一年以上iOS应用开发经验;
9. Github 使用者、熟悉c/c++开发,有开源项目贡献者优先考虑。


安卓工程师

岗位职责:
1. 负责IM SDK开发与相关应用的开发;
2. 对客户提供解决方案和必要的技术支持;

任职资格:
1. 熟悉android开发环境、android应用开发规范和开发流程;
2. 熟练使用android SDK,熟悉JNI开发,有一定的文档编写能力;
3. 熟悉android SDK中布局、网络、数据库、HTTP协议、XML/JSON解析等;
4. 掌握Android 平台的模块化设计架构,能够设计出恰当的应用方案;
5. 熟悉 Android 平台的内存管理机制,懂得内存优化技术;
6. 能够与产品经理、设计师、用户进行深入的沟通和交流;
7. 有即时通讯平台开发经验者优先考虑;
8. 两年以上开发经验,其中一年以上android应用开发经验;
9. Github 使用者、熟悉c/c++开发,有开源项目贡献者优先考虑。


H5前端工程师

工作职责
1.环信Web、IM、SDK等的开发设计 
2.环信业务后台管理系统的开发设计
任职资格
1.有web前端经验,熟悉流行的前端技术, 包括但不限于bootstrap、html5、css3、saas、less、jQuery、bower、grunt、webpack、reactJs 
2.有H5移动端开发经验 
3.熟悉Ajax, Rest等原理和使用方式 
4.熟悉Http, WebSocket, Spdy等协议 
5.深刻理解Web标准, 对可用性、可访问性等相关知识有实际的了解和实践经验 
6.有一定的设计美感 
7.简历请同时提供以往项目地址,以及github地址或技术博客地址 
加分项: 
1.熟悉ruby、python、bash、nodejs等脚本语言优先考虑 
2.有开源社区经验者优先考虑


后台工程师
工作职责
1.负责持续改进后端服务,打造业界领先的即时通讯云服务; 
2.或负责持续优化服务性能,提高后端服务的承载能力; 
3.或负责完成后端服务的多机房改造,为全球用户提供可靠实时的即时通讯服务;
任职资格
1.熟悉Java、Erlang或C/C++其中两种语言,有Unix/Linux平台相关开发经验; 
2.熟悉网络通信机制及常用数据传输协议; 
3.算法基础扎实,有ACM、TopCoder或其他比赛经验者优先; 
4.熟悉数据库相关开发,了解MySQL数据库,有HBase、Redis或其他NoSQL相关使用经验者优先; 
5.有较强的解决问题能力,能够承受压力情况下解决线上问题; 
6.能够带领团队成员,研究并攻克技术难关; 
7.需要有开放共享的心态,接受开源思想,有Github创建、维护或参与经验更好; 
8.5年以上开发工作经验;


项目经理(项目实施)-IM
您的责任:
1.确保项目目标的实现,领导项目团队准时、优质的完成全部工作。
2.及时有效地与客户沟通,了解项目的整体需求,与客户保持持续的联系,及时反馈阶段性的成果,并及时向研发更新客户提出的合理需求。
3.制定开发计划文档,量化任务,并合理分配给相关人员。
4.跟踪项目进度,有效的提高代码质量,并及时与研发、实施部署人员以及QA之间沟通,保证项目以及附属文档的完整和规范。
我们的要求:
1. 正规大学本科及以上学历
2.5年以上软件行业经验,3年以上开发/项目管理工作经验
3.能够独立完成中型项目的整体设计、任务计划和开发进度的管理工作
4.熟悉框架设计、系统设计、数据库设计、编码测试等软件工程知识和规范
5.精通软件开发流程,了解linux/unix系统,并能够熟练使用系统设计、数据库设计工具
6.对软件多层结构、以及各层间使用的软件技术有较全面的了解 ;      
7.具有开发队伍的管理能力和经验;
8.具备技术文档编写能力;
9.有乙方项目经理经历,能够与甲方顺畅沟通。
10..有互联网工作经历的优先。

iOS工程师

岗位职责:
1. 负责IM SDK开发与相关应用的开发;
2. 对客户提供解决方案和必要的技术支持;

任职资格:
1. 熟悉iOS开发环境、iOS App开发规范和App开发流程;
2. 熟练使用iOS开发核心库,有一定的文档编写能力;
3. 熟悉iOS SDK中布局、网络、数据库、HTTP协议、XML/JSON解析等;
4. 掌握iOS平台的模块化设计架构,能够设计出恰当的应用方案;
5. 熟悉iOS平台的内存管理机制,懂得内存优化技术;
6. 能够与产品经理、设计师、用户进行深入的沟通和交流;
7. 有即时通讯平台开发经验者优先考虑;
8. 两年以上开发经验,其中一年以上iOS应用开发经验;
9. Github 使用者、熟悉c/c++开发,有开源项目贡献者优先考虑。


安卓工程师

岗位职责:
1. 负责IM SDK开发与相关应用的开发;
2. 对客户提供解决方案和必要的技术支持;

任职资格:
1. 熟悉android开发环境、android应用开发规范和开发流程;
2. 熟练使用android SDK,熟悉JNI开发,有一定的文档编写能力;
3. 熟悉android SDK中布局、网络、数据库、HTTP协议、XML/JSON解析等;
4. 掌握Android 平台的模块化设计架构,能够设计出恰当的应用方案;
5. 熟悉 Android 平台的内存管理机制,懂得内存优化技术;
6. 能够与产品经理、设计师、用户进行深入的沟通和交流;
7. 有即时通讯平台开发经验者优先考虑;
8. 两年以上开发经验,其中一年以上android应用开发经验;
9. Github 使用者、熟悉c/c++开发,有开源项目贡献者优先考虑。


H5前端工程师

工作职责
1.环信Web、IM、SDK等的开发设计 
2.环信业务后台管理系统的开发设计
任职资格
1.有web前端经验,熟悉流行的前端技术, 包括但不限于bootstrap、html5、css3、saas、less、jQuery、bower、grunt、webpack、reactJs 
2.有H5移动端开发经验 
3.熟悉Ajax, Rest等原理和使用方式 
4.熟悉Http, WebSocket, Spdy等协议 
5.深刻理解Web标准, 对可用性、可访问性等相关知识有实际的了解和实践经验 
6.有一定的设计美感 
7.简历请同时提供以往项目地址,以及github地址或技术博客地址 
加分项: 
1.熟悉ruby、python、bash、nodejs等脚本语言优先考虑 
2.有开源社区经验者优先考虑


后台工程师
工作职责
1.负责持续改进后端服务,打造业界领先的即时通讯云服务; 
2.或负责持续优化服务性能,提高后端服务的承载能力; 
3.或负责完成后端服务的多机房改造,为全球用户提供可靠实时的即时通讯服务;
任职资格
1.熟悉Java、Erlang或C/C++其中两种语言,有Unix/Linux平台相关开发经验; 
2.熟悉网络通信机制及常用数据传输协议; 
3.算法基础扎实,有ACM、TopCoder或其他比赛经验者优先; 
4.熟悉数据库相关开发,了解MySQL数据库,有HBase、Redis或其他NoSQL相关使用经验者优先; 
5.有较强的解决问题能力,能够承受压力情况下解决线上问题; 
6.能够带领团队成员,研究并攻克技术难关; 
7.需要有开放共享的心态,接受开源思想,有Github创建、维护或参与经验更好; 
8.5年以上开发工作经验;


项目经理(项目实施)-IM
您的责任:
1.确保项目目标的实现,领导项目团队准时、优质的完成全部工作。
2.及时有效地与客户沟通,了解项目的整体需求,与客户保持持续的联系,及时反馈阶段性的成果,并及时向研发更新客户提出的合理需求。
3.制定开发计划文档,量化任务,并合理分配给相关人员。
4.跟踪项目进度,有效的提高代码质量,并及时与研发、实施部署人员以及QA之间沟通,保证项目以及附属文档的完整和规范。
我们的要求:
1. 正规大学本科及以上学历
2.5年以上软件行业经验,3年以上开发/项目管理工作经验
3.能够独立完成中型项目的整体设计、任务计划和开发进度的管理工作
4.熟悉框架设计、系统设计、数据库设计、编码测试等软件工程知识和规范
5.精通软件开发流程,了解linux/unix系统,并能够熟练使用系统设计、数据库设计工具
6.对软件多层结构、以及各层间使用的软件技术有较全面的了解 ;      
7.具有开发队伍的管理能力和经验;
8.具备技术文档编写能力;
9.有乙方项目经理经历,能够与甲方顺畅沟通。
10..有互联网工作经历的优先。
继续阅读 »
这里的每一项技术都会直接帮助平台上的App开发者,并在真正的应用里得到实践检验。

我们不仅是技术的研发者,也是技术的输出方。

这里的每一项技术都在改变世界!

欢迎加入!我们支持开源运动!

来环信,和我们一起用技术改变世界!

 以下职位工作地点是在河南郑州开发,小伙伴们简历赶紧砸过来吧!内推邮箱地址duc@easemob.com
 
iOS工程师

岗位职责:
1. 负责IM SDK开发与相关应用的开发;
2. 对客户提供解决方案和必要的技术支持;

任职资格:
1. 熟悉iOS开发环境、iOS App开发规范和App开发流程;
2. 熟练使用iOS开发核心库,有一定的文档编写能力;
3. 熟悉iOS SDK中布局、网络、数据库、HTTP协议、XML/JSON解析等;
4. 掌握iOS平台的模块化设计架构,能够设计出恰当的应用方案;
5. 熟悉iOS平台的内存管理机制,懂得内存优化技术;
6. 能够与产品经理、设计师、用户进行深入的沟通和交流;
7. 有即时通讯平台开发经验者优先考虑;
8. 两年以上开发经验,其中一年以上iOS应用开发经验;
9. Github 使用者、熟悉c/c++开发,有开源项目贡献者优先考虑。


安卓工程师

岗位职责:
1. 负责IM SDK开发与相关应用的开发;
2. 对客户提供解决方案和必要的技术支持;

任职资格:
1. 熟悉android开发环境、android应用开发规范和开发流程;
2. 熟练使用android SDK,熟悉JNI开发,有一定的文档编写能力;
3. 熟悉android SDK中布局、网络、数据库、HTTP协议、XML/JSON解析等;
4. 掌握Android 平台的模块化设计架构,能够设计出恰当的应用方案;
5. 熟悉 Android 平台的内存管理机制,懂得内存优化技术;
6. 能够与产品经理、设计师、用户进行深入的沟通和交流;
7. 有即时通讯平台开发经验者优先考虑;
8. 两年以上开发经验,其中一年以上android应用开发经验;
9. Github 使用者、熟悉c/c++开发,有开源项目贡献者优先考虑。


H5前端工程师

工作职责
1.环信Web、IM、SDK等的开发设计 
2.环信业务后台管理系统的开发设计
任职资格
1.有web前端经验,熟悉流行的前端技术, 包括但不限于bootstrap、html5、css3、saas、less、jQuery、bower、grunt、webpack、reactJs 
2.有H5移动端开发经验 
3.熟悉Ajax, Rest等原理和使用方式 
4.熟悉Http, WebSocket, Spdy等协议 
5.深刻理解Web标准, 对可用性、可访问性等相关知识有实际的了解和实践经验 
6.有一定的设计美感 
7.简历请同时提供以往项目地址,以及github地址或技术博客地址 
加分项: 
1.熟悉ruby、python、bash、nodejs等脚本语言优先考虑 
2.有开源社区经验者优先考虑


后台工程师
工作职责
1.负责持续改进后端服务,打造业界领先的即时通讯云服务; 
2.或负责持续优化服务性能,提高后端服务的承载能力; 
3.或负责完成后端服务的多机房改造,为全球用户提供可靠实时的即时通讯服务;
任职资格
1.熟悉Java、Erlang或C/C++其中两种语言,有Unix/Linux平台相关开发经验; 
2.熟悉网络通信机制及常用数据传输协议; 
3.算法基础扎实,有ACM、TopCoder或其他比赛经验者优先; 
4.熟悉数据库相关开发,了解MySQL数据库,有HBase、Redis或其他NoSQL相关使用经验者优先; 
5.有较强的解决问题能力,能够承受压力情况下解决线上问题; 
6.能够带领团队成员,研究并攻克技术难关; 
7.需要有开放共享的心态,接受开源思想,有Github创建、维护或参与经验更好; 
8.5年以上开发工作经验;


项目经理(项目实施)-IM
您的责任:
1.确保项目目标的实现,领导项目团队准时、优质的完成全部工作。
2.及时有效地与客户沟通,了解项目的整体需求,与客户保持持续的联系,及时反馈阶段性的成果,并及时向研发更新客户提出的合理需求。
3.制定开发计划文档,量化任务,并合理分配给相关人员。
4.跟踪项目进度,有效的提高代码质量,并及时与研发、实施部署人员以及QA之间沟通,保证项目以及附属文档的完整和规范。
我们的要求:
1. 正规大学本科及以上学历
2.5年以上软件行业经验,3年以上开发/项目管理工作经验
3.能够独立完成中型项目的整体设计、任务计划和开发进度的管理工作
4.熟悉框架设计、系统设计、数据库设计、编码测试等软件工程知识和规范
5.精通软件开发流程,了解linux/unix系统,并能够熟练使用系统设计、数据库设计工具
6.对软件多层结构、以及各层间使用的软件技术有较全面的了解 ;      
7.具有开发队伍的管理能力和经验;
8.具备技术文档编写能力;
9.有乙方项目经理经历,能够与甲方顺畅沟通。
10..有互联网工作经历的优先。

iOS工程师

岗位职责:
1. 负责IM SDK开发与相关应用的开发;
2. 对客户提供解决方案和必要的技术支持;

任职资格:
1. 熟悉iOS开发环境、iOS App开发规范和App开发流程;
2. 熟练使用iOS开发核心库,有一定的文档编写能力;
3. 熟悉iOS SDK中布局、网络、数据库、HTTP协议、XML/JSON解析等;
4. 掌握iOS平台的模块化设计架构,能够设计出恰当的应用方案;
5. 熟悉iOS平台的内存管理机制,懂得内存优化技术;
6. 能够与产品经理、设计师、用户进行深入的沟通和交流;
7. 有即时通讯平台开发经验者优先考虑;
8. 两年以上开发经验,其中一年以上iOS应用开发经验;
9. Github 使用者、熟悉c/c++开发,有开源项目贡献者优先考虑。


安卓工程师

岗位职责:
1. 负责IM SDK开发与相关应用的开发;
2. 对客户提供解决方案和必要的技术支持;

任职资格:
1. 熟悉android开发环境、android应用开发规范和开发流程;
2. 熟练使用android SDK,熟悉JNI开发,有一定的文档编写能力;
3. 熟悉android SDK中布局、网络、数据库、HTTP协议、XML/JSON解析等;
4. 掌握Android 平台的模块化设计架构,能够设计出恰当的应用方案;
5. 熟悉 Android 平台的内存管理机制,懂得内存优化技术;
6. 能够与产品经理、设计师、用户进行深入的沟通和交流;
7. 有即时通讯平台开发经验者优先考虑;
8. 两年以上开发经验,其中一年以上android应用开发经验;
9. Github 使用者、熟悉c/c++开发,有开源项目贡献者优先考虑。


H5前端工程师

工作职责
1.环信Web、IM、SDK等的开发设计 
2.环信业务后台管理系统的开发设计
任职资格
1.有web前端经验,熟悉流行的前端技术, 包括但不限于bootstrap、html5、css3、saas、less、jQuery、bower、grunt、webpack、reactJs 
2.有H5移动端开发经验 
3.熟悉Ajax, Rest等原理和使用方式 
4.熟悉Http, WebSocket, Spdy等协议 
5.深刻理解Web标准, 对可用性、可访问性等相关知识有实际的了解和实践经验 
6.有一定的设计美感 
7.简历请同时提供以往项目地址,以及github地址或技术博客地址 
加分项: 
1.熟悉ruby、python、bash、nodejs等脚本语言优先考虑 
2.有开源社区经验者优先考虑


后台工程师
工作职责
1.负责持续改进后端服务,打造业界领先的即时通讯云服务; 
2.或负责持续优化服务性能,提高后端服务的承载能力; 
3.或负责完成后端服务的多机房改造,为全球用户提供可靠实时的即时通讯服务;
任职资格
1.熟悉Java、Erlang或C/C++其中两种语言,有Unix/Linux平台相关开发经验; 
2.熟悉网络通信机制及常用数据传输协议; 
3.算法基础扎实,有ACM、TopCoder或其他比赛经验者优先; 
4.熟悉数据库相关开发,了解MySQL数据库,有HBase、Redis或其他NoSQL相关使用经验者优先; 
5.有较强的解决问题能力,能够承受压力情况下解决线上问题; 
6.能够带领团队成员,研究并攻克技术难关; 
7.需要有开放共享的心态,接受开源思想,有Github创建、维护或参与经验更好; 
8.5年以上开发工作经验;


项目经理(项目实施)-IM
您的责任:
1.确保项目目标的实现,领导项目团队准时、优质的完成全部工作。
2.及时有效地与客户沟通,了解项目的整体需求,与客户保持持续的联系,及时反馈阶段性的成果,并及时向研发更新客户提出的合理需求。
3.制定开发计划文档,量化任务,并合理分配给相关人员。
4.跟踪项目进度,有效的提高代码质量,并及时与研发、实施部署人员以及QA之间沟通,保证项目以及附属文档的完整和规范。
我们的要求:
1. 正规大学本科及以上学历
2.5年以上软件行业经验,3年以上开发/项目管理工作经验
3.能够独立完成中型项目的整体设计、任务计划和开发进度的管理工作
4.熟悉框架设计、系统设计、数据库设计、编码测试等软件工程知识和规范
5.精通软件开发流程,了解linux/unix系统,并能够熟练使用系统设计、数据库设计工具
6.对软件多层结构、以及各层间使用的软件技术有较全面的了解 ;      
7.具有开发队伍的管理能力和经验;
8.具备技术文档编写能力;
9.有乙方项目经理经历,能够与甲方顺畅沟通。
10..有互联网工作经历的优先。 收起阅读 »

【环信征文】集成环信V3.3.4SDK遇到的两个问题

公司又有了新项目,依然是含有即时通讯功能模块的项目。在经历了上个项目对环信sdk的集成后,对环信EaseUI有了大概的了解。这次果断还是集成环信,一回生二回熟,毕竟哪些地方有坑心里有数了。所以这次的项目集成起来就相对来说顺利很多。
项目集成的是环信V3.3.2版本,但今天下载了V3.3.4版本检查了一下,发现依然有不少V3.3.2版本遗留的问题没有修复,下面会列出一些项目中遇到的问题,并提供解决办法。
首先在会话界面自定义一个类比如BHChatViewController,继承自EaseMessageViewController类,基本上一个简单的界面就有了。因为是医疗类的项目,对话双方有可能是患者和患者,也有可能是患者和医生。项目需求是如果是患者和医生聊天,必须先经过预约,并只能在预约时间区间内才能和医生发送聊天消息、图片、语音、实时音视频。
以下就是EaseMessageViewController类的发送各种消息的方法
那么根据需要只需重写以下方法即可。
/*!
@method
@brief 发送文本消息
@discussion
@param text 文本消息
@result
*/
- (void)sendTextMessage:(NSString *)text;

/*!
@method
@brief 发送文本消息
@discussion
@param text 文本消息
@param ext 扩展信息
@result
*/
- (void)sendTextMessage:(NSString *)text withExt:(NSDictionary*)ext;

/*!
@method
@brief 发送图片消息
@discussion
@param image 发送图片
@result
*/
- (void)sendImageMessage:(UIImage *)image;

/*!
@method
@brief 发送位置消息
@discussion
@param latitude 经度
@param longitude 纬度
@param address 地址
@result
*/
- (void)sendLocationMessageLatitude:(double)latitude
longitude:(double)longitude
andAddress:(NSString *)address;

/*!
@method
@brief 发送语音消息
@discussion
@param localPath 语音本地地址
@param duration 时长
@result
*/
- (void)sendVoiceMessageWithLocalPath:(NSString *)localPath
duration:(NSInteger)duration;

/*!
@method
@brief 发送视频消息
@discussion
@param url 视频url
@result
*/
- (void)sendVideoMessageWithURL:(NSURL *)url;
我在对发送图片的操作进行处理的时候,发现当拍照发图时,走这个方法
//当你拍照发图时,走这个方法
- (void)sendImageMessage:(UIImage *)image;
但当从相册选择图片发送时,会发现,不走上面的方法了。
仔细检查代码发现走了EaseMessageViewController.m的如下方法

环信2.png

然而这个方法,环信并没有放在EaseMessageViewController.h成为公开方法。我们只需手动粘贴方法到.h,然后在自己的子类重写就可以了。

还有一个关于更多下图更多功能区域的问题

EaseChatBarMoreView.png

如上图所示,相册、拍照、视频等附加功能按钮,环信用EaseChatBarMoreView类来管理的。
如果需要增加功能按钮用这个方法
/*!
@method
@brief 新增一个新的功能按钮
@discussion
@param image 按钮图片
@param highLightedImage 高亮图片
@param title 按钮标题
@result
*/
- (void)insertItemWithImage:(UIImage*)image
highlightedImage:(UIImage*)highLightedImage
title:(NSString*)title;
移除某个功能按钮用这个方法
/*!
@method
@brief 根据索引删除功能按钮
@discussion
@param index 按钮索引
@result
*/
- (void)removeItematIndex:(NSInteger)index;
修改一个功能按钮用这个方法
/*!
@method
@brief 修改功能按钮图片
@discussion
@param image 按钮图片
@param highLightedImage 高亮图片
@param title 按钮标题
@param index 按钮索引
@result
*/
- (void)updateItemWithImage:(UIImage*)image
highlightedImage:(UIImage*)highLightedImage
title:(NSString*)title
atIndex:(NSInteger)index;
可当你添加按钮,或者修改按钮时,会发现按钮的名字设置不了
然后检查环信内部的实现,发现title的值在方法里根本就没用到?!
索性不用updateItemWithImage这个方法了,直接去改内部代码。
修改代码如下

到EaseChatBarMoreView.m修改- (void)setupSubviewsForType:(EMChatToolbarType)type方法。改动的部分在代码后面有标注。
- (void)setupSubviewsForType:(EMChatToolbarType)type
{
//self.backgroundColor = [UIColor clearColor];
self.accessibilityIdentifier = @"more_view";

_scrollview = [[UIScrollView alloc] init];
_scrollview.pagingEnabled = YES;
_scrollview.showsHorizontalScrollIndicator = NO;
_scrollview.showsVerticalScrollIndicator = NO;
_scrollview.delegate = self;
[self addSubview:_scrollview];

_pageControl = [[UIPageControl alloc] init];
_pageControl.currentPage = 0;
_pageControl.numberOfPages = 1;
[self addSubview:_pageControl];

CGFloat insets = (self.frame.size.width - 4 * CHAT_BUTTON_SIZE) / 5;

_photoButton =[UIButton buttonWithType:UIButtonTypeCustom];
[_photoButton setTitle:@"相册" forState:UIControlStateNormal];//改动
[_photoButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];//改动
_photoButton.titleLabel.font = [UIFont systemFontOfSize: 12.0];//改动
_photoButton.imageEdgeInsets = UIEdgeInsetsMake(-10, 0, 20, 0);//改动
_photoButton.titleEdgeInsets = UIEdgeInsetsMake(14, -60, -20, 0);//改动
_photoButton.accessibilityIdentifier = @"image";
[_photoButton setFrame:CGRectMake(insets, 10, CHAT_BUTTON_SIZE , CHAT_BUTTON_SIZE+10)];//改动
[_photoButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_photo"] forState:UIControlStateNormal];
[_photoButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_photoSelected"] forState:UIControlStateHighlighted];
[_photoButton addTarget:self action:@selector(photoAction) forControlEvents:UIControlEventTouchUpInside];
_photoButton.tag = MOREVIEW_BUTTON_TAG;
[_scrollview addSubview:_photoButton];

_locationButton =[UIButton buttonWithType:UIButtonTypeCustom];
[_locationButton setTitle:@"位置" forState:UIControlStateNormal];//改动
[_locationButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];//改动
_locationButton.titleLabel.font = [UIFont systemFontOfSize: 12.0];//改动
_locationButton.imageEdgeInsets = UIEdgeInsetsMake(-10, 0, 20, 0);//改动
_locationButton.titleEdgeInsets = UIEdgeInsetsMake(14, -60, -20, 0);//改动
_locationButton.accessibilityIdentifier = @"location";
[_locationButton setFrame:CGRectMake(insets * 2 + CHAT_BUTTON_SIZE, 10, CHAT_BUTTON_SIZE , CHAT_BUTTON_SIZE+10)];//
[_locationButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_location"] forState:UIControlStateNormal];
[_locationButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_locationSelected"] forState:UIControlStateHighlighted];
[_locationButton addTarget:self action:@selector(locationAction) forControlEvents:UIControlEventTouchUpInside];
_locationButton.tag = MOREVIEW_BUTTON_TAG + 1;
[_scrollview addSubview:_locationButton];

_takePicButton =[UIButton buttonWithType:UIButtonTypeCustom];
[_takePicButton setTitle:@"拍照" forState:UIControlStateNormal];//改动
[_takePicButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];//改动
_takePicButton.titleLabel.font = [UIFont systemFontOfSize: 12.0];//改动
_takePicButton.imageEdgeInsets = UIEdgeInsetsMake(-10, 0, 20, 0);//改动
_takePicButton.titleEdgeInsets = UIEdgeInsetsMake(14, -60, -20, 0);//改动
[_takePicButton setFrame:CGRectMake(insets * 3 + CHAT_BUTTON_SIZE * 2, 10, CHAT_BUTTON_SIZE , CHAT_BUTTON_SIZE+10)];//改动
[_takePicButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_camera"] forState:UIControlStateNormal];
[_takePicButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_cameraSelected"] forState:UIControlStateHighlighted];
[_takePicButton addTarget:self action:@selector(takePicAction) forControlEvents:UIControlEventTouchUpInside];
_takePicButton.tag = MOREVIEW_BUTTON_TAG + 2;
_maxIndex = 2;
[_scrollview addSubview:_takePicButton];

CGRect frame = self.frame;
if (type == EMChatToolbarTypeChat) {
frame.size.height = 150;
_audioCallButton =[UIButton buttonWithType:UIButtonTypeCustom];
[_audioCallButton setTitle:@"语音" forState:UIControlStateNormal];//改动
[_audioCallButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];//改动
_audioCallButton.titleLabel.font = [UIFont systemFontOfSize: 12.0];//改动
_audioCallButton.imageEdgeInsets = UIEdgeInsetsMake(-10, 0, 20, 0);//改动
_audioCallButton.titleEdgeInsets = UIEdgeInsetsMake(14, -60, -20, 0);//改动
[_audioCallButton setFrame:CGRectMake(insets * 4 + CHAT_BUTTON_SIZE * 3, 10, CHAT_BUTTON_SIZE , CHAT_BUTTON_SIZE+10)];//
[_audioCallButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_audioCall"] forState:UIControlStateNormal];
[_audioCallButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_audioCallSelected"] forState:UIControlStateHighlighted];
[_audioCallButton addTarget:self action:@selector(takeAudioCallAction) forControlEvents:UIControlEventTouchUpInside];
_audioCallButton.tag = MOREVIEW_BUTTON_TAG + 3;
[_scrollview addSubview:_audioCallButton];

_videoCallButton =[UIButton buttonWithType:UIButtonTypeCustom];
[_videoCallButton setTitle:@"视频" forState:UIControlStateNormal];//改动
[_videoCallButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];//改动
_videoCallButton.titleLabel.font = [UIFont systemFontOfSize: 12.0];//改动
_videoCallButton.imageEdgeInsets = UIEdgeInsetsMake(-10, 0, 20, 0);//改动
_videoCallButton.titleEdgeInsets = UIEdgeInsetsMake(14, -60, -20, 0);//改动
[_videoCallButton setFrame:CGRectMake(insets, 10 * 2 + CHAT_BUTTON_SIZE + 10, CHAT_BUTTON_SIZE , CHAT_BUTTON_SIZE+10)];//
[_videoCallButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_videoCall"] forState:UIControlStateNormal];
[_videoCallButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_videoCallSelected"] forState:UIControlStateHighlighted];
[_videoCallButton addTarget:self action:@selector(takeVideoCallAction) forControlEvents:UIControlEventTouchUpInside];
_videoCallButton.tag =MOREVIEW_BUTTON_TAG + 4;
_maxIndex = 4;
[_scrollview addSubview:_videoCallButton];
}
else if (type == EMChatToolbarTypeGroup)
{
frame.size.height = 80;
}
self.frame = frame;
_scrollview.frame = CGRectMake(0, 0, CGRectGetWidth(frame), CGRectGetHeight(frame));
_pageControl.frame = CGRectMake(0, CGRectGetHeight(frame) - 20, CGRectGetWidth(frame), 20);
_pageControl.hidden = _pageControl.numberOfPages<=1;
}


本人github:https://github.com/BHAreslee
本人简书:http://www.jianshu.com/u/bb53043aaa00
以上就是集成环信时暂时发现的问题,欢迎大家分享你们遇到的问题,也欢迎加入QQ群:372251359,一起讨论交流即时通讯的问题。
本人微信公众号:放心安慰剂

qrcode_for_gh_bc92a063b4a2_430.jpg
继续阅读 »
公司又有了新项目,依然是含有即时通讯功能模块的项目。在经历了上个项目对环信sdk的集成后,对环信EaseUI有了大概的了解。这次果断还是集成环信,一回生二回熟,毕竟哪些地方有坑心里有数了。所以这次的项目集成起来就相对来说顺利很多。
项目集成的是环信V3.3.2版本,但今天下载了V3.3.4版本检查了一下,发现依然有不少V3.3.2版本遗留的问题没有修复,下面会列出一些项目中遇到的问题,并提供解决办法。
首先在会话界面自定义一个类比如BHChatViewController,继承自EaseMessageViewController类,基本上一个简单的界面就有了。因为是医疗类的项目,对话双方有可能是患者和患者,也有可能是患者和医生。项目需求是如果是患者和医生聊天,必须先经过预约,并只能在预约时间区间内才能和医生发送聊天消息、图片、语音、实时音视频。
以下就是EaseMessageViewController类的发送各种消息的方法
那么根据需要只需重写以下方法即可。
/*!
@method
@brief 发送文本消息
@discussion
@param text 文本消息
@result
*/
- (void)sendTextMessage:(NSString *)text;

/*!
@method
@brief 发送文本消息
@discussion
@param text 文本消息
@param ext 扩展信息
@result
*/
- (void)sendTextMessage:(NSString *)text withExt:(NSDictionary*)ext;

/*!
@method
@brief 发送图片消息
@discussion
@param image 发送图片
@result
*/
- (void)sendImageMessage:(UIImage *)image;

/*!
@method
@brief 发送位置消息
@discussion
@param latitude 经度
@param longitude 纬度
@param address 地址
@result
*/
- (void)sendLocationMessageLatitude:(double)latitude
longitude:(double)longitude
andAddress:(NSString *)address;

/*!
@method
@brief 发送语音消息
@discussion
@param localPath 语音本地地址
@param duration 时长
@result
*/
- (void)sendVoiceMessageWithLocalPath:(NSString *)localPath
duration:(NSInteger)duration;

/*!
@method
@brief 发送视频消息
@discussion
@param url 视频url
@result
*/
- (void)sendVideoMessageWithURL:(NSURL *)url;
我在对发送图片的操作进行处理的时候,发现当拍照发图时,走这个方法
//当你拍照发图时,走这个方法
- (void)sendImageMessage:(UIImage *)image;
但当从相册选择图片发送时,会发现,不走上面的方法了。
仔细检查代码发现走了EaseMessageViewController.m的如下方法

环信2.png

然而这个方法,环信并没有放在EaseMessageViewController.h成为公开方法。我们只需手动粘贴方法到.h,然后在自己的子类重写就可以了。

还有一个关于更多下图更多功能区域的问题

EaseChatBarMoreView.png

如上图所示,相册、拍照、视频等附加功能按钮,环信用EaseChatBarMoreView类来管理的。
如果需要增加功能按钮用这个方法
/*!
@method
@brief 新增一个新的功能按钮
@discussion
@param image 按钮图片
@param highLightedImage 高亮图片
@param title 按钮标题
@result
*/
- (void)insertItemWithImage:(UIImage*)image
highlightedImage:(UIImage*)highLightedImage
title:(NSString*)title;
移除某个功能按钮用这个方法
/*!
@method
@brief 根据索引删除功能按钮
@discussion
@param index 按钮索引
@result
*/
- (void)removeItematIndex:(NSInteger)index;
修改一个功能按钮用这个方法
/*!
@method
@brief 修改功能按钮图片
@discussion
@param image 按钮图片
@param highLightedImage 高亮图片
@param title 按钮标题
@param index 按钮索引
@result
*/
- (void)updateItemWithImage:(UIImage*)image
highlightedImage:(UIImage*)highLightedImage
title:(NSString*)title
atIndex:(NSInteger)index;
可当你添加按钮,或者修改按钮时,会发现按钮的名字设置不了
然后检查环信内部的实现,发现title的值在方法里根本就没用到?!
索性不用updateItemWithImage这个方法了,直接去改内部代码。
修改代码如下

到EaseChatBarMoreView.m修改- (void)setupSubviewsForType:(EMChatToolbarType)type方法。改动的部分在代码后面有标注。
- (void)setupSubviewsForType:(EMChatToolbarType)type
{
//self.backgroundColor = [UIColor clearColor];
self.accessibilityIdentifier = @"more_view";

_scrollview = [[UIScrollView alloc] init];
_scrollview.pagingEnabled = YES;
_scrollview.showsHorizontalScrollIndicator = NO;
_scrollview.showsVerticalScrollIndicator = NO;
_scrollview.delegate = self;
[self addSubview:_scrollview];

_pageControl = [[UIPageControl alloc] init];
_pageControl.currentPage = 0;
_pageControl.numberOfPages = 1;
[self addSubview:_pageControl];

CGFloat insets = (self.frame.size.width - 4 * CHAT_BUTTON_SIZE) / 5;

_photoButton =[UIButton buttonWithType:UIButtonTypeCustom];
[_photoButton setTitle:@"相册" forState:UIControlStateNormal];//改动
[_photoButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];//改动
_photoButton.titleLabel.font = [UIFont systemFontOfSize: 12.0];//改动
_photoButton.imageEdgeInsets = UIEdgeInsetsMake(-10, 0, 20, 0);//改动
_photoButton.titleEdgeInsets = UIEdgeInsetsMake(14, -60, -20, 0);//改动
_photoButton.accessibilityIdentifier = @"image";
[_photoButton setFrame:CGRectMake(insets, 10, CHAT_BUTTON_SIZE , CHAT_BUTTON_SIZE+10)];//改动
[_photoButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_photo"] forState:UIControlStateNormal];
[_photoButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_photoSelected"] forState:UIControlStateHighlighted];
[_photoButton addTarget:self action:@selector(photoAction) forControlEvents:UIControlEventTouchUpInside];
_photoButton.tag = MOREVIEW_BUTTON_TAG;
[_scrollview addSubview:_photoButton];

_locationButton =[UIButton buttonWithType:UIButtonTypeCustom];
[_locationButton setTitle:@"位置" forState:UIControlStateNormal];//改动
[_locationButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];//改动
_locationButton.titleLabel.font = [UIFont systemFontOfSize: 12.0];//改动
_locationButton.imageEdgeInsets = UIEdgeInsetsMake(-10, 0, 20, 0);//改动
_locationButton.titleEdgeInsets = UIEdgeInsetsMake(14, -60, -20, 0);//改动
_locationButton.accessibilityIdentifier = @"location";
[_locationButton setFrame:CGRectMake(insets * 2 + CHAT_BUTTON_SIZE, 10, CHAT_BUTTON_SIZE , CHAT_BUTTON_SIZE+10)];//
[_locationButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_location"] forState:UIControlStateNormal];
[_locationButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_locationSelected"] forState:UIControlStateHighlighted];
[_locationButton addTarget:self action:@selector(locationAction) forControlEvents:UIControlEventTouchUpInside];
_locationButton.tag = MOREVIEW_BUTTON_TAG + 1;
[_scrollview addSubview:_locationButton];

_takePicButton =[UIButton buttonWithType:UIButtonTypeCustom];
[_takePicButton setTitle:@"拍照" forState:UIControlStateNormal];//改动
[_takePicButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];//改动
_takePicButton.titleLabel.font = [UIFont systemFontOfSize: 12.0];//改动
_takePicButton.imageEdgeInsets = UIEdgeInsetsMake(-10, 0, 20, 0);//改动
_takePicButton.titleEdgeInsets = UIEdgeInsetsMake(14, -60, -20, 0);//改动
[_takePicButton setFrame:CGRectMake(insets * 3 + CHAT_BUTTON_SIZE * 2, 10, CHAT_BUTTON_SIZE , CHAT_BUTTON_SIZE+10)];//改动
[_takePicButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_camera"] forState:UIControlStateNormal];
[_takePicButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_cameraSelected"] forState:UIControlStateHighlighted];
[_takePicButton addTarget:self action:@selector(takePicAction) forControlEvents:UIControlEventTouchUpInside];
_takePicButton.tag = MOREVIEW_BUTTON_TAG + 2;
_maxIndex = 2;
[_scrollview addSubview:_takePicButton];

CGRect frame = self.frame;
if (type == EMChatToolbarTypeChat) {
frame.size.height = 150;
_audioCallButton =[UIButton buttonWithType:UIButtonTypeCustom];
[_audioCallButton setTitle:@"语音" forState:UIControlStateNormal];//改动
[_audioCallButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];//改动
_audioCallButton.titleLabel.font = [UIFont systemFontOfSize: 12.0];//改动
_audioCallButton.imageEdgeInsets = UIEdgeInsetsMake(-10, 0, 20, 0);//改动
_audioCallButton.titleEdgeInsets = UIEdgeInsetsMake(14, -60, -20, 0);//改动
[_audioCallButton setFrame:CGRectMake(insets * 4 + CHAT_BUTTON_SIZE * 3, 10, CHAT_BUTTON_SIZE , CHAT_BUTTON_SIZE+10)];//
[_audioCallButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_audioCall"] forState:UIControlStateNormal];
[_audioCallButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_audioCallSelected"] forState:UIControlStateHighlighted];
[_audioCallButton addTarget:self action:@selector(takeAudioCallAction) forControlEvents:UIControlEventTouchUpInside];
_audioCallButton.tag = MOREVIEW_BUTTON_TAG + 3;
[_scrollview addSubview:_audioCallButton];

_videoCallButton =[UIButton buttonWithType:UIButtonTypeCustom];
[_videoCallButton setTitle:@"视频" forState:UIControlStateNormal];//改动
[_videoCallButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];//改动
_videoCallButton.titleLabel.font = [UIFont systemFontOfSize: 12.0];//改动
_videoCallButton.imageEdgeInsets = UIEdgeInsetsMake(-10, 0, 20, 0);//改动
_videoCallButton.titleEdgeInsets = UIEdgeInsetsMake(14, -60, -20, 0);//改动
[_videoCallButton setFrame:CGRectMake(insets, 10 * 2 + CHAT_BUTTON_SIZE + 10, CHAT_BUTTON_SIZE , CHAT_BUTTON_SIZE+10)];//
[_videoCallButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_videoCall"] forState:UIControlStateNormal];
[_videoCallButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_videoCallSelected"] forState:UIControlStateHighlighted];
[_videoCallButton addTarget:self action:@selector(takeVideoCallAction) forControlEvents:UIControlEventTouchUpInside];
_videoCallButton.tag =MOREVIEW_BUTTON_TAG + 4;
_maxIndex = 4;
[_scrollview addSubview:_videoCallButton];
}
else if (type == EMChatToolbarTypeGroup)
{
frame.size.height = 80;
}
self.frame = frame;
_scrollview.frame = CGRectMake(0, 0, CGRectGetWidth(frame), CGRectGetHeight(frame));
_pageControl.frame = CGRectMake(0, CGRectGetHeight(frame) - 20, CGRectGetWidth(frame), 20);
_pageControl.hidden = _pageControl.numberOfPages<=1;
}


本人github:https://github.com/BHAreslee
本人简书:http://www.jianshu.com/u/bb53043aaa00
以上就是集成环信时暂时发现的问题,欢迎大家分享你们遇到的问题,也欢迎加入QQ群:372251359,一起讨论交流即时通讯的问题。
本人微信公众号:放心安慰剂

qrcode_for_gh_bc92a063b4a2_430.jpg
收起阅读 »

android studio 2.3.3 最新 中文 汉化包 韩梦飞沙 安卓工作室 美化包

韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha

汉化包 百度云盘 下载地址:https://pan.baidu.com/s/1pLjwyeB 
最新最详细全面最牛逼的汉化!稳定无BUG!设置界面可以打开!不会报错!中英对照!界面酷炫!
使用汉化美化包,让你的开发工具IDE 不再单调普通,彰显个性,与众不同!
中文的 菜单工具设置信息,让你一眼看懂,让你用好这款开发软件,最大发挥它的作用!
 
继续阅读 »
韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha

汉化包 百度云盘 下载地址:https://pan.baidu.com/s/1pLjwyeB 
最新最详细全面最牛逼的汉化!稳定无BUG!设置界面可以打开!不会报错!中英对照!界面酷炫!
使用汉化美化包,让你的开发工具IDE 不再单调普通,彰显个性,与众不同!
中文的 菜单工具设置信息,让你一眼看懂,让你用好这款开发软件,最大发挥它的作用!
  收起阅读 »

环信公开课16期回放|环信智能鉴黄:用深度学习实现99%精准度的鉴黄服务

   8月31日,环信公开课以“智能鉴黄”为主题,为大家普及了内容审查工作的前世今生,以及环信智能鉴黄算法、技术实现和行业解决方案。
 
关于环信智能鉴黄:

   随着移动互联网的飞速发展和信息量的猛增,大量的色情、赌博、暴力等不良信息图片夹杂在信息流中,严重影响着整个互联网的体验和健康发展。各大互联网公司为了保持自己所提供的服务不触犯国家法律和法规,使得鉴黄工作变得尤为重要。环信智能鉴黄服务基于深度学习的智能鉴黄算法,识别精准度高达99%,可以帮助企业完成95%的图片内容审查工作,节省90%的时间及人工成本。


环信公开课第16期分享内容:
001.png


002.png


003.png


004.png


005.png


006.png


007.png


008.png


009.png


010.png


环信公开课第16期视频回放:






参加环信公开课还有大礼相送:
恭喜手机尾号8985的leoNN同学成为本期公开课幸运观众,获得环信定制版瑞士军团双肩背包。

环信智能鉴黄免费体验请联系环信小助手,微信huanxin-hh
3a36009c9eb571b9a3a2797f17c4ae25.gif
继续阅读 »
   8月31日,环信公开课以“智能鉴黄”为主题,为大家普及了内容审查工作的前世今生,以及环信智能鉴黄算法、技术实现和行业解决方案。
 
关于环信智能鉴黄:

   随着移动互联网的飞速发展和信息量的猛增,大量的色情、赌博、暴力等不良信息图片夹杂在信息流中,严重影响着整个互联网的体验和健康发展。各大互联网公司为了保持自己所提供的服务不触犯国家法律和法规,使得鉴黄工作变得尤为重要。环信智能鉴黄服务基于深度学习的智能鉴黄算法,识别精准度高达99%,可以帮助企业完成95%的图片内容审查工作,节省90%的时间及人工成本。


环信公开课第16期分享内容:
001.png


002.png


003.png


004.png


005.png


006.png


007.png


008.png


009.png


010.png


环信公开课第16期视频回放:






参加环信公开课还有大礼相送:
恭喜手机尾号8985的leoNN同学成为本期公开课幸运观众,获得环信定制版瑞士军团双肩背包。

环信智能鉴黄免费体验请联系环信小助手,微信huanxin-hh
3a36009c9eb571b9a3a2797f17c4ae25.gif
收起阅读 »

【开源项目】一个基于环信IM开发的开源的私密社交APP-Baby

   Baby这个开源项目基于环信IM开发,刚开始选择IM的时候,看到知乎上黑环信的人挺多的,就亲自下载了几家IM的demo源码跑一遍,从功能、集成难易和消息稳定几个方面对比,最终还是选择了环信。集成这方面环信做的真不错,尤其是有了EaseUi这个包,基本上一天就能集成完毕。项目运行至今没有出现过什么问题,发送消息挺稳定的。
先上效果图

003.png

开屏页的登录和注册


001.png

编辑个人信息


002.png

相册页面


004.png

首页的Moment


版本更新:
 
version 1.6
  1. 加入Tinker 热修复
  2. 更新部分依赖
  3. 修复大量细节问题,加入部分注释


version 1.5
  1. bug fix
  2. update sth


version 1.4
  1. 增加长按删除功能
  2. 优化Rxbus订阅加载数据
  3. 外国友人优化的一些细节
  4. 等等


version 1.3
  1. 增加了评论功能
  2. 优化了相册加载
  3. 修复了一些内存泄漏
  4. 等等


version 1.2
  1. 修复了一些Bug
  2. 把登陆注册事件换了个Zip操作符更符合流的思想


version 1.1
  1. 修复了主页背景无法切换的问题
  2. 修复了聊天推送的问题
  3. 修了语音视频的问题
  4. 做了一些细节修改

Download

 
github地址

 Development Environment & Library
 
MVP

这个项目是基于MVP框架写的(大体上,聊天那块直接用环信的了),大部分Base类参考FastAndroid里边的基类,参考这个很快就能布好基本的MVP架构。本来是有考虑过MVVM后来想想还是先学习一下MVP吧,看过几个MVVM项目感觉还是挺好用的,不过还是BETA版不知道有没有什么坑。

Material Design

早就手痒想体验一把V7包里边的各种控件了,特喜欢coordinatorlayout和collapsingtoolbarlayout的互动让Tollbar隐藏又现的感觉,但是看起来好看还是要点代价的,在这里捣鼓了不少时间,尤其是collapsingtoolbarlayout的Expanded固定让我Google了好久,因为用英文搜索可能我表达的不太好,最后竟然是一句nestedScroll(false)就可以了。。。。 还是感谢Stackoveflow里边的大腿吧。

Dagger2

依赖注入Dagger2,也是我早就想用的一个框架了,理由是各种配合Mvp十分方便和好用,渐渐也能体会到一次注入到处可用的快感。不过一个新技术真的学习成本,国内没什么中文文档介绍,看国外的看的云里雾里。原理看的明白,用起来好像不太知道如何使用,尤其是在@inject之后对象,也可以在别的地方Inject,原本是被Inject方后来也成了Module提供方。虽然到最后原理还不是特别明白这里,但还是不阻碍用起来的快感。

Realm

一开始被新技术吸引到的是不会放过任何新东西的包括Realm,不过进了坑不代表这个坑可以跳阿。由于我这次用到了leacncloud,Realm感觉会和LeanCloud的子类化冲突让你只能选择其中之一,不过这个也算了,Leancloud提供了类似Map的Put方法也可以接受就是麻烦了点。但是被坑到的地方是Realm所谓的自动数据同步竟然是一改就是改真实的数据,并不是数据的拷贝。。。感觉和我使用到要缓存的数据有点冲突,因为这个Moment里边的项是有点赞的,点赞要修改当前Recycleview的数据(修改数据要开事务)。修改数据后会出现一些很奇怪的现象,不在Recycleview当前Item会跳到当前Item,点赞的动画也会消失。。。真的是想破脑袋也解决不了,就直接跳坑了。最后感觉这个Realm在保存不跟服务器需要同步的数据会好点。

LeanCloud

用LeanCloud是因为在知乎太多吹它的人了而且它的确在BAAS这方面功能比较多(后来才发现即时通信没有语音和视频),所以就尝试使用了,SDK整体来说是不错的都挺好用的,满足了我对存储方面的要求。不过就在我开发的这几天,貌似稳定性没有想象中那么好,好几次上传个头像都会SocketTimeOut,查询也会有点慢,不过还好都在接受范围内(不过要是到了收费的标准我就接受不了)。

环信

baby这个开源项目基于环信IM开发,刚开始选择IM的时候,看到知乎上黑环信的人挺多的,就亲自下载了几家IM的demo源码跑一遍,从功能、集成难易和消息稳定几个方面对比,最终还是选择了环信。集成这方面环信做的真不错,尤其是有了EaseUi这个包,基本上一天就能集成完毕。项目运行至今没有出现过什么问题,发送消息挺稳定的。

Rxjava、RxAndroid

Rxjava我从第一眼看到了就喜欢上了(个人特喜欢那种通过.设置完成的感觉),接触也有几个月,一开始就和Retrofit 、Okhttp一起使用。学习成本还是要有的阿,看了不知道多少篇关于Rxjava使用的文章和例子,对里边的操作符也仅仅停留在那几个最常用的,其他一大堆好多都没用过,看来还用得不够。

Glide

Glide也是一个后来居上让我喜欢的图片加载库,一开始我喜欢picasso 是觉得轻巧而且好用有保证(主要是我偶像Jake Wharton主导,有加成),慢慢觉得Picasso对内存没有Glide来的友好,Glide在加载速度方面也领先,虽然整个库代码量是Picasso的几倍,但是比起重要的内存和用户体验来说还是Glide的领先一筹。

Butterknife、Ucrop等等

当让还有其他的一些润色的轮子啦,不过不是那么重要就不一一感谢啦。

Thanks
  • 感谢Github、LeanCloud、环信、还有造那么多轮子给我们用的Square FaceBook Google的大大们。
  • Thanks for improving my code m-ezzat.


Contacts

 
Copyright 2016 Roger ou

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
继续阅读 »
   Baby这个开源项目基于环信IM开发,刚开始选择IM的时候,看到知乎上黑环信的人挺多的,就亲自下载了几家IM的demo源码跑一遍,从功能、集成难易和消息稳定几个方面对比,最终还是选择了环信。集成这方面环信做的真不错,尤其是有了EaseUi这个包,基本上一天就能集成完毕。项目运行至今没有出现过什么问题,发送消息挺稳定的。
先上效果图

003.png

开屏页的登录和注册


001.png

编辑个人信息


002.png

相册页面


004.png

首页的Moment


版本更新:
 
version 1.6
  1. 加入Tinker 热修复
  2. 更新部分依赖
  3. 修复大量细节问题,加入部分注释


version 1.5
  1. bug fix
  2. update sth


version 1.4
  1. 增加长按删除功能
  2. 优化Rxbus订阅加载数据
  3. 外国友人优化的一些细节
  4. 等等


version 1.3
  1. 增加了评论功能
  2. 优化了相册加载
  3. 修复了一些内存泄漏
  4. 等等


version 1.2
  1. 修复了一些Bug
  2. 把登陆注册事件换了个Zip操作符更符合流的思想


version 1.1
  1. 修复了主页背景无法切换的问题
  2. 修复了聊天推送的问题
  3. 修了语音视频的问题
  4. 做了一些细节修改

Download

 
github地址

 Development Environment & Library
 
MVP

这个项目是基于MVP框架写的(大体上,聊天那块直接用环信的了),大部分Base类参考FastAndroid里边的基类,参考这个很快就能布好基本的MVP架构。本来是有考虑过MVVM后来想想还是先学习一下MVP吧,看过几个MVVM项目感觉还是挺好用的,不过还是BETA版不知道有没有什么坑。

Material Design

早就手痒想体验一把V7包里边的各种控件了,特喜欢coordinatorlayout和collapsingtoolbarlayout的互动让Tollbar隐藏又现的感觉,但是看起来好看还是要点代价的,在这里捣鼓了不少时间,尤其是collapsingtoolbarlayout的Expanded固定让我Google了好久,因为用英文搜索可能我表达的不太好,最后竟然是一句nestedScroll(false)就可以了。。。。 还是感谢Stackoveflow里边的大腿吧。

Dagger2

依赖注入Dagger2,也是我早就想用的一个框架了,理由是各种配合Mvp十分方便和好用,渐渐也能体会到一次注入到处可用的快感。不过一个新技术真的学习成本,国内没什么中文文档介绍,看国外的看的云里雾里。原理看的明白,用起来好像不太知道如何使用,尤其是在@inject之后对象,也可以在别的地方Inject,原本是被Inject方后来也成了Module提供方。虽然到最后原理还不是特别明白这里,但还是不阻碍用起来的快感。

Realm

一开始被新技术吸引到的是不会放过任何新东西的包括Realm,不过进了坑不代表这个坑可以跳阿。由于我这次用到了leacncloud,Realm感觉会和LeanCloud的子类化冲突让你只能选择其中之一,不过这个也算了,Leancloud提供了类似Map的Put方法也可以接受就是麻烦了点。但是被坑到的地方是Realm所谓的自动数据同步竟然是一改就是改真实的数据,并不是数据的拷贝。。。感觉和我使用到要缓存的数据有点冲突,因为这个Moment里边的项是有点赞的,点赞要修改当前Recycleview的数据(修改数据要开事务)。修改数据后会出现一些很奇怪的现象,不在Recycleview当前Item会跳到当前Item,点赞的动画也会消失。。。真的是想破脑袋也解决不了,就直接跳坑了。最后感觉这个Realm在保存不跟服务器需要同步的数据会好点。

LeanCloud

用LeanCloud是因为在知乎太多吹它的人了而且它的确在BAAS这方面功能比较多(后来才发现即时通信没有语音和视频),所以就尝试使用了,SDK整体来说是不错的都挺好用的,满足了我对存储方面的要求。不过就在我开发的这几天,貌似稳定性没有想象中那么好,好几次上传个头像都会SocketTimeOut,查询也会有点慢,不过还好都在接受范围内(不过要是到了收费的标准我就接受不了)。

环信

baby这个开源项目基于环信IM开发,刚开始选择IM的时候,看到知乎上黑环信的人挺多的,就亲自下载了几家IM的demo源码跑一遍,从功能、集成难易和消息稳定几个方面对比,最终还是选择了环信。集成这方面环信做的真不错,尤其是有了EaseUi这个包,基本上一天就能集成完毕。项目运行至今没有出现过什么问题,发送消息挺稳定的。

Rxjava、RxAndroid

Rxjava我从第一眼看到了就喜欢上了(个人特喜欢那种通过.设置完成的感觉),接触也有几个月,一开始就和Retrofit 、Okhttp一起使用。学习成本还是要有的阿,看了不知道多少篇关于Rxjava使用的文章和例子,对里边的操作符也仅仅停留在那几个最常用的,其他一大堆好多都没用过,看来还用得不够。

Glide

Glide也是一个后来居上让我喜欢的图片加载库,一开始我喜欢picasso 是觉得轻巧而且好用有保证(主要是我偶像Jake Wharton主导,有加成),慢慢觉得Picasso对内存没有Glide来的友好,Glide在加载速度方面也领先,虽然整个库代码量是Picasso的几倍,但是比起重要的内存和用户体验来说还是Glide的领先一筹。

Butterknife、Ucrop等等

当让还有其他的一些润色的轮子啦,不过不是那么重要就不一一感谢啦。

Thanks
  • 感谢Github、LeanCloud、环信、还有造那么多轮子给我们用的Square FaceBook Google的大大们。
  • Thanks for improving my code m-ezzat.


Contacts

 
Copyright 2016 Roger ou

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
收起阅读 »

【环信征文】神通广大的JavaScript

一切可以用 JavaScript 编写的程序,最终都会使用 JavaScript 编写
——Atwood 2007

就在前几天“JavaScript是世界上最好的语言”这句话火了,PHP的地位遭受了前所未有的挑战。JavaScript到底有何神通,能登上世界上最好的语言的宝座?

JavaScript是诞生于1995年的一种直译式脚本语言,原名Mocha。JavaScript是一种动态类型、弱类型、基于原型的语言,内置支持类型。JavaScript具备简单灵活和跨平台的优势,会成为解决大部分IT问题的优选方案。著名程序员 Jeff Atwood 在2007年发布了著名的 Atwood's Law: “Any application that can be written in JavaScript, will eventually be written in JavaScript. (一切可以用 JavaScript 编写的程序,最终都会使用 JavaScript 编写)”。就像世界上大多数人都是白种人一样,GitHub上用JavaScript写的代码也占据了大多数,JavaScript的开放性和简洁性功不可没。

网页前端
JavaScript最初是用来给HTML网页增加动态功能的。与JavaScript同时出现的JScript、ActionScript和ScriptEase等都几乎销声匿迹,但JavaScript仍然被广泛用于Web应用开发,也用来为网页添加各式各样的动态功能,为用户提供更流畅美观的浏览效果,甚至成为了前端开发的代名词,这就说明了JavaScript的强大之处。

为传统企业做一个展示网站通常耗时以周计,此时开发者只要找一个模板就够了。而开发时间以月计的互联网公司前端开发工作就不得不选择一个合适的框架了,以下是世界主流的JavaScript前端开发框架和类库:

出自Google的前端开发框架Angular.js自带MVC框架,通过新的属性和表达式扩展了 HTML,并且通过被称为指令(directives)的结构让浏览器能够识别新的语法,现在已经凭借数据双向绑定成为了使用人数最多的前端开发框架。

来自FaceBook的前端开发框架React.js的设计思想是用组件套组件的方式来绘制Web画面。现在大家开发前端的思路早已不是当年的 Web page,而是 Application——传统的HEML+CSS已经不适合这个时代了,组件化开发即将成为主流。

国内前端专家尤雨溪的前端开发框架Vue.js在GitHub的Star数量已经非常接近React.js,Vue.js能像织席贩履的刘备一样与出身名门的Angular.js和React.js鼎足而立的原因在于提供了更加简洁、更易于理解的API, 更加轻量级也更加容易上手。自带MVVM架构的Vue.js必将以开源世界中国人的骄傲载入史册。

体量并不能称为一个“框架”的jQuery是一个号称“Write Less,Do More”的JavaScript类库,封装了大多数常见、但写起来复杂的实用代码段,如优化HTML文档操作、事件处理和动画设计等。

服务端和大数据
JavaScript不仅适合前端开发,Node.js的出现使得JavaScript程序员进行后台开发成为可能。Node.js是一个基于 Chrome V8 引擎的 JavaScript 运行环境,其包管理器 npm是全球最大的开源库生态系统。无论公司自备机房还是使用阿里云、金山云等云服务,Node.js都是创业团队的最佳选择。但因为JavaScript是单线程语言,在处理高并发和大数据等问题上常常力不从心。

如果你是一个Android或iOS开发者,服务器仅仅是给自己业余项目或开源项目用的,那么Bmob云(没错,Bmob云端代码也是JavaScript)也能为你提供一个小而美、并且价格低廉的服务器。

网页游戏
网页游戏不都是粗制滥造的“一刀999级”或“屠龙宝刀,注册就送”等圈钱产品,用浏览器玩的游戏也能做到画面精美、特效绚丽。

Cocos2d-x-js是全世界最著名游戏框架Cocos2d-x专为HTML5游戏设计的JavaScript版本,采用原生JavaScript语言编写。随着Flash退出历史舞台,掌握Cocos2d-x-js技术的程序员就是新一代的闪客。

2014年2月创立于北京的Egret是一套完整的HTML5游戏开发解决方案,其核心产品白鹭引擎(Egret Engine)凭借上手简便、性能强大已占据国内超七成的手机页游引擎市场份额。Egret布道师徐聪(笔名:臭臭打不死人)不但能用自己精益求精的技术和助人为乐的精神帮助开发者解决使用Erget时遇到的技术问题,还经常向有探索精神、帮助其他开发者了解Erget的开发者赠送礼物。

移动端
最著名的HTML5移动开发框架当属Facebook发布于2015年的React Native(顾名思义,是上文提到的React.js的一个分支),这是一套跨平台、动态更新的 Javascript 框架,口号是“Learn once, write anywhere”。与之类似有同属舶来的PhoneGap等。

国产的HTML5开发框架在国内也百家争鸣,常见的有HBuilder和AppCan,二者共同特点是都为了便于新手入门制作了专用的编译器。2016年,在Qcon大会上宣布开源的Weex也异军突起,来自阿里的它因为开发的软件与原生App别无二致受到很多人的青睐。

掌握JavaScript的程序员在国内还有一个新出路,就是微信开发。在国内有7亿用户的微信向广大JavaScript程序员提供了无数公众号和小程序开发的就业岗位,并且现在的移动互联网创业公司或者想涉足移动互联网的传统企业都可以先用微信公众号和小程序试水而不必一开始就开发成本高昂、进度缓慢的原生App

VR
2016年被誉为“中国VR元年”,其实VR并不神秘,只要掌握了眼球追踪和立体视觉,一切3D引擎都可以摇身一变成为VR引擎。而JavaScript恰好编写过几款著名的2D引擎

Three.js是3D绘图协议webGL的一款框架,也是增长最迅速的和讨论最热烈的3D游戏引擎;React VR是FaceBook今年推出的基于JavaScript框架的虚拟现实创建工具……这些五光十色的框架大大降低了JavaScript程序员涉足VR的门槛。

Egret Engine3D游戏引擎是国产的3D游戏引擎,不但网页兼容性更好,更支持手机浏览器,加载也更快,还配套了3D骨骼等配套工具,更具备支持将VR游戏发布到微信公众号及小程序的中国软件的种族优势。

尽管目前VR领域仍然是Unity-3d的时代,VR程序员都是写C#的,但JavaScript征服VR世界只是一个时间问题。

AI
AlphaGo击败柯洁的新闻在科技界引发了轩然大波,AI一夜之间登上了各大送索引擎的搜索榜首。

理论上一切图灵完备的语言都能成为AI开发语言,而JavaScript正是图灵完备的。无数JavaScript程序员致力于JavaScript在自然语言处理和手写识别等领域的研究,目前国外已经出现用JavaScript编写的人脸识别工具Landmarker.io

尽管目前业界主流观点还是“AI入门用Python,AI追求性能用C++,AI工业化用Java”,但我们仍然可以坚信克服了AI专业库缺失和无法精确控制内问题的JavaScript终将在AI领域占据一席之地。

loT
loT比一般的软件系统多了一个硬件层,这就决定了loT的架构的复杂程度,常常需要多种语言的配合才行:
1、用Arduino给硬件编写一个控制器
2、用使用C语言编写的Raspberry Pi连接网络,并传输控制信号给硬件
3、用“钩子语言”Python连接以上两条
4、用Java语言编写一个Android应用,用手机作为遥控器
……
万幸这个需要掌握多种语言才能进行loT工作的时代即将成为过去式。三星设计了用JavaScript编写的物联网引擎loT.js,它的运行内存小于64kb,而且全部代码能够存储在不足200KB的ROM上,如此轻量的体积在智能家居等硬件设备上有明显的优势。由此可见,物联网也将成为JavaScript工程师的新蓝海。
继续阅读 »
一切可以用 JavaScript 编写的程序,最终都会使用 JavaScript 编写
——Atwood 2007

就在前几天“JavaScript是世界上最好的语言”这句话火了,PHP的地位遭受了前所未有的挑战。JavaScript到底有何神通,能登上世界上最好的语言的宝座?

JavaScript是诞生于1995年的一种直译式脚本语言,原名Mocha。JavaScript是一种动态类型、弱类型、基于原型的语言,内置支持类型。JavaScript具备简单灵活和跨平台的优势,会成为解决大部分IT问题的优选方案。著名程序员 Jeff Atwood 在2007年发布了著名的 Atwood's Law: “Any application that can be written in JavaScript, will eventually be written in JavaScript. (一切可以用 JavaScript 编写的程序,最终都会使用 JavaScript 编写)”。就像世界上大多数人都是白种人一样,GitHub上用JavaScript写的代码也占据了大多数,JavaScript的开放性和简洁性功不可没。

网页前端
JavaScript最初是用来给HTML网页增加动态功能的。与JavaScript同时出现的JScript、ActionScript和ScriptEase等都几乎销声匿迹,但JavaScript仍然被广泛用于Web应用开发,也用来为网页添加各式各样的动态功能,为用户提供更流畅美观的浏览效果,甚至成为了前端开发的代名词,这就说明了JavaScript的强大之处。

为传统企业做一个展示网站通常耗时以周计,此时开发者只要找一个模板就够了。而开发时间以月计的互联网公司前端开发工作就不得不选择一个合适的框架了,以下是世界主流的JavaScript前端开发框架和类库:

出自Google的前端开发框架Angular.js自带MVC框架,通过新的属性和表达式扩展了 HTML,并且通过被称为指令(directives)的结构让浏览器能够识别新的语法,现在已经凭借数据双向绑定成为了使用人数最多的前端开发框架。

来自FaceBook的前端开发框架React.js的设计思想是用组件套组件的方式来绘制Web画面。现在大家开发前端的思路早已不是当年的 Web page,而是 Application——传统的HEML+CSS已经不适合这个时代了,组件化开发即将成为主流。

国内前端专家尤雨溪的前端开发框架Vue.js在GitHub的Star数量已经非常接近React.js,Vue.js能像织席贩履的刘备一样与出身名门的Angular.js和React.js鼎足而立的原因在于提供了更加简洁、更易于理解的API, 更加轻量级也更加容易上手。自带MVVM架构的Vue.js必将以开源世界中国人的骄傲载入史册。

体量并不能称为一个“框架”的jQuery是一个号称“Write Less,Do More”的JavaScript类库,封装了大多数常见、但写起来复杂的实用代码段,如优化HTML文档操作、事件处理和动画设计等。

服务端和大数据
JavaScript不仅适合前端开发,Node.js的出现使得JavaScript程序员进行后台开发成为可能。Node.js是一个基于 Chrome V8 引擎的 JavaScript 运行环境,其包管理器 npm是全球最大的开源库生态系统。无论公司自备机房还是使用阿里云、金山云等云服务,Node.js都是创业团队的最佳选择。但因为JavaScript是单线程语言,在处理高并发和大数据等问题上常常力不从心。

如果你是一个Android或iOS开发者,服务器仅仅是给自己业余项目或开源项目用的,那么Bmob云(没错,Bmob云端代码也是JavaScript)也能为你提供一个小而美、并且价格低廉的服务器。

网页游戏
网页游戏不都是粗制滥造的“一刀999级”或“屠龙宝刀,注册就送”等圈钱产品,用浏览器玩的游戏也能做到画面精美、特效绚丽。

Cocos2d-x-js是全世界最著名游戏框架Cocos2d-x专为HTML5游戏设计的JavaScript版本,采用原生JavaScript语言编写。随着Flash退出历史舞台,掌握Cocos2d-x-js技术的程序员就是新一代的闪客。

2014年2月创立于北京的Egret是一套完整的HTML5游戏开发解决方案,其核心产品白鹭引擎(Egret Engine)凭借上手简便、性能强大已占据国内超七成的手机页游引擎市场份额。Egret布道师徐聪(笔名:臭臭打不死人)不但能用自己精益求精的技术和助人为乐的精神帮助开发者解决使用Erget时遇到的技术问题,还经常向有探索精神、帮助其他开发者了解Erget的开发者赠送礼物。

移动端
最著名的HTML5移动开发框架当属Facebook发布于2015年的React Native(顾名思义,是上文提到的React.js的一个分支),这是一套跨平台、动态更新的 Javascript 框架,口号是“Learn once, write anywhere”。与之类似有同属舶来的PhoneGap等。

国产的HTML5开发框架在国内也百家争鸣,常见的有HBuilder和AppCan,二者共同特点是都为了便于新手入门制作了专用的编译器。2016年,在Qcon大会上宣布开源的Weex也异军突起,来自阿里的它因为开发的软件与原生App别无二致受到很多人的青睐。

掌握JavaScript的程序员在国内还有一个新出路,就是微信开发。在国内有7亿用户的微信向广大JavaScript程序员提供了无数公众号和小程序开发的就业岗位,并且现在的移动互联网创业公司或者想涉足移动互联网的传统企业都可以先用微信公众号和小程序试水而不必一开始就开发成本高昂、进度缓慢的原生App

VR
2016年被誉为“中国VR元年”,其实VR并不神秘,只要掌握了眼球追踪和立体视觉,一切3D引擎都可以摇身一变成为VR引擎。而JavaScript恰好编写过几款著名的2D引擎

Three.js是3D绘图协议webGL的一款框架,也是增长最迅速的和讨论最热烈的3D游戏引擎;React VR是FaceBook今年推出的基于JavaScript框架的虚拟现实创建工具……这些五光十色的框架大大降低了JavaScript程序员涉足VR的门槛。

Egret Engine3D游戏引擎是国产的3D游戏引擎,不但网页兼容性更好,更支持手机浏览器,加载也更快,还配套了3D骨骼等配套工具,更具备支持将VR游戏发布到微信公众号及小程序的中国软件的种族优势。

尽管目前VR领域仍然是Unity-3d的时代,VR程序员都是写C#的,但JavaScript征服VR世界只是一个时间问题。

AI
AlphaGo击败柯洁的新闻在科技界引发了轩然大波,AI一夜之间登上了各大送索引擎的搜索榜首。

理论上一切图灵完备的语言都能成为AI开发语言,而JavaScript正是图灵完备的。无数JavaScript程序员致力于JavaScript在自然语言处理和手写识别等领域的研究,目前国外已经出现用JavaScript编写的人脸识别工具Landmarker.io

尽管目前业界主流观点还是“AI入门用Python,AI追求性能用C++,AI工业化用Java”,但我们仍然可以坚信克服了AI专业库缺失和无法精确控制内问题的JavaScript终将在AI领域占据一席之地。

loT
loT比一般的软件系统多了一个硬件层,这就决定了loT的架构的复杂程度,常常需要多种语言的配合才行:
1、用Arduino给硬件编写一个控制器
2、用使用C语言编写的Raspberry Pi连接网络,并传输控制信号给硬件
3、用“钩子语言”Python连接以上两条
4、用Java语言编写一个Android应用,用手机作为遥控器
……
万幸这个需要掌握多种语言才能进行loT工作的时代即将成为过去式。三星设计了用JavaScript编写的物联网引擎loT.js,它的运行内存小于64kb,而且全部代码能够存储在不足200KB的ROM上,如此轻量的体积在智能家居等硬件设备上有明显的优势。由此可见,物联网也将成为JavaScript工程师的新蓝海。 收起阅读 »

精通环信开发已成程序员招聘刚需?看别人家的招聘要求

今天在一个2000人技术交流群里看到一家互联网公司招聘Android/ios开发

TIM截图20170825163121.png


timg.jpg


一段不到200字的招聘要求,竟然出现了两次“环信”。眉头一紧,感觉这事不简单了!

TIM图片20170825160503.jpg


去年在环信社区看到《今天面试一个自称两年经验的Android》《我又做了一次面试官》两篇面试经历还不以为然,没想到一年内作者预言成真,精通环信开发等第三方API开发已然成为程序员招聘刚需!

作为一个与时俱进的好司机赶紧打开X度搜索“如何精通环信开发”,还真让我找到了环信Alpha全国开发者培训计划
TIM截图20170825160913.png
环信alpha计划将对所有报名的ISV厂商和开发者提供技术、审核认证及发行等方面的支持。环信“Alpha计划”旨在为ISV和开发者们提供更加全面且专业的支持,帮助其在包括企业IM、协同OA、APP内社交、直播互动、IOT、智能硬件等领域挖掘产生更多落地有商业前景的优质项目,一起建设整个即时通讯云服务生态。

文末有小伙伴愿意去这家福建公司的发送简历到duc@easemob.com邮箱,暗号“我精通环信开发”,我们等的就是你!
继续阅读 »
今天在一个2000人技术交流群里看到一家互联网公司招聘Android/ios开发

TIM截图20170825163121.png


timg.jpg


一段不到200字的招聘要求,竟然出现了两次“环信”。眉头一紧,感觉这事不简单了!

TIM图片20170825160503.jpg


去年在环信社区看到《今天面试一个自称两年经验的Android》《我又做了一次面试官》两篇面试经历还不以为然,没想到一年内作者预言成真,精通环信开发等第三方API开发已然成为程序员招聘刚需!

作为一个与时俱进的好司机赶紧打开X度搜索“如何精通环信开发”,还真让我找到了环信Alpha全国开发者培训计划
TIM截图20170825160913.png
环信alpha计划将对所有报名的ISV厂商和开发者提供技术、审核认证及发行等方面的支持。环信“Alpha计划”旨在为ISV和开发者们提供更加全面且专业的支持,帮助其在包括企业IM、协同OA、APP内社交、直播互动、IOT、智能硬件等领域挖掘产生更多落地有商业前景的优质项目,一起建设整个即时通讯云服务生态。

文末有小伙伴愿意去这家福建公司的发送简历到duc@easemob.com邮箱,暗号“我精通环信开发”,我们等的就是你! 收起阅读 »

该用哪种技术或框架来开发

学海无涯

最近,常常被人问到你团队有用甚幺新技术或是框架去开发?或是,我们因该要用什幺新技术和选哪一个框架去开发,这系统比较好?用AngualrJS好像不错。现在很热门,采用SPA开发网页好像可以节省带宽,使得整体反应相当快速…等。突然觉得在这技术爆炸年代,让开发变得很不单纯,又当微软宣布.NET走向开源之后,不管在前端(前端Framework更是雨后春笋般出现)或后端的技术开发,或是新的框架的诞生,真是多到不知道该怎样去选择才好,

有些时候,感觉不去”使用”这些新的语言或是新的开发方式去开发系统,就好像是落伍或是跟不上时代,又或是外界媒体不段在洗脑或是传达某些技术,感觉使用这个才是王道。(注意,这边我是用”使用”一词。因为,学习跟使用 这两者是不同),确实,当时代不断改变,人是必须不断去学习各种程序和新技术所带来的冲击,至少当你是走在信息这个产业时,必须要有的领悟。回到该用那种技术或框架开发系统这一个问题,我个人觉得如果你本身不是公司老板或是在公司的政策强迫下,在使用新技术去开发可以从下面三个层面去思考,

解决问题

这一层面主要是从商业或是业务需求面去看。我认为不管那一种的新技术或是新框架的诞生,都是为了解决当时的一些需求或是某开发上的问题所衍生出来的。因此,当我们去开发一套系统时候,不该一昧认为最新的技术就是最好用的,而是,必须先做事前的分析,了解目前的业务需求举例来说,如果你的系统,未来只会去服务十个用户,而它的目的只是让用户加速他日常工作或是简化一些流程(别笑,很多in House系统就是这样),单纯用自己拿手的WebForm开发就可以解决用户问题?是否有必要采用SPA方式去开发?又或是,当大家都在谈论开发要搭配AngularJS,但,整体需求面看不到,导入AngularJS会解决业务或是架构问题时,是否单纯搭配Javascrip或Jquery就可以呢?不过,如果今天你的系统必须要高性能高可扩充性且需要降低网页传输量,那请使用SPA,甚至ReactJS去开发,或是,一些可以解决这方面的技术,即使困难度很高,还是有其导入必要性。一切都必须从需求和解决问题去思考该用哪一种技术。

开发ROI

这一层面主要是从系统开发过程的投资报酬率去看开发系统的ROI评估,这一点很重要,一套不熟悉的框架或是技术的导入,对一般人来说都是一个高成本的投入,像是在新创团队中,能快速将自己的发想或是解决问题的方法变成产品,并赶紧丢到市场验证,验证回来后再持续快速修正,这才是最有效益的,投入一个你都不熟悉的技术或是框架,等你摸完再开发出来,此时,你的投资回报率已经不见了,因为,你的可能主意已经被别人捷足先登了。而在一般企业中,MIS往往都被时程压着打,甚至,从分析到开发测试,往往只有一两个月就要完成,且通常还会被用系统产出率决定MIS的绩效,与其导入一个比完成需求还复杂的技术或是框架时,还不如采用合宜的目前需求的框架去开发,那样怎样才知道要用那些技术或是框架才合宜呢?这就是开发人员还是要持续的原因有时候学习的广会比学习的深还有帮助

维护成本

这一层面则是从团队文化去看对于开发In House系统来说这是很重要的考量,且往往又是很不好拿捏,就拿内部系统开发来说好了,内部系统大都是像是肝一样,辛苦但往往会被忽视。而且,内部系统不是说时间到就可以升级版本,或是,旧版本就不去维护。也因此,久而久之,可以发现MIS要了解的语言从 VB6到.NET 5都有,还不包括一些林林种种的分支技术。再者,加上公司人员来来去去,系统的Owner不断改变,需求不断增加(新需求往往会被建筑在多年前的系统上)维护成本就越来越高了。从维护成本思考下,就必须了解整个团队对于该技术与框架的熟悉度。若只是,团队中只有一两个人对此框架熟悉,大部分都不熟悉时候,就要强行导入,后续可能就会垫加系统的维护成本了,毕竟,当系统上线有异常时候,团队有办法去维护吗?可被允许的down time是多少?又或是当商业需求改变,要立即增加或是修改系统功能时,所要付出的成本是多少。从以上角度思考,是否要此刻运用此技术或是框架到团队中就是需要评估的,又或是该逐步提升团队技能或是熟悉度再做考量呢?

 

技术 这东西有如两面刃,它可以带来很大效益,同时,也会伴随许多风险,唯有不断学习和改善才可以去降低使用风险,而无论是架构设计或是技术框架的导入,还是必须依附在商业与业务需求,过多或是不及架构或是一昧听从潮流而去使用的技术,对于产品和系统的帮助都不大。

从团队角度来看,若是成员技术差异很大时候,与其采用一些新技术,还不如先提升成员的技术力,让大家彼此的能力差距缩小,纵使使用一些旧有技术又何妨呢?现在已经是不缺选择使用框架与技术的世代,而是要怎样选择的才是有助于整体开发的思维了。

以上只是个人长期所处产业的开发经验与看法之分享
 
转载自:该用哪种技术或框架来开发 | Teambition知识文档
继续阅读 »
学海无涯

最近,常常被人问到你团队有用甚幺新技术或是框架去开发?或是,我们因该要用什幺新技术和选哪一个框架去开发,这系统比较好?用AngualrJS好像不错。现在很热门,采用SPA开发网页好像可以节省带宽,使得整体反应相当快速…等。突然觉得在这技术爆炸年代,让开发变得很不单纯,又当微软宣布.NET走向开源之后,不管在前端(前端Framework更是雨后春笋般出现)或后端的技术开发,或是新的框架的诞生,真是多到不知道该怎样去选择才好,

有些时候,感觉不去”使用”这些新的语言或是新的开发方式去开发系统,就好像是落伍或是跟不上时代,又或是外界媒体不段在洗脑或是传达某些技术,感觉使用这个才是王道。(注意,这边我是用”使用”一词。因为,学习跟使用 这两者是不同),确实,当时代不断改变,人是必须不断去学习各种程序和新技术所带来的冲击,至少当你是走在信息这个产业时,必须要有的领悟。回到该用那种技术或框架开发系统这一个问题,我个人觉得如果你本身不是公司老板或是在公司的政策强迫下,在使用新技术去开发可以从下面三个层面去思考,

解决问题

这一层面主要是从商业或是业务需求面去看。我认为不管那一种的新技术或是新框架的诞生,都是为了解决当时的一些需求或是某开发上的问题所衍生出来的。因此,当我们去开发一套系统时候,不该一昧认为最新的技术就是最好用的,而是,必须先做事前的分析,了解目前的业务需求举例来说,如果你的系统,未来只会去服务十个用户,而它的目的只是让用户加速他日常工作或是简化一些流程(别笑,很多in House系统就是这样),单纯用自己拿手的WebForm开发就可以解决用户问题?是否有必要采用SPA方式去开发?又或是,当大家都在谈论开发要搭配AngularJS,但,整体需求面看不到,导入AngularJS会解决业务或是架构问题时,是否单纯搭配Javascrip或Jquery就可以呢?不过,如果今天你的系统必须要高性能高可扩充性且需要降低网页传输量,那请使用SPA,甚至ReactJS去开发,或是,一些可以解决这方面的技术,即使困难度很高,还是有其导入必要性。一切都必须从需求和解决问题去思考该用哪一种技术。

开发ROI

这一层面主要是从系统开发过程的投资报酬率去看开发系统的ROI评估,这一点很重要,一套不熟悉的框架或是技术的导入,对一般人来说都是一个高成本的投入,像是在新创团队中,能快速将自己的发想或是解决问题的方法变成产品,并赶紧丢到市场验证,验证回来后再持续快速修正,这才是最有效益的,投入一个你都不熟悉的技术或是框架,等你摸完再开发出来,此时,你的投资回报率已经不见了,因为,你的可能主意已经被别人捷足先登了。而在一般企业中,MIS往往都被时程压着打,甚至,从分析到开发测试,往往只有一两个月就要完成,且通常还会被用系统产出率决定MIS的绩效,与其导入一个比完成需求还复杂的技术或是框架时,还不如采用合宜的目前需求的框架去开发,那样怎样才知道要用那些技术或是框架才合宜呢?这就是开发人员还是要持续的原因有时候学习的广会比学习的深还有帮助

维护成本

这一层面则是从团队文化去看对于开发In House系统来说这是很重要的考量,且往往又是很不好拿捏,就拿内部系统开发来说好了,内部系统大都是像是肝一样,辛苦但往往会被忽视。而且,内部系统不是说时间到就可以升级版本,或是,旧版本就不去维护。也因此,久而久之,可以发现MIS要了解的语言从 VB6到.NET 5都有,还不包括一些林林种种的分支技术。再者,加上公司人员来来去去,系统的Owner不断改变,需求不断增加(新需求往往会被建筑在多年前的系统上)维护成本就越来越高了。从维护成本思考下,就必须了解整个团队对于该技术与框架的熟悉度。若只是,团队中只有一两个人对此框架熟悉,大部分都不熟悉时候,就要强行导入,后续可能就会垫加系统的维护成本了,毕竟,当系统上线有异常时候,团队有办法去维护吗?可被允许的down time是多少?又或是当商业需求改变,要立即增加或是修改系统功能时,所要付出的成本是多少。从以上角度思考,是否要此刻运用此技术或是框架到团队中就是需要评估的,又或是该逐步提升团队技能或是熟悉度再做考量呢?

 

技术 这东西有如两面刃,它可以带来很大效益,同时,也会伴随许多风险,唯有不断学习和改善才可以去降低使用风险,而无论是架构设计或是技术框架的导入,还是必须依附在商业与业务需求,过多或是不及架构或是一昧听从潮流而去使用的技术,对于产品和系统的帮助都不大。

从团队角度来看,若是成员技术差异很大时候,与其采用一些新技术,还不如先提升成员的技术力,让大家彼此的能力差距缩小,纵使使用一些旧有技术又何妨呢?现在已经是不缺选择使用框架与技术的世代,而是要怎样选择的才是有助于整体开发的思维了。

以上只是个人长期所处产业的开发经验与看法之分享
 
转载自:该用哪种技术或框架来开发 | Teambition知识文档 收起阅读 »

【环信征文】程序员如何成为别人的男朋友

这个世界上程序员数量很多,有女朋友的程序员在其中的比例却很少。究其原因,不外乎大多数程序员根本不知道怎么才能成为别人的男朋友。成为别人的男朋友对于富二代和拆迁户很容易,而对于程序员却很难,“潘驴邓小闲”五要素缺一不可。


第一要素“潘”指的是貌若潘安。

程序员素以不修边幅出名,着装仪表各种混搭:发际线像清穿剧里的阿哥,黑眼圈像动物园里的熊猫,上半身的格子衫、冲锋衣像送外卖的骑手,下半身的大裤衩、人字拖像索马里的海盗……这是典型的注孤生打扮。

为了改变妹子们对广大程序员朋友们的刻板印象,我制定了一份程序员外观改造计划,实施之后你也会变得像《微微一笑很倾城》里的肖奈一样帅:

(1)桌子上摆一盆多汁的多肉植物,比如芦荟。电脑显示器辐射都脸部皮肤危害巨大,多肉植物能吸收大量辐射,而且当程序员感觉脸部皮肤干涩的时候可以随手掰掉一块,拿天然的芦荟胶抹自己一脸。

(2)抽屉里常备一把木梳。脑力劳动会造成头部温度过高;并且头部血液供应大脑,导致头皮供血不足;这些都是让程序员聪明绝顶的罪魁祸首。如果在等待编译或者sync的时候用木梳按摩自己的头皮,会刺激毛囊上皮细胞,抑制毛囊进入休止期,让程序员的头发一如既往的茂盛。

(3)买一些时尚的衣服。俗话说“人靠衣装”,衣服的时尚或邋遢会对一个人的外观造成决定性的影响,因此没事常去商城转转,搭配几件经典复古风或者街头休闲风的衣服,能把颜值和魅力提高不止一个档次。

(4)清空收藏夹里没有备注的链接,删除硬盘里的隐藏文件。国家一级演员吴刚表情光明磊落的时候是耿直纯真的市委书记李达康,面目笑里藏刀的时候是阴险狡诈的军统特务陆桥山——气质是一个人外表的重要组成部分,少看点不文明的视频,脸色就不那么枯槁了;少想点不健康的故事,眼神也就不那么猥琐了。


第二要素“驴”指的是身体像驴一样健壮。

程序员是典型的脑力工作者,在充满电脑辐射的室内环境中久坐不动会导致严重的大脑发达、四肢简单的亚健康症状。程序员加班猝死已经不再是新闻,“但愿有头生白发,何忧无地觅黄金”,我们不能为了忙于工作牺牲健康。对于危害程序员健康的几大职业病,我们应该对症下药:

(1)肾结石、前列腺炎。下半身的疾病基本都是久坐不动导致的,最简单的办法就是站立式编程,最好桌子下面放一个跑步机;没有条件的程序员可以在工作时多喝水,这样有助于增加起身上厕所的次数。

(2)肩周炎、颈椎病。程序员的职业生涯读的最后一本书常常是《颈椎病康复指南》,因为屏幕不一定正对着人脸,所以程序员不得不弯腰驼背。如果不能定制桌子,那么可以坐能调节高度的人体工程学座椅,让你只有在保持正确坐姿的情况下才能正对屏幕。没有条件的程序员可以拿几本旧字典把显示器垫高。

(3)失眠、肥胖、骨质疏松。脑力劳动者的运动量普遍偏少,为了避免失眠、肥胖、骨质疏松,程序员可以在夜间做瑜伽、体操、太极拳之类的有氧运动。下班早的话可以跑跑步打打球,但加班到深夜就千万不要做任何剧烈运动,容易猝死。


第三要素“邓”指的是像邓通一样有钱。

程序员账面收入很高,但增量优势在绝对的存量都是浮云。我曾经卧底某一线城市Android千人群,1000人中没一个是有房子的本地人。为了使自己在资产上的劣势不太明显,增加8小时外的收入至关重要。

(1)程序员赚外快最直接的方式就是做一个接单的威客。但需要注意的是,写出客户满意的软件很容易,但找到收到满意的软件之后和你说自己很满意并且乐意付费的客户很难。

(2)录制教学视频。利用自己编程的经验录制教学视频,放在网站上供人付费下载,这种方式就像一本万利的培训机构一样,赚那些觉得程序员是一个“整天坐在办公室玩电脑就有工资的工作”的人的钱。

(3)译书或著书。如果你属于同时精通编程和外语,或者博客阅读量和粉丝数巨大的IT红人,那么版税就是你最重要的被动收入。

(4)前三样都很耗时,如果你想通过一种短平快的方式赚取外快,可以向imGeek投稿。只要你写一篇关键词为“环信”、“移动开发”、“人工智能”等相关的文章,就有可能获得50~500元现金奖励。



第四要素“小”指的是脾气小,并对女性体贴入微。

程序员常常遇到客户催逼进度或者产品经理乱改需求的情况,一来二去就变得急躁易怒。再加上程序员与电脑打交道比与人打交道多,因此也不容易对女性体贴入微。

根治程序员常发脾气的毛病不用医生开药方,用机械键盘即可痊愈,越沉重、价格越昂贵的机械键盘疗效越好,HHKB最佳,国产的狼蛛鬼王亦可。

软件工程专业学生Nerd因为大学前三年贪玩LOL不好好学习,基础松松垮垮,概念一知半解,导致大四做毕业设计时常常感觉力不从心,于是常常借口“释放压力”更加沉迷LOL。Nerd搞毕业设计遇到瓶颈的时候,其实谁都知道大多数是玩LOL被猪队友坑了的时候就发脾气,拿键盘砸桌子,在外实习的室友每周回宿舍都能看到一屋子键盘的碎片。好在校园里电子产品商店的东西便宜,键盘20块钱就能买。有一天Nerd过生日,室友送给Nerd一副电竞专用的狼蛛鬼王键鼠套装。Nerd又一次听到“defeat”的声音的时候,条件反射一般抡起了键盘,只不过在砸向桌子的一瞬间住手了——他首先想到的是这个键盘砸坏了之后20块钱买不来新的,然后又想到了1kg的钢板砸下去桌子也碎了。

Nerd脾气变小了以后,身边很快就围过来一群妹子,他终于顺利脱单。


第五要素“闲”指的是有大把的休闲时间。

程序员工资虽高,可这都是默认包含加班费的,因此休闲时间常常不能得到保障。但陪妹子的时间就像北漂地下室蚁族程序员的牙膏一样,挤不出来拿擀面杖也能擀出来。

在8小时之内要合理利用设计模式。每天拿出一小时学习设计模式,第二天可以节省一小时复制粘贴高耦合度代码的时间。但需要注意很多设计模式都是牺牲运行效率换开发速度,因此并非所有设计模式都适合对性能要求高或者硬件质量严苛的软件。

在8小时之外要减少无用社交。积极回答IT新人的问题是一个好习惯,谁知道隔着屏幕的那个人是不是3年前的自己。不过百度前两页就有答案的问题就不要回答了,不要把时间浪费在不值得帮助的人身上。
 
继续阅读 »
这个世界上程序员数量很多,有女朋友的程序员在其中的比例却很少。究其原因,不外乎大多数程序员根本不知道怎么才能成为别人的男朋友。成为别人的男朋友对于富二代和拆迁户很容易,而对于程序员却很难,“潘驴邓小闲”五要素缺一不可。


第一要素“潘”指的是貌若潘安。

程序员素以不修边幅出名,着装仪表各种混搭:发际线像清穿剧里的阿哥,黑眼圈像动物园里的熊猫,上半身的格子衫、冲锋衣像送外卖的骑手,下半身的大裤衩、人字拖像索马里的海盗……这是典型的注孤生打扮。

为了改变妹子们对广大程序员朋友们的刻板印象,我制定了一份程序员外观改造计划,实施之后你也会变得像《微微一笑很倾城》里的肖奈一样帅:

(1)桌子上摆一盆多汁的多肉植物,比如芦荟。电脑显示器辐射都脸部皮肤危害巨大,多肉植物能吸收大量辐射,而且当程序员感觉脸部皮肤干涩的时候可以随手掰掉一块,拿天然的芦荟胶抹自己一脸。

(2)抽屉里常备一把木梳。脑力劳动会造成头部温度过高;并且头部血液供应大脑,导致头皮供血不足;这些都是让程序员聪明绝顶的罪魁祸首。如果在等待编译或者sync的时候用木梳按摩自己的头皮,会刺激毛囊上皮细胞,抑制毛囊进入休止期,让程序员的头发一如既往的茂盛。

(3)买一些时尚的衣服。俗话说“人靠衣装”,衣服的时尚或邋遢会对一个人的外观造成决定性的影响,因此没事常去商城转转,搭配几件经典复古风或者街头休闲风的衣服,能把颜值和魅力提高不止一个档次。

(4)清空收藏夹里没有备注的链接,删除硬盘里的隐藏文件。国家一级演员吴刚表情光明磊落的时候是耿直纯真的市委书记李达康,面目笑里藏刀的时候是阴险狡诈的军统特务陆桥山——气质是一个人外表的重要组成部分,少看点不文明的视频,脸色就不那么枯槁了;少想点不健康的故事,眼神也就不那么猥琐了。


第二要素“驴”指的是身体像驴一样健壮。

程序员是典型的脑力工作者,在充满电脑辐射的室内环境中久坐不动会导致严重的大脑发达、四肢简单的亚健康症状。程序员加班猝死已经不再是新闻,“但愿有头生白发,何忧无地觅黄金”,我们不能为了忙于工作牺牲健康。对于危害程序员健康的几大职业病,我们应该对症下药:

(1)肾结石、前列腺炎。下半身的疾病基本都是久坐不动导致的,最简单的办法就是站立式编程,最好桌子下面放一个跑步机;没有条件的程序员可以在工作时多喝水,这样有助于增加起身上厕所的次数。

(2)肩周炎、颈椎病。程序员的职业生涯读的最后一本书常常是《颈椎病康复指南》,因为屏幕不一定正对着人脸,所以程序员不得不弯腰驼背。如果不能定制桌子,那么可以坐能调节高度的人体工程学座椅,让你只有在保持正确坐姿的情况下才能正对屏幕。没有条件的程序员可以拿几本旧字典把显示器垫高。

(3)失眠、肥胖、骨质疏松。脑力劳动者的运动量普遍偏少,为了避免失眠、肥胖、骨质疏松,程序员可以在夜间做瑜伽、体操、太极拳之类的有氧运动。下班早的话可以跑跑步打打球,但加班到深夜就千万不要做任何剧烈运动,容易猝死。


第三要素“邓”指的是像邓通一样有钱。

程序员账面收入很高,但增量优势在绝对的存量都是浮云。我曾经卧底某一线城市Android千人群,1000人中没一个是有房子的本地人。为了使自己在资产上的劣势不太明显,增加8小时外的收入至关重要。

(1)程序员赚外快最直接的方式就是做一个接单的威客。但需要注意的是,写出客户满意的软件很容易,但找到收到满意的软件之后和你说自己很满意并且乐意付费的客户很难。

(2)录制教学视频。利用自己编程的经验录制教学视频,放在网站上供人付费下载,这种方式就像一本万利的培训机构一样,赚那些觉得程序员是一个“整天坐在办公室玩电脑就有工资的工作”的人的钱。

(3)译书或著书。如果你属于同时精通编程和外语,或者博客阅读量和粉丝数巨大的IT红人,那么版税就是你最重要的被动收入。

(4)前三样都很耗时,如果你想通过一种短平快的方式赚取外快,可以向imGeek投稿。只要你写一篇关键词为“环信”、“移动开发”、“人工智能”等相关的文章,就有可能获得50~500元现金奖励。



第四要素“小”指的是脾气小,并对女性体贴入微。

程序员常常遇到客户催逼进度或者产品经理乱改需求的情况,一来二去就变得急躁易怒。再加上程序员与电脑打交道比与人打交道多,因此也不容易对女性体贴入微。

根治程序员常发脾气的毛病不用医生开药方,用机械键盘即可痊愈,越沉重、价格越昂贵的机械键盘疗效越好,HHKB最佳,国产的狼蛛鬼王亦可。

软件工程专业学生Nerd因为大学前三年贪玩LOL不好好学习,基础松松垮垮,概念一知半解,导致大四做毕业设计时常常感觉力不从心,于是常常借口“释放压力”更加沉迷LOL。Nerd搞毕业设计遇到瓶颈的时候,其实谁都知道大多数是玩LOL被猪队友坑了的时候就发脾气,拿键盘砸桌子,在外实习的室友每周回宿舍都能看到一屋子键盘的碎片。好在校园里电子产品商店的东西便宜,键盘20块钱就能买。有一天Nerd过生日,室友送给Nerd一副电竞专用的狼蛛鬼王键鼠套装。Nerd又一次听到“defeat”的声音的时候,条件反射一般抡起了键盘,只不过在砸向桌子的一瞬间住手了——他首先想到的是这个键盘砸坏了之后20块钱买不来新的,然后又想到了1kg的钢板砸下去桌子也碎了。

Nerd脾气变小了以后,身边很快就围过来一群妹子,他终于顺利脱单。


第五要素“闲”指的是有大把的休闲时间。

程序员工资虽高,可这都是默认包含加班费的,因此休闲时间常常不能得到保障。但陪妹子的时间就像北漂地下室蚁族程序员的牙膏一样,挤不出来拿擀面杖也能擀出来。

在8小时之内要合理利用设计模式。每天拿出一小时学习设计模式,第二天可以节省一小时复制粘贴高耦合度代码的时间。但需要注意很多设计模式都是牺牲运行效率换开发速度,因此并非所有设计模式都适合对性能要求高或者硬件质量严苛的软件。

在8小时之外要减少无用社交。积极回答IT新人的问题是一个好习惯,谁知道隔着屏幕的那个人是不是3年前的自己。不过百度前两页就有答案的问题就不要回答了,不要把时间浪费在不值得帮助的人身上。
  收起阅读 »

基于办公的 IM 的基础设计

IM OA
   现在的 IM 在设计上是基于会话的,多个人可以组成一个会话,相当于一个聊天室,当一个人加入到一个会话后,就可以看到从加入开始之后这个聊天室里所有参与人的发言。有的 IM 会把两人对话也抽象成同一个东西,也可能出于优化的考虑把双人对话特殊处理。

所以,这些 IM 在操作界面上会有一个会话列表:表现出来会是联系人名单、聊天群列表等等。选中会话列表中的项目,进入会话查看聊天记录、发言,就是这类 IM 的使用逻辑。

我认为,这种对即时通讯的抽象方式,其实是不适合办公环境的。和日常个人社交环境不同,办公群体其实是一个相对关系密切的团体,我们通常不会拉黑一个同事不让他给你发消息,也不会拒收公司发的通告,也不会因为一个同事平常不和你打交道就拒绝建立联系。项目组里的讨论,也未见得是多么保密的事情,需要防止隔壁组的同事旁听。你也很少会在办公 IM 上和妹子私聊谈人生理想。

我们这几年使用腾讯的 RTX 作为公司办公使用,我就感受到了太多这类设计缺陷。比如,有同事找我有事,我忽略了他的私聊信息;找人一般在对方活跃的项目群组里吼;程序群沦为了日常扯淡的位置,常常同时讨论着不同的问题,线索及其混乱。“群”这个设计,我在很多年前就思考过 ,我一直觉得需要在根本上换个角度看待社交聊天的需求。

我现在的想法是这样的:

作为办公 IM ,我们不应该基于固定会话(群)来设计,而应该是“通知”和“话题”。

所谓通知,就是有人发起了一条消息,他需要把这条消息传达给某些对象,对象可以是人,也可以是某个组织:比如程序、游戏项目组、等等。

组织并非是群那样的聊天室,而仅仅是一个标签,由人来关注标签,而不是去组织这个聊天室里有多少听众。

而话题,则是由消息或旧话题衍生而来。任何通知消息、话题内部消息,都可以变成一个新话题。话题也可以包含在一则消息里转发给某个对象。

用户的客户端应该把所有的通知按时间线排列在一起,呈现在同一个地方。也就是说,无论是谁给我发消息(默认就是通知)都应该投递在一起,而不是像现在 RTX 那样只是在系统托盘里闪烁提醒、也不是微信 qq 那样,联系人名单上多出一个小红点。

而一旦我回复一个通知消息,其实就把这则通知转化成了一个话题,在时间线上,话题内的消息是归属在一起的。同一时刻,无论你的思维切换多么快,其实在短时间内你只能聚焦在一个话题上,所以客户端界面是很容易表达的,把当前话题展开在主界面(通知的时间线)即可,切换话题后自然可以折叠起来。

话题并不是聊天室、它更像是论坛的帖子。一个话题可以有很多人参与(至少发言一次),更应该支持更多的人浏览。我们不应该按聊天室的思路:用户只有在加入聊天室的那一刻开始,才能收到后续的消息,而应该像论坛那样,他只是打开了这个话题帖,可以随时聊天过去到现在发生的事情。话题内的任何一个消息,都可以由用户展开为新话题,老话题对新话题只是一个引用链接而已,并不需要有层级关系,我们也可以把任意一个话题或尚未转化为话题的消息转发出去,如果有人对他评论,就生成了新话题。

话题是一个有时效性的东西,对于办公来说,如果一个话题超过 8 小时没有新的消息,就可以认为这个话题已经结束了。但是事后我们依然可以对老话题浏览,或是继续讨论,而继续讨论就是生成的一个新话题了。

只要生成话题足够方便,每个用户的主时间线上就只会有不多的通知消息,信息传达更为有效。而管理每天的消息、检索旧消息也有很强的时间线。不像现有的 IM 群聊天,每天的聊天内容会被自然的组织成话题,这些话题上标识了参与人数、归属的组织的 tag 、继承于哪个父话题或通知、经历的时间段、衍生出哪些后续话题,等等。

即使是两个人之间的对话,也同样应该是话题的形式,而不应该把消息直接组织成一长串的聊天历史。话题未必有明确的主题,只是一种更自然的信息聚合形式而已。

对于办公场合来说,有意个最重要的优势:用户群有足够的自律。基于这种自律,我认为上面的思路若实现出来很容易推广使用。

在自律之外,或许还需要一些权限管理。这些权限管理应该是相对松散简单的,主要是限制用户订阅特定组织的 tag (比如一般员工不能订阅管理层的 tag ),限制围观特定话题(比如两人之间的私聊话题默认就是不对第三人开放权限的),话题可以锁定不准转发。权限设置的细节还需要进一步推敲。
 
本文转自云风的BLOG,原文地址http://blog.codingnow.com/
继续阅读 »
   现在的 IM 在设计上是基于会话的,多个人可以组成一个会话,相当于一个聊天室,当一个人加入到一个会话后,就可以看到从加入开始之后这个聊天室里所有参与人的发言。有的 IM 会把两人对话也抽象成同一个东西,也可能出于优化的考虑把双人对话特殊处理。

所以,这些 IM 在操作界面上会有一个会话列表:表现出来会是联系人名单、聊天群列表等等。选中会话列表中的项目,进入会话查看聊天记录、发言,就是这类 IM 的使用逻辑。

我认为,这种对即时通讯的抽象方式,其实是不适合办公环境的。和日常个人社交环境不同,办公群体其实是一个相对关系密切的团体,我们通常不会拉黑一个同事不让他给你发消息,也不会拒收公司发的通告,也不会因为一个同事平常不和你打交道就拒绝建立联系。项目组里的讨论,也未见得是多么保密的事情,需要防止隔壁组的同事旁听。你也很少会在办公 IM 上和妹子私聊谈人生理想。

我们这几年使用腾讯的 RTX 作为公司办公使用,我就感受到了太多这类设计缺陷。比如,有同事找我有事,我忽略了他的私聊信息;找人一般在对方活跃的项目群组里吼;程序群沦为了日常扯淡的位置,常常同时讨论着不同的问题,线索及其混乱。“群”这个设计,我在很多年前就思考过 ,我一直觉得需要在根本上换个角度看待社交聊天的需求。

我现在的想法是这样的:

作为办公 IM ,我们不应该基于固定会话(群)来设计,而应该是“通知”和“话题”。

所谓通知,就是有人发起了一条消息,他需要把这条消息传达给某些对象,对象可以是人,也可以是某个组织:比如程序、游戏项目组、等等。

组织并非是群那样的聊天室,而仅仅是一个标签,由人来关注标签,而不是去组织这个聊天室里有多少听众。

而话题,则是由消息或旧话题衍生而来。任何通知消息、话题内部消息,都可以变成一个新话题。话题也可以包含在一则消息里转发给某个对象。

用户的客户端应该把所有的通知按时间线排列在一起,呈现在同一个地方。也就是说,无论是谁给我发消息(默认就是通知)都应该投递在一起,而不是像现在 RTX 那样只是在系统托盘里闪烁提醒、也不是微信 qq 那样,联系人名单上多出一个小红点。

而一旦我回复一个通知消息,其实就把这则通知转化成了一个话题,在时间线上,话题内的消息是归属在一起的。同一时刻,无论你的思维切换多么快,其实在短时间内你只能聚焦在一个话题上,所以客户端界面是很容易表达的,把当前话题展开在主界面(通知的时间线)即可,切换话题后自然可以折叠起来。

话题并不是聊天室、它更像是论坛的帖子。一个话题可以有很多人参与(至少发言一次),更应该支持更多的人浏览。我们不应该按聊天室的思路:用户只有在加入聊天室的那一刻开始,才能收到后续的消息,而应该像论坛那样,他只是打开了这个话题帖,可以随时聊天过去到现在发生的事情。话题内的任何一个消息,都可以由用户展开为新话题,老话题对新话题只是一个引用链接而已,并不需要有层级关系,我们也可以把任意一个话题或尚未转化为话题的消息转发出去,如果有人对他评论,就生成了新话题。

话题是一个有时效性的东西,对于办公来说,如果一个话题超过 8 小时没有新的消息,就可以认为这个话题已经结束了。但是事后我们依然可以对老话题浏览,或是继续讨论,而继续讨论就是生成的一个新话题了。

只要生成话题足够方便,每个用户的主时间线上就只会有不多的通知消息,信息传达更为有效。而管理每天的消息、检索旧消息也有很强的时间线。不像现有的 IM 群聊天,每天的聊天内容会被自然的组织成话题,这些话题上标识了参与人数、归属的组织的 tag 、继承于哪个父话题或通知、经历的时间段、衍生出哪些后续话题,等等。

即使是两个人之间的对话,也同样应该是话题的形式,而不应该把消息直接组织成一长串的聊天历史。话题未必有明确的主题,只是一种更自然的信息聚合形式而已。

对于办公场合来说,有意个最重要的优势:用户群有足够的自律。基于这种自律,我认为上面的思路若实现出来很容易推广使用。

在自律之外,或许还需要一些权限管理。这些权限管理应该是相对松散简单的,主要是限制用户订阅特定组织的 tag (比如一般员工不能订阅管理层的 tag ),限制围观特定话题(比如两人之间的私聊话题默认就是不对第三人开放权限的),话题可以锁定不准转发。权限设置的细节还需要进一步推敲。
 
本文转自云风的BLOG,原文地址http://blog.codingnow.com/ 收起阅读 »

【移动战略说 · 第一期】智能硬件产品开发从0到1

   据GSMA预期,到2020年,全球互联设备将突破270亿,移动互联设备有望达到105亿,新的市场机遇将进一步增多。自动上报家中燃气数据、远程开关气阀、精准透明计费、自动调节远程定时控制路灯等,基于新一代物联网的新型智慧产品正在走入我们的生产生活。

   开发一款智能硬件产品涉及的环节很多。本次活动,APICloud联合华强聚丰和智石科技,从样品生产、App开发和近场通讯技术在智能硬件中的应用跟大家分享智能硬件产品如何快速从0到1!
 
活动概况
【活动时间】2017年8月19日(周六),13:30-16:30
【面向人群】制造业企业、智能硬件管理层、产品负责人、技术负责人,其他相关从业者
【活动咨询/合作】请加微信:appdev1,备注819
活动议程
【13:30-14:00】签到
【14:00-14:40】如何快速完成样品生产
内容概要:产品硬件开发者希望快速拿到样品,进行方案验证和调试,发现设计问题,快速进行方案修正,以便进入下一开发环节,完成开发工作。怎样解决这些困难?怎样才能让生产环节快速顺利完成样品生产?
【14:40-15:20】自主研发or外包?智能硬件App开发指南
内容概要:现在市场上智能硬件往往需要一款App配合,无论是控制设备还是查看数据。企业不但需要考虑成本,还要兼顾产品体验。本环节APICloud将会为大家介绍App开发技术如何选型;自己招团队与找外包的对比;以及项目准备、开发、测试、上线各个阶段可能遇到的问题和注意事项。
【15:20-16:00】室内精准位置物联网络搭建
【16:00-】幸运抽奖&自由交流
分享嘉宾

30972779689807524.jpeg


30242778644313753.jpg


30852779689957552.jpeg


报名地址活动报名
继续阅读 »
   据GSMA预期,到2020年,全球互联设备将突破270亿,移动互联设备有望达到105亿,新的市场机遇将进一步增多。自动上报家中燃气数据、远程开关气阀、精准透明计费、自动调节远程定时控制路灯等,基于新一代物联网的新型智慧产品正在走入我们的生产生活。

   开发一款智能硬件产品涉及的环节很多。本次活动,APICloud联合华强聚丰和智石科技,从样品生产、App开发和近场通讯技术在智能硬件中的应用跟大家分享智能硬件产品如何快速从0到1!
 
活动概况
【活动时间】2017年8月19日(周六),13:30-16:30
【面向人群】制造业企业、智能硬件管理层、产品负责人、技术负责人,其他相关从业者
【活动咨询/合作】请加微信:appdev1,备注819
活动议程
【13:30-14:00】签到
【14:00-14:40】如何快速完成样品生产
内容概要:产品硬件开发者希望快速拿到样品,进行方案验证和调试,发现设计问题,快速进行方案修正,以便进入下一开发环节,完成开发工作。怎样解决这些困难?怎样才能让生产环节快速顺利完成样品生产?
【14:40-15:20】自主研发or外包?智能硬件App开发指南
内容概要:现在市场上智能硬件往往需要一款App配合,无论是控制设备还是查看数据。企业不但需要考虑成本,还要兼顾产品体验。本环节APICloud将会为大家介绍App开发技术如何选型;自己招团队与找外包的对比;以及项目准备、开发、测试、上线各个阶段可能遇到的问题和注意事项。
【15:20-16:00】室内精准位置物联网络搭建
【16:00-】幸运抽奖&自由交流
分享嘉宾

30972779689807524.jpeg


30242778644313753.jpg


30852779689957552.jpeg


报名地址活动报名 收起阅读 »

【环信征文】程序员为灾区祈福,我听说过的语言差不多都有了

8月8日21时19分在四川阿坝九寨沟县发生7.0级地震,地震发生后社会各界纷纷为灾区祈福。使用各种语言的程序员也不甘示弱吗,争先恐后地用自己的语言为灾区祈福。我听说过的语言差不多都有了。

~trace("ActionScript程序员为灾区祈福!");
~TEXT_IO.PUT_LINE ("Ada程序员为灾区祈福!");
~<% Response.Write("ASP程序员为灾区祈福!") %>
~MsgBox(1,'','AutoIt程序员为灾区祈福!')
~BEGIN { print "AWK程序员为灾区祈福!" }
~echo 'Bash程序员为灾区祈福!'
~? "BASIC程序员为灾区祈福!"
~WRITES ("BCPL程序员为灾区祈福")
~Print "BlitzBasic程序员为灾区祈福!"
~print "BOO程序员为灾区祈福!"
~printf("C程序员为灾区祈福!");
~cout << "C++程序员为灾区祈福!"<<endl;
~System.Console.WriteLine("C#程序员为灾区祈福");
~PROCEDURE DIVISION.DISPLAY "COBOL程序员为灾区祈福!".STOP RUN.
~echo Linux Shell程序员为灾区祈福!
~io.put_string("Eiffel程序员为灾区祈福!")
~hello_world() -> io:fwrite("Erlang程序员为灾区祈福!").
~." Forth程序员为灾区祈福!" CR
~WRITE(*,*) 'Fortran程序员为灾区祈福!'
~HTML程序员为灾区祈福!
~System.out.println("Java程序员为灾区祈福!");
~<%=("JSP程序员为灾区祈福!")%>
~(format t "Lisp程序员为灾区祈福!")
~print "Lua程序员为灾区祈福!"
~Print["Mathematica程序员为灾区祈福!"]
~Nuva程序员为灾区祈福!
~NSLog(@"Objective-C程序员为灾区祈福!");
~print_endline "OCaml程序员为灾区祈福!";
~writeln('Pascal程序员为灾区祈福!');
~say "Perl程序员为灾区祈福!";
~<?= "PHP程序员为灾区祈福!"?>~
~write("Pike程序员为灾区祈福!");
~write("Prolog程序员为灾区祈福!").
~#!/usr/bin/env pythonprint("Python程序员为灾区祈福!")
~say "REXX程序员为灾区祈福!"
~#!/usr/bin/rubyputs "Ruby程序员为灾区祈福!"
~Om:"Sbyke Laborana程序员为灾区祈福!"
~(display "Scheme程序员为灾区祈福!")
~sed -ne '1s/.*/sed程序员为灾区祈福/p'
~writeln("Seed7程序员为灾区祈福!");
~Transcript show: 'Smalltalk程序员为灾区祈福!'
~TextWindow.WriteLine("Small Basic程序员为灾区祈福!")
~OUTPUT = "SNOBOL程序员为灾区祈福!"
~print 'SQL程序员为灾区祈福!'
~println("Swift程序员为灾区祈福!")
~#!/usr/local/bin/tclputs "Tcl程序员为灾区祈福!"
~? "TScript程序员为灾区祈福!"
~put "Turing程序员为灾区祈福!"
~<includeonly>UNIX-style shell程序员为灾区祈福!</includeonly>
~ShowMessage('Delphi程序员为灾区祈福!');
~Print "Visual Basic程序员为灾区祈福!"
~? "Visual FoxPro程序员为灾区祈福!"
~QLabel label("X11程序员为灾区祈福!");
~alert("JavaScript程序员为灾区祈福!");
~(PostScript程序员为灾区祈福!) show
~println("Scala程序员为灾区祈福!")
~println("Kotlin程序员为灾区祈福!");
~调试输出(“易语言程序员为灾区祈福!”)
继续阅读 »
8月8日21时19分在四川阿坝九寨沟县发生7.0级地震,地震发生后社会各界纷纷为灾区祈福。使用各种语言的程序员也不甘示弱吗,争先恐后地用自己的语言为灾区祈福。我听说过的语言差不多都有了。

~trace("ActionScript程序员为灾区祈福!");
~TEXT_IO.PUT_LINE ("Ada程序员为灾区祈福!");
~<% Response.Write("ASP程序员为灾区祈福!") %>
~MsgBox(1,'','AutoIt程序员为灾区祈福!')
~BEGIN { print "AWK程序员为灾区祈福!" }
~echo 'Bash程序员为灾区祈福!'
~? "BASIC程序员为灾区祈福!"
~WRITES ("BCPL程序员为灾区祈福")
~Print "BlitzBasic程序员为灾区祈福!"
~print "BOO程序员为灾区祈福!"
~printf("C程序员为灾区祈福!");
~cout << "C++程序员为灾区祈福!"<<endl;
~System.Console.WriteLine("C#程序员为灾区祈福");
~PROCEDURE DIVISION.DISPLAY "COBOL程序员为灾区祈福!".STOP RUN.
~echo Linux Shell程序员为灾区祈福!
~io.put_string("Eiffel程序员为灾区祈福!")
~hello_world() -> io:fwrite("Erlang程序员为灾区祈福!").
~." Forth程序员为灾区祈福!" CR
~WRITE(*,*) 'Fortran程序员为灾区祈福!'
~HTML程序员为灾区祈福!
~System.out.println("Java程序员为灾区祈福!");
~<%=("JSP程序员为灾区祈福!")%>
~(format t "Lisp程序员为灾区祈福!")
~print "Lua程序员为灾区祈福!"
~Print["Mathematica程序员为灾区祈福!"]
~Nuva程序员为灾区祈福!
~NSLog(@"Objective-C程序员为灾区祈福!");
~print_endline "OCaml程序员为灾区祈福!";
~writeln('Pascal程序员为灾区祈福!');
~say "Perl程序员为灾区祈福!";
~<?= "PHP程序员为灾区祈福!"?>~
~write("Pike程序员为灾区祈福!");
~write("Prolog程序员为灾区祈福!").
~#!/usr/bin/env pythonprint("Python程序员为灾区祈福!")
~say "REXX程序员为灾区祈福!"
~#!/usr/bin/rubyputs "Ruby程序员为灾区祈福!"
~Om:"Sbyke Laborana程序员为灾区祈福!"
~(display "Scheme程序员为灾区祈福!")
~sed -ne '1s/.*/sed程序员为灾区祈福/p'
~writeln("Seed7程序员为灾区祈福!");
~Transcript show: 'Smalltalk程序员为灾区祈福!'
~TextWindow.WriteLine("Small Basic程序员为灾区祈福!")
~OUTPUT = "SNOBOL程序员为灾区祈福!"
~print 'SQL程序员为灾区祈福!'
~println("Swift程序员为灾区祈福!")
~#!/usr/local/bin/tclputs "Tcl程序员为灾区祈福!"
~? "TScript程序员为灾区祈福!"
~put "Turing程序员为灾区祈福!"
~<includeonly>UNIX-style shell程序员为灾区祈福!</includeonly>
~ShowMessage('Delphi程序员为灾区祈福!');
~Print "Visual Basic程序员为灾区祈福!"
~? "Visual FoxPro程序员为灾区祈福!"
~QLabel label("X11程序员为灾区祈福!");
~alert("JavaScript程序员为灾区祈福!");
~(PostScript程序员为灾区祈福!) show
~println("Scala程序员为灾区祈福!")
~println("Kotlin程序员为灾区祈福!");
~调试输出(“易语言程序员为灾区祈福!”) 收起阅读 »

【环信征文】请不要说自己是Android程序员

经常在网上看到各种标题为“Android程序员”、“Java程序员”、“PHP程序员”、“C/C++程序员”的招聘帖子,但这种招聘方式,很难找到好的人才。语言只是一种工具,对一个聪明的程序员来说,用没用过什么工具主要是由他原来的工作需要决定,并不能代表他全部的技能。

软件行业是一个非常强调人的价值的行业,价值就体现在有效的推动产品前进,而语言只是实现这个价值的工具。
(W[}_`X~BVTQM{3A`@HN4JU.png


一个软件产品往往涉及很多方面的知识,比如网络、数据库、Cache、编译环境工具等。如果这些必要基础知识不足,很难很好的独立完成一个产品的某个部分。

另一方面,一个人的聪明程度、对新知识的好奇心、自我驱动意识、为问题找到最佳解决方案的决心,才是他能不能成为一个好程序员的关键。举个例子,我的一位在某米当cto学长的告诉我,有位同事本来是服务器端以C#语言为主做开发的,完全没有过android开发经验,但他表现出对移动开发很有兴趣,并且在做服务器端开发时,表现出良好的学习能力,后来我把他调到Android组,负责android SDK和APNs相关的工作,结果只花了几个星期,Android SDK的稳定性大幅提升,解决了多个致命问题。

不要仅仅把自己定位为某种语言的程序员,说自己是Java程序员,C#程序员,Python程序员等等。一方面会限制自己的发展,一方面对团队整体的能力提升也不利。几乎所有的语言都有它自己的适用场景,在合适的地方用合适的语言,才能极大的提升生产效率。
正确的做法是,首先要有良好的基础知识,深刻的掌握2~3门语言,然后适用于不同场景的语言要了解概念。基础知识包括各种计算机原理、数据方面的知识,在学校没认真学的,现在有时间也要补充。语言方面比如掌握了C/Java,那C++/Python/Bash/Javascript/CSS等都可以了解下概念,至少要理解在一个完整的产品链里,它们分别适用于哪个环节。

标题用“请不要说自己是Android程序员”没有贬低Android程序员的意思,Java是目前被采用得最多的语言,主要用Java的程序员里,也是有大量牛人。另外,同样的,也不要说自己是C程序员、Python程序员。

 古语说的好,“书中自有黄金屋”。这句话告诉我们书籍是学习知识的第一大根本方向。在与Java相关的专业书籍中,相继记述着关于这门课程的基础知识及进阶内容,先易后难、步步深入,非常适合初学者去学习。
  虚心求教不可少。
往往很多高深莫测,经验丰富,功力深厚的人都埋藏在自己的身边,不容自己去察觉。所以如果大家想要从事Java行业,不妨请假身边从事过该行业的朋友,求学不在高低贵贱之分,只要碰到不懂的地方,就去虚心求教,世界这么大,而且这门知识又是如此让人追捧,比自己懂的人岂止千百?从这些人身上自己一定能够受益匪浅。

现在以Java语言为主的工作非常之多,另外在学校里就以学习Java为主的人也越来越多。但是,从学校就以学习Java这种高级语言为主的人,很多基础知识比较薄弱。高级语言掩盖了太多细节,提高了生产力,但在学习阶段,却不利于基础知识累积。
MSBFLGP1I{8KVLTCJ9)Q46.png

“Nicholas C. Zakas是全世界最著名的JavaScript程序员之一,之前是在雅虎将近工作5年。三年前,他写了一篇长文,回顾自己的职业生涯,提到七个对他来说最重要的建议,希望对大家的职业生涯有帮助:

1、 不要别人点什么,就做什么

我的第一份工作,只干了8个月,那家公司就倒闭了。我问经理,接下来我该怎么办,他说:"小伙子,千万不要当一个被人点菜的厨师,别人点什么,你就烧什么。不要接受那样一份工作,别人下命令你该干什么,以及怎么干。你要去一个地方,那里的人肯定你对产品的想法,相信你的能力,放手让你去做。"

我从此明白,单单实现一个产品是不够的,你还必须参与决定怎么实现。好的工程师并不仅仅服从命令,而且还给出反馈,帮助产品的拥有者改进它。

2、 推销自己




我进入雅虎公司以后,经理有一天跟我谈话,他觉得我还做得不够。

"你工作得很好,代码看上去不错,很少出Bug。但是,问题是别人都没看到这一点。为了让其他人相信你,你必须首先让别人知道你做了什么。你需要推销自己,引起别人的注意。"

我这才意识到,即使做出了很好的工作,别人都不知道,也没用。做一个角落里静静编码的工程师,并不可取。你的主管会支持你,但是他没法替你宣传。公司的其他人需要明白你的价值,最好的办法就是告诉别人你做了什么。一封简单的Email:"嗨,我完成了XXX,欢迎将你的想法告诉我",就很管用。

3、 学会带领团队
工作几年后,已经没人怀疑我的技术能力了,大家知道我能写出高质量的可靠代码。有一次,我问主管,怎么才能得到提升,他说:"当你的技术能力过关以后,就要考验你与他人相处的能力了。"
于是,我看到了,自己缺乏的是领导能力,如何带领一个团队,有效地与其他人协同工作,取到更大的成果。

4、 生活才是最重要的
有一段时间,我在雅虎公司很有挫折感,对公司的一些做法不认同,经常会对别人发火。我问一个同事,他怎么能对这种事情保持平静,他回答:"你要想通,这一切并不重要。有人提交了烂代码,网站下线了,又怎么样?工作并不是你的整个生活。它们不是真正的问题,只是工作上的问题。真正重要的事情都发生在工作以外。我回到家,家里人正在等我,这才重要啊。"
从此,我就把工作和生活分开了,只把它当作"工作问题"看待。这样一来,我对工作就总能心平气和,与人交流也更顺利了。
5、 自己找到道路
我被提升为主管以后,不知道该怎么做。我请教了上级,他回答:"以前都是我们告诉你做什么,从现在开始,你必须自己回答这个问题了,我期待你来告诉我,什么事情需要做。"
很多工程师都没有完成这个转变,如果能够做到,可能就说明你成熟了,学会了取舍。你不可能把时间花在所有事情上面,必须找到一个重点。
6、 把自己当成主人

我每天要开很多会,有些会议我根本无话可说。我对一个朋友说,我不知道自己为什么要参加这个会,也没有什么可以贡献,他说:"不要再去开这样的会了。你参加一个会,那是因为你参与了某件事。如果不确定自己为什么要在场,就停下来问。如果这件事不需要你,就离开。不要从头到尾都静静地参加一个会,要把自己当成负责人,大家会相信你的。"
从那时起,我从没有一声不发地参加会议。我确保只参加那些需要我参加的会议。
7、 找到水平更高的人
最后,让我从自己的经历出发,给我的学员一个建议。
"找到那些比你水平更高、更聪明的人,尽量和他们在一起,吃饭或者喝咖啡,向他们讨教,了解他们拥有的知识。你的职业,甚至你的生活,都会因此变得更好。"
 我的感受是IT行业是当今社会的热门行业,说它热门是因为它的发展潜力是无穷的,所以我们能进入到这个行业是一种幸运。在此,我特别感谢上家公司带我教我前辈们和师傅,在学习期间给了我莫大的帮助,在我遇到困难时,给我很大的鼓励和帮助,让我更加有信心坚持下来,找到工作。最后送大家一句话:相信自己没有选错行业,相信自己有立足的能力,为自己制定明确的目标,然后努力地去学习、体会、感悟、进步!
 
继续阅读 »
经常在网上看到各种标题为“Android程序员”、“Java程序员”、“PHP程序员”、“C/C++程序员”的招聘帖子,但这种招聘方式,很难找到好的人才。语言只是一种工具,对一个聪明的程序员来说,用没用过什么工具主要是由他原来的工作需要决定,并不能代表他全部的技能。

软件行业是一个非常强调人的价值的行业,价值就体现在有效的推动产品前进,而语言只是实现这个价值的工具。
(W[}_`X~BVTQM{3A`@HN4JU.png


一个软件产品往往涉及很多方面的知识,比如网络、数据库、Cache、编译环境工具等。如果这些必要基础知识不足,很难很好的独立完成一个产品的某个部分。

另一方面,一个人的聪明程度、对新知识的好奇心、自我驱动意识、为问题找到最佳解决方案的决心,才是他能不能成为一个好程序员的关键。举个例子,我的一位在某米当cto学长的告诉我,有位同事本来是服务器端以C#语言为主做开发的,完全没有过android开发经验,但他表现出对移动开发很有兴趣,并且在做服务器端开发时,表现出良好的学习能力,后来我把他调到Android组,负责android SDK和APNs相关的工作,结果只花了几个星期,Android SDK的稳定性大幅提升,解决了多个致命问题。

不要仅仅把自己定位为某种语言的程序员,说自己是Java程序员,C#程序员,Python程序员等等。一方面会限制自己的发展,一方面对团队整体的能力提升也不利。几乎所有的语言都有它自己的适用场景,在合适的地方用合适的语言,才能极大的提升生产效率。
正确的做法是,首先要有良好的基础知识,深刻的掌握2~3门语言,然后适用于不同场景的语言要了解概念。基础知识包括各种计算机原理、数据方面的知识,在学校没认真学的,现在有时间也要补充。语言方面比如掌握了C/Java,那C++/Python/Bash/Javascript/CSS等都可以了解下概念,至少要理解在一个完整的产品链里,它们分别适用于哪个环节。

标题用“请不要说自己是Android程序员”没有贬低Android程序员的意思,Java是目前被采用得最多的语言,主要用Java的程序员里,也是有大量牛人。另外,同样的,也不要说自己是C程序员、Python程序员。

 古语说的好,“书中自有黄金屋”。这句话告诉我们书籍是学习知识的第一大根本方向。在与Java相关的专业书籍中,相继记述着关于这门课程的基础知识及进阶内容,先易后难、步步深入,非常适合初学者去学习。
  虚心求教不可少。
往往很多高深莫测,经验丰富,功力深厚的人都埋藏在自己的身边,不容自己去察觉。所以如果大家想要从事Java行业,不妨请假身边从事过该行业的朋友,求学不在高低贵贱之分,只要碰到不懂的地方,就去虚心求教,世界这么大,而且这门知识又是如此让人追捧,比自己懂的人岂止千百?从这些人身上自己一定能够受益匪浅。

现在以Java语言为主的工作非常之多,另外在学校里就以学习Java为主的人也越来越多。但是,从学校就以学习Java这种高级语言为主的人,很多基础知识比较薄弱。高级语言掩盖了太多细节,提高了生产力,但在学习阶段,却不利于基础知识累积。
MSBFLGP1I{8KVLTCJ9)Q46.png

“Nicholas C. Zakas是全世界最著名的JavaScript程序员之一,之前是在雅虎将近工作5年。三年前,他写了一篇长文,回顾自己的职业生涯,提到七个对他来说最重要的建议,希望对大家的职业生涯有帮助:

1、 不要别人点什么,就做什么

我的第一份工作,只干了8个月,那家公司就倒闭了。我问经理,接下来我该怎么办,他说:"小伙子,千万不要当一个被人点菜的厨师,别人点什么,你就烧什么。不要接受那样一份工作,别人下命令你该干什么,以及怎么干。你要去一个地方,那里的人肯定你对产品的想法,相信你的能力,放手让你去做。"

我从此明白,单单实现一个产品是不够的,你还必须参与决定怎么实现。好的工程师并不仅仅服从命令,而且还给出反馈,帮助产品的拥有者改进它。

2、 推销自己




我进入雅虎公司以后,经理有一天跟我谈话,他觉得我还做得不够。

"你工作得很好,代码看上去不错,很少出Bug。但是,问题是别人都没看到这一点。为了让其他人相信你,你必须首先让别人知道你做了什么。你需要推销自己,引起别人的注意。"

我这才意识到,即使做出了很好的工作,别人都不知道,也没用。做一个角落里静静编码的工程师,并不可取。你的主管会支持你,但是他没法替你宣传。公司的其他人需要明白你的价值,最好的办法就是告诉别人你做了什么。一封简单的Email:"嗨,我完成了XXX,欢迎将你的想法告诉我",就很管用。

3、 学会带领团队
工作几年后,已经没人怀疑我的技术能力了,大家知道我能写出高质量的可靠代码。有一次,我问主管,怎么才能得到提升,他说:"当你的技术能力过关以后,就要考验你与他人相处的能力了。"
于是,我看到了,自己缺乏的是领导能力,如何带领一个团队,有效地与其他人协同工作,取到更大的成果。

4、 生活才是最重要的
有一段时间,我在雅虎公司很有挫折感,对公司的一些做法不认同,经常会对别人发火。我问一个同事,他怎么能对这种事情保持平静,他回答:"你要想通,这一切并不重要。有人提交了烂代码,网站下线了,又怎么样?工作并不是你的整个生活。它们不是真正的问题,只是工作上的问题。真正重要的事情都发生在工作以外。我回到家,家里人正在等我,这才重要啊。"
从此,我就把工作和生活分开了,只把它当作"工作问题"看待。这样一来,我对工作就总能心平气和,与人交流也更顺利了。
5、 自己找到道路
我被提升为主管以后,不知道该怎么做。我请教了上级,他回答:"以前都是我们告诉你做什么,从现在开始,你必须自己回答这个问题了,我期待你来告诉我,什么事情需要做。"
很多工程师都没有完成这个转变,如果能够做到,可能就说明你成熟了,学会了取舍。你不可能把时间花在所有事情上面,必须找到一个重点。
6、 把自己当成主人

我每天要开很多会,有些会议我根本无话可说。我对一个朋友说,我不知道自己为什么要参加这个会,也没有什么可以贡献,他说:"不要再去开这样的会了。你参加一个会,那是因为你参与了某件事。如果不确定自己为什么要在场,就停下来问。如果这件事不需要你,就离开。不要从头到尾都静静地参加一个会,要把自己当成负责人,大家会相信你的。"
从那时起,我从没有一声不发地参加会议。我确保只参加那些需要我参加的会议。
7、 找到水平更高的人
最后,让我从自己的经历出发,给我的学员一个建议。
"找到那些比你水平更高、更聪明的人,尽量和他们在一起,吃饭或者喝咖啡,向他们讨教,了解他们拥有的知识。你的职业,甚至你的生活,都会因此变得更好。"
 我的感受是IT行业是当今社会的热门行业,说它热门是因为它的发展潜力是无穷的,所以我们能进入到这个行业是一种幸运。在此,我特别感谢上家公司带我教我前辈们和师傅,在学习期间给了我莫大的帮助,在我遇到困难时,给我很大的鼓励和帮助,让我更加有信心坚持下来,找到工作。最后送大家一句话:相信自己没有选错行业,相信自己有立足的能力,为自己制定明确的目标,然后努力地去学习、体会、感悟、进步!
  收起阅读 »

如何阅读计算机科学类的书

 
QQ图片20170810185201.png

 作为一个研发工程师,无论你是否喜爱阅读,相信你都一定读过不少关于计算机技术的书籍。这其中不乏《21天学会JAVA》这样的语言入门书籍,也有《算法导论》这样的专题书籍,也有《人月神话》这样关于软件管理学的实用性的书籍。也许你已经读过他们中的大部分,也许你现在还在不断地购入新的书籍来补充你的知识库。但请稍等一下,你是否思考过这样的问题,面对大量的计算机科学书籍,你是否都真正读懂了它们呢?有多少本书,当你将他放在书架上之后,就再也没有重新打开过?有多少知识是真正被存储在你的大脑中,并随时可以提供调用?拿到一本书后,高效阅读的正确姿势的什么?如果你有以上的疑惑,那么接下来,我们将一起探讨一个问题,如何阅读一本计算机科学类书籍。

阅读的四种层次

   首先,我们先要学会如何阅读。你可能会觉得不可思议,我已经接受过高等教育,怎么可能还不会阅读。然而可悲的是,现代教育体系中,恰恰忽略了对阅读能力的训练。我们在初中之后,阅读水平就几乎没有机会再得到提升。总体来说,阅读分为四种层次,分别是:
  • 基础阅读
  • 检视阅读
  • 分析阅读
  • 主题阅读

 
   这其中的概念来源于莫提默·J·艾德勒和查尔斯·范多伦的著作《如何阅读一本书(How To Read A Book)》,这里我必须对其中的概念做简单的总结,以便在后续的篇幅中,我们能统一对阅读名词的理解。

基础阅读
   当我们完成中学学业后,我们中的绝大部分人,都已经掌握了基础阅读的能力。在这个层次中,我们关心的是,书里的每句话是什么意思。这是一个最基础的层次。
检视阅读
   检视阅读,我们也可以称之为快速阅读。快速浏览全书,了解书的主题,架构全书,提出核心问题。这并不是很新鲜的概念,但很多人可能并没有思考过,为什么要做检视阅读。检视阅读作用是为了帮助我们筛选这本书是否值得阅读,同时为接下来的分析阅读打下基础。在这个层次中,我们关心的是,这本书在讲什么。
 
分析阅读
   分析阅读是一个更为高级的阅读层次,目标让我们能充分理解本书,与作者对话。其中包含了多个阶段,这里不再详述,有兴趣的同学可以研读原著。
 
主题阅读
   当我们跨越过分析阅读后,这本书已经被我们掌握。此时,我们会就相同的主题,阅读不同的书籍,找出其中关联与矛盾,倾听不同的作者的不同声音,从而对某个主题产生更加深刻的认识。这个阶段,我们关注的不再是某一本书,而是一个具体的问题。
 
计算机科学书籍的特征
   原著中针对不同类型的书籍,给予了不同的阅读建议。但由于所著时间很早,就计算机科学类图书的阅读建议,在书中并没有专门设计章节阐述。根据我的阅读经历,深感计算机科学类书籍,较其他类型图书有着其独特性:

单本书籍的信息量大
   相较其他学科,绝大多数计算机科学类书籍并不是以得出结论并且论证结论为核心,而偏重于阐述方法和解释原理。有很多计算机书籍旨在剖析某个系统。这里的系统不仅仅指代诸如操作系统这样的实体系统,还包括一门语言或者一套管理方法论这样的理论系统。而系统通常是由多个部分组成的综合体,这其中势必包含不同组成部分的不同细节,信息量之大可见一斑。
 
注重实践
   计算机科学是一门实用性的学科。这里的实用性可以理解为,计算机科学诞生的目的就是为了解决实际问题。因此,几乎所有的计算机科学书籍,都是以指导实践为目标而作。
 
更新速度快
   计算机科学的更迭速度可以准确地被描述为日新月异。有些技术很快地火爆起来,又很快地消亡,所以有些书也就跟着很快地淹没在时代的进程中。
 
分类细致但同质度高
   计算机科学对自己有着过分清晰的划分,不同的技术之间往往边界清晰。我们很少见操作系统和数据库系统在同一本书中论述,也不常见集不同语言之成的大作。由于领域划分细致,相同领域的书籍,多数时候往往论述的是同样的主题。
 
阅读计算机科学书籍的误区
   绝大多数读者的错误意识在于把所有的书籍都认为是层层推进的论述过程。这样的阅读经验一旦沿用在计算机科学类书籍中,就会感觉举步维艰。前文说过,大多数的计算机书籍都是在剖析系统,一个系统又是由许多相互关联的部分组成。解读这类书籍,如同拆解一个机械,我们在拆解的过程,常常会犯下这些错误。

通读全书
   在你的头脑中没有对全书的结构有整体了解的情况下,从头至尾通读全书,意味着试图从细节窥视一个系统的全貌。这是一种低效的读书方式。当读到中落时,你会因为没有全局概念,而迷失在各种细节中,以至于完全失去了阅读的方向和目标。
 
跳过序言
   序言往往是很多人忽略的内容,似乎序言只是重复了正文的内容。而正因为如此,序言以简短精炼的语言,为你分解了整本书的架构,帮助你把握系统的整体。这项工作本来应该是读者在阅读全书之前的必备工作,绝大多数的作者都已经帮你完成了,而你需要做的仅仅是认真的阅读它。
 
脱离实践
   前文说过,计算机科学类书籍重视实践,脱离了实践,往往就不能完全理解书中所述的理论和方法,过目就忘,纸上谈兵。
 
忽视基础
   封装在计算机的世界中是一个非常重要的概念。计算机的发展史,总的来说就是一部封装史:将底层不断包装,提供简单的调用方式,由此不断的扩展计算机的边界和能力。新的技术层出不穷,而他们的很多所依赖的环境和系统,从设计之初就没有发生过质的变化。
有时,在追逐新的技术之前,深入了解他们所在的系统;在学习新的算法之前,掌握好其基础的数学原理。只有牢固的基础才能支撑足够结实的上层建筑。
 
阅读计算机科学书籍的建议
   当了解阅读误区后,你们是不是已经发现阅读这类书籍的核心原理呢?那就是将整本书当做一个系统,从整体到局部,层层递进,逐步剖析。根据这个核心原理,我总结了一些好的实践方式。
 
检视阅读
   当你拿到一本计算机科学书籍,第一步就应该快速浏览序言和目录,然后用检视阅读的方式整理出整本书的大纲。这样,你对这本书是介绍理论还是关注实践,所属什么分类,哪些问题是本书将会讨论,而哪些问题是不被详细讨论的,这些信息你都会有整体上的认知。这时,你就可以很轻松地判断,这本书值不值的阅读,哪些内容是你已经熟知的,哪些内容是你关注的重点,这样做阅读的效率将会大大的提高。
   如果从来没有使用过这种阅读方式,开始实践时,会受到一定的心理上的阻力。可能你对某个专有名词完全没有概念,以至于整章的内容都模棱两可。这时,你应该坚持继续阅读,对不甚理解的内容,先记住有这样的概念。绝大多数的时候,经过检视阅读后,过程中的问题都会有所释怀,剩下依然没有明白的内容,视其重要性,再决定是否对其进行分析阅读。
 
提取问题
   当你了解了整本书的全貌,一般而言,你会发现,有些章节你已经熟悉,有些章节你全然不知。这时就要对这些章节进行分析阅读。分析阅读的很多步骤和方法在《如何阅读一本书(How To Read A Book)》有详细的介绍,这里不展开细说。但有时,你在阅读的过程中,会发现阅读的兴趣在下降。信息量愈大,阅读的动力愈弱,最后你就迷失在信息的汪洋之中。
我们应该如何避免这样的信息疲劳呢?答案就是去掉冗余的干扰信息。在上一个建议中,我们强调了检视阅读的重要性。那检视阅读的成果是什么呢?那就是你对每个部分(不一定是书中给你划分的章节)所提出的问题,也可以称之为阅读目标。而你要做的就是,找到这些问题的答案,完成自己的阅读目标。
   这样做过滤了很多作者认为重要,其实和你关心的主旨没有联系的信息,减少了信息疲劳。同时,不同部分之间有关联的问题,可以帮助你更好的串联全书阐述的核心概念,把握整本书的主要脉络。
例如,我在阅读《深入理解计算机系统》的异常控制流时,就提出这样的问题:进程是如何管理内存?而部分的答案,在下一个章节虚拟内存中。当我解答这个问题时,我就会将这两个分离的章节的内容,通过一个问题联系在一起,加深了自己的理解。
 
持续重读
   一本经典优秀的计算机科学书籍,值得你反复的阅读。不要觉得整本书我已经完全理解,就再也不需要重新回顾阅读了。因为此类书籍存在大量信息,而这些信息并没有必要占据我们大脑有限的记忆存储空间。我们要做的就是认真做好第一条建议,当我们需要使用这些书籍解决问题的时候,能第一时间在其中找到我们需要的信息。毫不夸张的说,计算机科学类的书籍生来就是供人反复翻阅的。
 
鉴别烂书
   作为阅读爱好者,谁能说自己没读过几本烂书呢。在计算机科学这个类别中,烂书的比例一点也不比其他学科低。信息重复(抄袭),结构混乱,论证不清晰(作者对某个技术一知半解)等等,都是烂书的特征。关于烂书,我们要做的就是第一时间将其鉴别出来,然后放到自己的黑名单中。具体如何鉴别烂书,由于本篇幅太长,我可能会新开一篇文章单独讨论。
 
结语
   以上就是我对于如何阅读计算机科学类书籍的理解。本来想缩短些篇幅,但最后还是决定保留那些我觉得应该详细论述的部分。毕竟这篇文章的初心并非是厕所读物,而是一个阅读爱好者认真地与读者探讨一个严肃的话题。如果可以,我希望在通过我不断地探索,阅读能力的持续提升,我还能在此宝地继续这个话题,完善我的理论。
我在下面列出我认为经典优秀的计算机科学书籍,也欢迎大家补充,排名不分先后。
继续阅读 »
 
QQ图片20170810185201.png

 作为一个研发工程师,无论你是否喜爱阅读,相信你都一定读过不少关于计算机技术的书籍。这其中不乏《21天学会JAVA》这样的语言入门书籍,也有《算法导论》这样的专题书籍,也有《人月神话》这样关于软件管理学的实用性的书籍。也许你已经读过他们中的大部分,也许你现在还在不断地购入新的书籍来补充你的知识库。但请稍等一下,你是否思考过这样的问题,面对大量的计算机科学书籍,你是否都真正读懂了它们呢?有多少本书,当你将他放在书架上之后,就再也没有重新打开过?有多少知识是真正被存储在你的大脑中,并随时可以提供调用?拿到一本书后,高效阅读的正确姿势的什么?如果你有以上的疑惑,那么接下来,我们将一起探讨一个问题,如何阅读一本计算机科学类书籍。

阅读的四种层次

   首先,我们先要学会如何阅读。你可能会觉得不可思议,我已经接受过高等教育,怎么可能还不会阅读。然而可悲的是,现代教育体系中,恰恰忽略了对阅读能力的训练。我们在初中之后,阅读水平就几乎没有机会再得到提升。总体来说,阅读分为四种层次,分别是:
  • 基础阅读
  • 检视阅读
  • 分析阅读
  • 主题阅读

 
   这其中的概念来源于莫提默·J·艾德勒和查尔斯·范多伦的著作《如何阅读一本书(How To Read A Book)》,这里我必须对其中的概念做简单的总结,以便在后续的篇幅中,我们能统一对阅读名词的理解。

基础阅读
   当我们完成中学学业后,我们中的绝大部分人,都已经掌握了基础阅读的能力。在这个层次中,我们关心的是,书里的每句话是什么意思。这是一个最基础的层次。
检视阅读
   检视阅读,我们也可以称之为快速阅读。快速浏览全书,了解书的主题,架构全书,提出核心问题。这并不是很新鲜的概念,但很多人可能并没有思考过,为什么要做检视阅读。检视阅读作用是为了帮助我们筛选这本书是否值得阅读,同时为接下来的分析阅读打下基础。在这个层次中,我们关心的是,这本书在讲什么。
 
分析阅读
   分析阅读是一个更为高级的阅读层次,目标让我们能充分理解本书,与作者对话。其中包含了多个阶段,这里不再详述,有兴趣的同学可以研读原著。
 
主题阅读
   当我们跨越过分析阅读后,这本书已经被我们掌握。此时,我们会就相同的主题,阅读不同的书籍,找出其中关联与矛盾,倾听不同的作者的不同声音,从而对某个主题产生更加深刻的认识。这个阶段,我们关注的不再是某一本书,而是一个具体的问题。
 
计算机科学书籍的特征
   原著中针对不同类型的书籍,给予了不同的阅读建议。但由于所著时间很早,就计算机科学类图书的阅读建议,在书中并没有专门设计章节阐述。根据我的阅读经历,深感计算机科学类书籍,较其他类型图书有着其独特性:

单本书籍的信息量大
   相较其他学科,绝大多数计算机科学类书籍并不是以得出结论并且论证结论为核心,而偏重于阐述方法和解释原理。有很多计算机书籍旨在剖析某个系统。这里的系统不仅仅指代诸如操作系统这样的实体系统,还包括一门语言或者一套管理方法论这样的理论系统。而系统通常是由多个部分组成的综合体,这其中势必包含不同组成部分的不同细节,信息量之大可见一斑。
 
注重实践
   计算机科学是一门实用性的学科。这里的实用性可以理解为,计算机科学诞生的目的就是为了解决实际问题。因此,几乎所有的计算机科学书籍,都是以指导实践为目标而作。
 
更新速度快
   计算机科学的更迭速度可以准确地被描述为日新月异。有些技术很快地火爆起来,又很快地消亡,所以有些书也就跟着很快地淹没在时代的进程中。
 
分类细致但同质度高
   计算机科学对自己有着过分清晰的划分,不同的技术之间往往边界清晰。我们很少见操作系统和数据库系统在同一本书中论述,也不常见集不同语言之成的大作。由于领域划分细致,相同领域的书籍,多数时候往往论述的是同样的主题。
 
阅读计算机科学书籍的误区
   绝大多数读者的错误意识在于把所有的书籍都认为是层层推进的论述过程。这样的阅读经验一旦沿用在计算机科学类书籍中,就会感觉举步维艰。前文说过,大多数的计算机书籍都是在剖析系统,一个系统又是由许多相互关联的部分组成。解读这类书籍,如同拆解一个机械,我们在拆解的过程,常常会犯下这些错误。

通读全书
   在你的头脑中没有对全书的结构有整体了解的情况下,从头至尾通读全书,意味着试图从细节窥视一个系统的全貌。这是一种低效的读书方式。当读到中落时,你会因为没有全局概念,而迷失在各种细节中,以至于完全失去了阅读的方向和目标。
 
跳过序言
   序言往往是很多人忽略的内容,似乎序言只是重复了正文的内容。而正因为如此,序言以简短精炼的语言,为你分解了整本书的架构,帮助你把握系统的整体。这项工作本来应该是读者在阅读全书之前的必备工作,绝大多数的作者都已经帮你完成了,而你需要做的仅仅是认真的阅读它。
 
脱离实践
   前文说过,计算机科学类书籍重视实践,脱离了实践,往往就不能完全理解书中所述的理论和方法,过目就忘,纸上谈兵。
 
忽视基础
   封装在计算机的世界中是一个非常重要的概念。计算机的发展史,总的来说就是一部封装史:将底层不断包装,提供简单的调用方式,由此不断的扩展计算机的边界和能力。新的技术层出不穷,而他们的很多所依赖的环境和系统,从设计之初就没有发生过质的变化。
有时,在追逐新的技术之前,深入了解他们所在的系统;在学习新的算法之前,掌握好其基础的数学原理。只有牢固的基础才能支撑足够结实的上层建筑。
 
阅读计算机科学书籍的建议
   当了解阅读误区后,你们是不是已经发现阅读这类书籍的核心原理呢?那就是将整本书当做一个系统,从整体到局部,层层递进,逐步剖析。根据这个核心原理,我总结了一些好的实践方式。
 
检视阅读
   当你拿到一本计算机科学书籍,第一步就应该快速浏览序言和目录,然后用检视阅读的方式整理出整本书的大纲。这样,你对这本书是介绍理论还是关注实践,所属什么分类,哪些问题是本书将会讨论,而哪些问题是不被详细讨论的,这些信息你都会有整体上的认知。这时,你就可以很轻松地判断,这本书值不值的阅读,哪些内容是你已经熟知的,哪些内容是你关注的重点,这样做阅读的效率将会大大的提高。
   如果从来没有使用过这种阅读方式,开始实践时,会受到一定的心理上的阻力。可能你对某个专有名词完全没有概念,以至于整章的内容都模棱两可。这时,你应该坚持继续阅读,对不甚理解的内容,先记住有这样的概念。绝大多数的时候,经过检视阅读后,过程中的问题都会有所释怀,剩下依然没有明白的内容,视其重要性,再决定是否对其进行分析阅读。
 
提取问题
   当你了解了整本书的全貌,一般而言,你会发现,有些章节你已经熟悉,有些章节你全然不知。这时就要对这些章节进行分析阅读。分析阅读的很多步骤和方法在《如何阅读一本书(How To Read A Book)》有详细的介绍,这里不展开细说。但有时,你在阅读的过程中,会发现阅读的兴趣在下降。信息量愈大,阅读的动力愈弱,最后你就迷失在信息的汪洋之中。
我们应该如何避免这样的信息疲劳呢?答案就是去掉冗余的干扰信息。在上一个建议中,我们强调了检视阅读的重要性。那检视阅读的成果是什么呢?那就是你对每个部分(不一定是书中给你划分的章节)所提出的问题,也可以称之为阅读目标。而你要做的就是,找到这些问题的答案,完成自己的阅读目标。
   这样做过滤了很多作者认为重要,其实和你关心的主旨没有联系的信息,减少了信息疲劳。同时,不同部分之间有关联的问题,可以帮助你更好的串联全书阐述的核心概念,把握整本书的主要脉络。
例如,我在阅读《深入理解计算机系统》的异常控制流时,就提出这样的问题:进程是如何管理内存?而部分的答案,在下一个章节虚拟内存中。当我解答这个问题时,我就会将这两个分离的章节的内容,通过一个问题联系在一起,加深了自己的理解。
 
持续重读
   一本经典优秀的计算机科学书籍,值得你反复的阅读。不要觉得整本书我已经完全理解,就再也不需要重新回顾阅读了。因为此类书籍存在大量信息,而这些信息并没有必要占据我们大脑有限的记忆存储空间。我们要做的就是认真做好第一条建议,当我们需要使用这些书籍解决问题的时候,能第一时间在其中找到我们需要的信息。毫不夸张的说,计算机科学类的书籍生来就是供人反复翻阅的。
 
鉴别烂书
   作为阅读爱好者,谁能说自己没读过几本烂书呢。在计算机科学这个类别中,烂书的比例一点也不比其他学科低。信息重复(抄袭),结构混乱,论证不清晰(作者对某个技术一知半解)等等,都是烂书的特征。关于烂书,我们要做的就是第一时间将其鉴别出来,然后放到自己的黑名单中。具体如何鉴别烂书,由于本篇幅太长,我可能会新开一篇文章单独讨论。
 
结语
   以上就是我对于如何阅读计算机科学类书籍的理解。本来想缩短些篇幅,但最后还是决定保留那些我觉得应该详细论述的部分。毕竟这篇文章的初心并非是厕所读物,而是一个阅读爱好者认真地与读者探讨一个严肃的话题。如果可以,我希望在通过我不断地探索,阅读能力的持续提升,我还能在此宝地继续这个话题,完善我的理论。
我在下面列出我认为经典优秀的计算机科学书籍,也欢迎大家补充,排名不分先后。 收起阅读 »

【环信征文】没有几样强迫症,不配自称程序员

程序员是一类特殊的群体,因为与电脑交流多于与人交流,所以他们成为了强迫症的高发群体。我国的程序员人数已经达到了 500 万人,比世界上一半的国家人口都多。任何小问题乘以 500 万都是很惊人的,程序员的强迫症成了不可忽视的社会现象。我将程序员高发的强迫症分为十大类。

0 数字强迫症

数字强迫症的症状是数数从 0 开始,这是中了大多数编程语言的毒导致的。

数字强迫症的另一种症状就是对二进制有执念,很多程序员员都认为世界上有 10 种人:一种懂二进制,另一种不懂。

数字强迫症的晚期症状是认为 256 和 1024 等 2 的 n 次方很完美,常常有 1kg == 1024g 或者 1L = 1024mL 的错觉。

1 格式强迫症

格式强迫症的症状是对代码的缩进要求极其严格,代码务必美观。即使遇到缩进不能再整齐的代码,如果有的缩进是 1 个Tab而有的缩进是 4 个Space都会浑身难受。

当代的IDE做到了Enter换行自动缩进和Ctrl + Alt + L整理格式,大大减少了格式强迫症的发病率,格式强迫症也顺理成章发生了变异。格式强迫症最常见的变异就是从只追求左边的对齐变成了也追求右边的对齐,患者会把IDE的字体都换为等宽字体。

2 命名强迫症

命名强迫症的症状是对类、接口、变量、常量、方法、枚举等的命名既追求简短,又追求直白,希望能一目了然——但一般来说简短和直白就如同物美和价廉一样不可兼得。当命名强迫症作为输入强迫症的并发症出现时,经常会因为一列对象的命名字数不一致而有砸电脑的冲动。

中国的程序员有种特殊的命名强迫症,就是不喜欢拼音命名,看见前任遗留代码中的拼音命名就会火冒三丈。

命名强迫症的另一种症状是不喜欢看到笼统的命名,例如data_1、msg_2、view_3甚至干脆就是i、j、k(方法内部循环除外);更不喜欢看到有误导的命名,比如突然发现这么一句注释:“//以下所有left代表右,所有right代表左”。

命名强迫症的晚期症状就是对驼峰命名法有莫名其妙的痴迷,就连新注册网站的用户名都要严格遵循驼峰命名法。

3 保存强迫症

在Eclipse + NetBean的时代,IDE没有自动保存功能,很多程序员养成了随时Ctrl+S的习惯。而当代IDE基本上都有自动保存的功能,他们的习惯,这就是保存强迫症。

前端程序员上网的时候会不断Ctrl+S。如果网页有文本编辑器,在Ctrl+S的时候会弹出对话框:“文字已成功保存于某年月日”,然后会莫名紧张:“怎么又弹窗了?”好久才反应过来自己在上网。

保存强迫症并非一无是处,患者玩单机游戏会自带“随时使用S/L大法”技能,会大大避免前功尽弃的可能。

4 维修强迫症

维修强迫症的症状是在U盘或者移动硬盘里保存各类杀毒软件、木马库、系统镜像、越狱工具、Android root工具以便随时维修电脑和手机。病因是被七大姑八大姨“你不是程序员吗怎么连电脑/手机都不会修?”逼的。

维修强迫症没有晚期症状,三舅妈的大姑姐找程序员帮她修智能洗衣机等loT设备或者四叔的小舅子找程序员把科学计算器刷成Android系统时就把程序员直接逼死了。

5 硬件强迫症

硬件强迫症的症状是程序员对自己工作有关的硬件要求极高。以下常见的致病硬件的逼格和获得的成本递增:

移动硬盘:移动硬盘是线下的Git,保存无数代码、文档以及秘钥。在“考研资料/政治/马克思主义哲学/第十八章/课程H”下面也隐藏着不为人知的东西。

机械键盘:噼里啪啦的手感和不菲的身价,HHKB是每个程序员的信仰,买不起HHKB的程序员会用国产的机械键盘凑合着用。

iMac或者Macbook Pro:苹果的电脑性能都非常好,编译程序速度非常快。更重要的一点:OS X系统不能玩LOL,避免了浪费写代码的时间。

双显示器:对于前端程序员来说,双显示器不仅是装逼用的,一台竖屏显示器显示WebStorm,而另一台横屏显示器显示Chrome对编程很有帮助的。显示器的价格并不昂贵,昂贵的是能呈 120 度角摆两台显示器的桌子下面的地皮在北上广深杭写字楼里的租金。

人体工程学座椅:五花八门的不正常办公家具包括人体工程学座椅和支持站立编程的桌子等,美其名曰保护程序员的颈椎、腰、屁股和前列腺,受到程序员喜爱的真实原因你懂的。

程序员鼓励师:大多数程序员渴望但不曾拥有过的硬件是只属于自己的程序员鼓励师,换句话说就是在你写代码时红袖添香的女朋友。

6 白盒强迫症

白盒强迫症的常见症状是看见代码就想优化一下。说程序员只怕“error”不怕“warning”是非常错误的,很多程序员见不得黄字和中划线,也见不得蓝色的“// TODO”。

白盒强迫症很多时候都是有益的,可以让代码变得整洁,隐藏的漏洞也会减少。

白盒强迫症的晚期患者每次打开一个网页都要右键查看源代码,已经无法正常上网。

7 黑盒强迫症

黑盒强迫症的常见症状是每次看见闭源的软件都想研究一下里面的原理,再想想自己能不能做得更好。比如用支付宝扫码支付的时候想的是识别二维码、通信加密、支付安全等原理;或者乘坐电梯时看着电梯的按钮面板(现实世界的UI)会开始思考电梯的调度算法,比如多个实例之间状态可以互相影响,还有一些优先级、加速度、预判方面的东西。

黑盒强迫症的晚期症状是看见现实世界中办事的流程都想用算法知识优化一下,常见的是想着如何优化公司报销和升职的审批流程;再举个反面例子,看《人民的名义》或《官场现形记》时都想着怎么优化贪官和奸商的“办事”流程。

8 收藏强迫症

收藏强迫症的症状是在GitHub上看见好源码必star,技术博客上看到好文章必然收藏,没有收藏功能的个人站也要加入收藏夹。收藏虽多,但不会再看。明知如此,还感觉不收藏就会吃亏。

9 身份强迫症

身份强迫症的早期症状就是头脑中“程序员 == 我自己”的概念根深蒂固,看到和程序员有关的话题都要打开看一下,尽管大多数程序员不会因为应勤是程序员就看《欢乐颂2》,但你打开本文一定是因为本文标题有“程序员”。读完本文的患者还会把自己和同事们作为一个数组,本文中 10 种强迫症作为另一个数组,然后在自己的大脑里做一个递归,查查自己和同事们分别中了几枪。

身份强迫症的晚期症状是把现实世界中见到的一切理解为IT知识,忘记了自己在职场外怎么做一个正常人:走火入魔的患者偶然有一天没有在家写代码,出门看见太阳想到的是“单例模式”,看见双胞胎想到的是“拷贝”,看到摩天轮想到的“循环”,看到排队想到的是“队列”。

身份强迫症进入日薄西山阶段的症状是患者已经无法用人类的语言进行交流了,QQ聊天时每句话的最后都要家一个“;”,没错,是半角的分号;更有甚者还会把脏话用“/*”和“*/”框起来,以为对方就看不见了;看见卖西瓜就只买一个包子的程序员听说学姐留学归来,会四门语言的第一反应是问她那四门语言是Java、PHP、Python和JavaScript还是C、C++、C#和Objective-C。

身份强迫症进入回光返照阶段的情况是试图把别的语言、工具、领域的程序员改造成自己同行的程序员,曾高呼“PHP是最好的语言”的程序员在移动互联网时代改行Android后会纠结怎么把iMac或者Macbook Pro屏幕背面的Apple形状的灯改成Android形状的。

如果你读到最后,不但一枪没中,也没把自己身边的朋友和同事套在这十大强迫症上做个递归,那么你一定不是一个程序员。
继续阅读 »
程序员是一类特殊的群体,因为与电脑交流多于与人交流,所以他们成为了强迫症的高发群体。我国的程序员人数已经达到了 500 万人,比世界上一半的国家人口都多。任何小问题乘以 500 万都是很惊人的,程序员的强迫症成了不可忽视的社会现象。我将程序员高发的强迫症分为十大类。

0 数字强迫症

数字强迫症的症状是数数从 0 开始,这是中了大多数编程语言的毒导致的。

数字强迫症的另一种症状就是对二进制有执念,很多程序员员都认为世界上有 10 种人:一种懂二进制,另一种不懂。

数字强迫症的晚期症状是认为 256 和 1024 等 2 的 n 次方很完美,常常有 1kg == 1024g 或者 1L = 1024mL 的错觉。

1 格式强迫症

格式强迫症的症状是对代码的缩进要求极其严格,代码务必美观。即使遇到缩进不能再整齐的代码,如果有的缩进是 1 个Tab而有的缩进是 4 个Space都会浑身难受。

当代的IDE做到了Enter换行自动缩进和Ctrl + Alt + L整理格式,大大减少了格式强迫症的发病率,格式强迫症也顺理成章发生了变异。格式强迫症最常见的变异就是从只追求左边的对齐变成了也追求右边的对齐,患者会把IDE的字体都换为等宽字体。

2 命名强迫症

命名强迫症的症状是对类、接口、变量、常量、方法、枚举等的命名既追求简短,又追求直白,希望能一目了然——但一般来说简短和直白就如同物美和价廉一样不可兼得。当命名强迫症作为输入强迫症的并发症出现时,经常会因为一列对象的命名字数不一致而有砸电脑的冲动。

中国的程序员有种特殊的命名强迫症,就是不喜欢拼音命名,看见前任遗留代码中的拼音命名就会火冒三丈。

命名强迫症的另一种症状是不喜欢看到笼统的命名,例如data_1、msg_2、view_3甚至干脆就是i、j、k(方法内部循环除外);更不喜欢看到有误导的命名,比如突然发现这么一句注释:“//以下所有left代表右,所有right代表左”。

命名强迫症的晚期症状就是对驼峰命名法有莫名其妙的痴迷,就连新注册网站的用户名都要严格遵循驼峰命名法。

3 保存强迫症

在Eclipse + NetBean的时代,IDE没有自动保存功能,很多程序员养成了随时Ctrl+S的习惯。而当代IDE基本上都有自动保存的功能,他们的习惯,这就是保存强迫症。

前端程序员上网的时候会不断Ctrl+S。如果网页有文本编辑器,在Ctrl+S的时候会弹出对话框:“文字已成功保存于某年月日”,然后会莫名紧张:“怎么又弹窗了?”好久才反应过来自己在上网。

保存强迫症并非一无是处,患者玩单机游戏会自带“随时使用S/L大法”技能,会大大避免前功尽弃的可能。

4 维修强迫症

维修强迫症的症状是在U盘或者移动硬盘里保存各类杀毒软件、木马库、系统镜像、越狱工具、Android root工具以便随时维修电脑和手机。病因是被七大姑八大姨“你不是程序员吗怎么连电脑/手机都不会修?”逼的。

维修强迫症没有晚期症状,三舅妈的大姑姐找程序员帮她修智能洗衣机等loT设备或者四叔的小舅子找程序员把科学计算器刷成Android系统时就把程序员直接逼死了。

5 硬件强迫症

硬件强迫症的症状是程序员对自己工作有关的硬件要求极高。以下常见的致病硬件的逼格和获得的成本递增:

移动硬盘:移动硬盘是线下的Git,保存无数代码、文档以及秘钥。在“考研资料/政治/马克思主义哲学/第十八章/课程H”下面也隐藏着不为人知的东西。

机械键盘:噼里啪啦的手感和不菲的身价,HHKB是每个程序员的信仰,买不起HHKB的程序员会用国产的机械键盘凑合着用。

iMac或者Macbook Pro:苹果的电脑性能都非常好,编译程序速度非常快。更重要的一点:OS X系统不能玩LOL,避免了浪费写代码的时间。

双显示器:对于前端程序员来说,双显示器不仅是装逼用的,一台竖屏显示器显示WebStorm,而另一台横屏显示器显示Chrome对编程很有帮助的。显示器的价格并不昂贵,昂贵的是能呈 120 度角摆两台显示器的桌子下面的地皮在北上广深杭写字楼里的租金。

人体工程学座椅:五花八门的不正常办公家具包括人体工程学座椅和支持站立编程的桌子等,美其名曰保护程序员的颈椎、腰、屁股和前列腺,受到程序员喜爱的真实原因你懂的。

程序员鼓励师:大多数程序员渴望但不曾拥有过的硬件是只属于自己的程序员鼓励师,换句话说就是在你写代码时红袖添香的女朋友。

6 白盒强迫症

白盒强迫症的常见症状是看见代码就想优化一下。说程序员只怕“error”不怕“warning”是非常错误的,很多程序员见不得黄字和中划线,也见不得蓝色的“// TODO”。

白盒强迫症很多时候都是有益的,可以让代码变得整洁,隐藏的漏洞也会减少。

白盒强迫症的晚期患者每次打开一个网页都要右键查看源代码,已经无法正常上网。

7 黑盒强迫症

黑盒强迫症的常见症状是每次看见闭源的软件都想研究一下里面的原理,再想想自己能不能做得更好。比如用支付宝扫码支付的时候想的是识别二维码、通信加密、支付安全等原理;或者乘坐电梯时看着电梯的按钮面板(现实世界的UI)会开始思考电梯的调度算法,比如多个实例之间状态可以互相影响,还有一些优先级、加速度、预判方面的东西。

黑盒强迫症的晚期症状是看见现实世界中办事的流程都想用算法知识优化一下,常见的是想着如何优化公司报销和升职的审批流程;再举个反面例子,看《人民的名义》或《官场现形记》时都想着怎么优化贪官和奸商的“办事”流程。

8 收藏强迫症

收藏强迫症的症状是在GitHub上看见好源码必star,技术博客上看到好文章必然收藏,没有收藏功能的个人站也要加入收藏夹。收藏虽多,但不会再看。明知如此,还感觉不收藏就会吃亏。

9 身份强迫症

身份强迫症的早期症状就是头脑中“程序员 == 我自己”的概念根深蒂固,看到和程序员有关的话题都要打开看一下,尽管大多数程序员不会因为应勤是程序员就看《欢乐颂2》,但你打开本文一定是因为本文标题有“程序员”。读完本文的患者还会把自己和同事们作为一个数组,本文中 10 种强迫症作为另一个数组,然后在自己的大脑里做一个递归,查查自己和同事们分别中了几枪。

身份强迫症的晚期症状是把现实世界中见到的一切理解为IT知识,忘记了自己在职场外怎么做一个正常人:走火入魔的患者偶然有一天没有在家写代码,出门看见太阳想到的是“单例模式”,看见双胞胎想到的是“拷贝”,看到摩天轮想到的“循环”,看到排队想到的是“队列”。

身份强迫症进入日薄西山阶段的症状是患者已经无法用人类的语言进行交流了,QQ聊天时每句话的最后都要家一个“;”,没错,是半角的分号;更有甚者还会把脏话用“/*”和“*/”框起来,以为对方就看不见了;看见卖西瓜就只买一个包子的程序员听说学姐留学归来,会四门语言的第一反应是问她那四门语言是Java、PHP、Python和JavaScript还是C、C++、C#和Objective-C。

身份强迫症进入回光返照阶段的情况是试图把别的语言、工具、领域的程序员改造成自己同行的程序员,曾高呼“PHP是最好的语言”的程序员在移动互联网时代改行Android后会纠结怎么把iMac或者Macbook Pro屏幕背面的Apple形状的灯改成Android形状的。

如果你读到最后,不但一枪没中,也没把自己身边的朋友和同事套在这十大强迫症上做个递归,那么你一定不是一个程序员。 收起阅读 »

战狼3剧透!!!

   
16783307241313752924.jpg


   冷锋回到中国后尽管已经恢复了军职,还受到了人民的爱戴,冷锋拥有了以前不可能拥有的荣耀,但是他忘不了的还是龙小云,几年后,他费劲千辛万苦终于得到了龙小云的消息,大家都以为龙小云在几年前被反政府武装的雇佣兵杀死了,令人庆幸的是龙小云被南非的救援中心救了下来。

   冷锋的到消息后立马跑去南非找龙小云,可是在欧洲臭名远扬的雇佣兵也知道了这个消息,原来老爹的幕后大咖就是他的父亲飞鱼,飞鱼为了给儿子报仇雪恨竟也来带走龙小云,还出动了大批的先进专备,于是又一轮的世纪大战又开始了。

   冷锋在期间困难重重但他还是咬牙坚持下去了,后来冷锋救回龙小云后,他们决定回到北京生活,不久后他们在北京开了互联网公司,还亲自找环信学习即时通讯的集成,生意做得风生水起!从此,过上了幸福的生活!!![鼓掌][鼓掌][鼓掌]冷锋为了感谢环信,还将那个子弹头送给了环信!你也想他一样嘛!?赶紧报名参加环信的Alpha计划培训吧。

   环信Alpha计划北京场报名已满,参加的小伙伴请选择上海和深圳场,报名地址环信Alpha计划报名
继续阅读 »
   
16783307241313752924.jpg


   冷锋回到中国后尽管已经恢复了军职,还受到了人民的爱戴,冷锋拥有了以前不可能拥有的荣耀,但是他忘不了的还是龙小云,几年后,他费劲千辛万苦终于得到了龙小云的消息,大家都以为龙小云在几年前被反政府武装的雇佣兵杀死了,令人庆幸的是龙小云被南非的救援中心救了下来。

   冷锋的到消息后立马跑去南非找龙小云,可是在欧洲臭名远扬的雇佣兵也知道了这个消息,原来老爹的幕后大咖就是他的父亲飞鱼,飞鱼为了给儿子报仇雪恨竟也来带走龙小云,还出动了大批的先进专备,于是又一轮的世纪大战又开始了。

   冷锋在期间困难重重但他还是咬牙坚持下去了,后来冷锋救回龙小云后,他们决定回到北京生活,不久后他们在北京开了互联网公司,还亲自找环信学习即时通讯的集成,生意做得风生水起!从此,过上了幸福的生活!!![鼓掌][鼓掌][鼓掌]冷锋为了感谢环信,还将那个子弹头送给了环信!你也想他一样嘛!?赶紧报名参加环信的Alpha计划培训吧。

   环信Alpha计划北京场报名已满,参加的小伙伴请选择上海和深圳场,报名地址环信Alpha计划报名 收起阅读 »

看看30万程序员怎么评论:在网吧写代码是怎样一种体验?

今天要给大家分享一个有趣的话题,在网吧写代码是怎样的体验,你想想,你吃着泡面唱着歌,突然电脑就死机了!哈哈,这是一种悲哀 ,我自己没有在网吧写过代码,但是看了论坛上的小伙伴们说的这些趣事,还是挺有意思的:
TIM截图20170810110817.png


TIM截图20170810110919.png


TIM截图20170810110954.png


TIM截图20170810111108.png

TIM截图20170810111131.png

TIM截图20170810111158.png

TIM截图20170810111300.png

116c7861bf9f02ba648912446deae8b0_b.jpg

最后再来给程序员提几点建议:

1.写代码好像没试过,不过那个时候做个人网站,家里没有网,写好代码winzip打包,拷软盘里。找网吧前台小妹放软盘(那个网吧只有前台的电脑有软驱)。共享,在我的机器上拷出来,ftp上传到免费空间。周围和我同龄的孩子们基本都是qq 红警 星际之类的。我一直因为不会打游戏也不会去聊天室和妹纸聊天没法和他们融在一起。在所有人的鄙视甚至类似于今天的类似“装逼”等词汇的鄙视中,完成工作。唯一欣慰的是有几个女生看到我的网站会投来些许崇拜的目光(也仅仅是些许)。

2.程序员工作空闲之余也就是逛逛论坛,上上网,聊聊天。下班时间宅在家里,打打游戏,写写代码,写写博客,很少锻炼身体,以至于某天的头条就有可能是某某公司大老猝死了,所以大伙们懂的。
继续阅读 »
今天要给大家分享一个有趣的话题,在网吧写代码是怎样的体验,你想想,你吃着泡面唱着歌,突然电脑就死机了!哈哈,这是一种悲哀 ,我自己没有在网吧写过代码,但是看了论坛上的小伙伴们说的这些趣事,还是挺有意思的:
TIM截图20170810110817.png


TIM截图20170810110919.png


TIM截图20170810110954.png


TIM截图20170810111108.png

TIM截图20170810111131.png

TIM截图20170810111158.png

TIM截图20170810111300.png

116c7861bf9f02ba648912446deae8b0_b.jpg

最后再来给程序员提几点建议:

1.写代码好像没试过,不过那个时候做个人网站,家里没有网,写好代码winzip打包,拷软盘里。找网吧前台小妹放软盘(那个网吧只有前台的电脑有软驱)。共享,在我的机器上拷出来,ftp上传到免费空间。周围和我同龄的孩子们基本都是qq 红警 星际之类的。我一直因为不会打游戏也不会去聊天室和妹纸聊天没法和他们融在一起。在所有人的鄙视甚至类似于今天的类似“装逼”等词汇的鄙视中,完成工作。唯一欣慰的是有几个女生看到我的网站会投来些许崇拜的目光(也仅仅是些许)。

2.程序员工作空闲之余也就是逛逛论坛,上上网,聊聊天。下班时间宅在家里,打打游戏,写写代码,写写博客,很少锻炼身体,以至于某天的头条就有可能是某某公司大老猝死了,所以大伙们懂的。 收起阅读 »

2017年的八大顶级开源项目

摘要:本文介绍了在开源界比较有名的八个项目。如果你对其中的某个项目不了解的话,赶快来学习一下吧。以下是译文。
原文:Top Open Source Projects In 2017
作者:William Belk 
翻译:雁惊寒

2397007-9583dc6fe2d5d8f2.png

今天,让我们一起来看一下2017年开源界的八个顶级玩家。下面列出的几个开源项目反映了开源社区在过去几年来发展的成熟度。这里列出的所有项目(Lab41除外)都是在2014年及以后发布的,每个项目都在各自的社区里发挥着重要的作用。
 
TensorFlow

Google的TensorFlow发布于2015年,它是一个可扩展的基于神经元的机器学习库。我们可以使用TensorFlow构造流水线来对图像和文本这类东西进行分类,甚至还可以构造出更复杂的问题场景,例如“X类型的用户会买Y吗?”。

许多行业目前对于机器学习的研究或应用还只是流于表面。尽管在我们的意识中一直认为自己可以用AI来实现任何目的,但机器学习还是会受到计算资源和数据训练的限制。在未来的几年里,数据的训练可能依然是大家忽略的问题,许多人低估了能够解决复杂问题所需的可靠训练数据的数量。也就是说,机器学习是为真实场景服务的,并且会很快出现在我们每天使用的很多应用程序之中,隐匿于应用程序的底层。我们还将看到许多有趣的项目和展望,这些来源于机器学习的东西说明了目前还存在着太多的公开数据可供使用。

如果你想了解更多有关TensorFlow的内容,请查阅这篇来自于Google的博文

Hyperledger

Hyperledger发布于2015年,由Linux基金会赞助,旨在推动区块链技术在未来商业的应用。 Hyperledger开发了模块化的工具,可以作为分布式区块链基础来解决各种商业问题,包括合同安全、匿名账户和身份管理,以及基于社区的历史交易记录。

Hyperledger已经使得IBM、思科、红帽、VMWare,摩根大通、富国银行、埃森哲等公司对其产生了巨大的兴趣。

Node.js / React Native

我们得承认 Node.js 社区的胜利,它现在无处不在。Node.js使得新一代程序员在服务器端编码方面摆脱了束缚。我们在谈论React Native的时候,不能不承认Node.js将继续在软件工程领域保持强劲的势头,特别是对于消费者和移动应用。

React Native于2015年推出,并且许下了一个美好的愿望:只使用一个代码库就能将应用程序部署到多个平台上。例如,使用单个代码库来为苹果iOS、Android和Web编译应用程序。

这为什么是一个诱人的想法呢?对于消费者网站而言,我们可以使用最常用的语言:javascript。我们无需把团队根据不同语言的特点拆分开来,例如javascript、ruby/python/php、java、Objective C。我们可以快速地进行构建。我们可以利用本地设备组件来解决像图像处理这样的“硬骨头”。我们可以只维护单个应用程序,然后将其核心应用分发到每一个需要的平台上。

React Native还有哪些酷炫的地方呢? 应用广泛,就像Facebook、特斯拉、Airbnb、Instagram、腾讯、彭博和Uber一样。

Dolores
 
Dolores是一套“可定制”、“可私有化部署”的OA办公系统,一套完整的企业通信解决方案,一个完整的企业沟通工具(以下简称企业IM),支持以下几个功能:IM消息服务、组织架构管理、工作流集成。

   公司想自己开发一套IM系统应该从哪里开始呢? 企业通讯录怎么保持同步呢? 企业通讯录的权限管理应该怎么做?
   三个关于OA办公系统的究极问题,从开源的OA办公项目-Dolores(朵拉)诞生迎刃而解了。Dolores项目遵循Apache Licence 2.0 开源协议,可以直接拿来用,也可以修改代码来满足需要并作为开源或商业产品发布/销售。

Kubernetes

当Google在2014年发布Kubernetes的时候,这个项目的前途看起来很光明。该项目的目标非常远大,试图解决在多个层次、组和角色之间对分布式服务器容器协调的问题。例如,一家公司可能在四个城市的三个环境层(开发、预备、生产)上运行了200多个容器,这管理起来非常头疼。

我们必须要承认,在过去的几年里,虚拟服务器协作在大型企业的复杂部署中占有举足轻重的地位。这是Amazon Web Services目前如此成功的其中一个原因。即使像Docker这种虚拟化的容器部署逐渐兴起,但问题依然存在。公司必须依靠脆弱的开源项目、昂贵的专有平台或者依靠广泛的内部工具来管理虚拟集群和容器。

在大规模的容器协作方面,Kubernetes似乎明显处于领先地位,并与纽约时报、高盛、SoundCloud、Box、Comcast 和 易趣 等用户建立了合作关系。

Lab41
Lab41是一个“挑战实验室”,在那里美国情报界与他们在学术界工业界中的同行一起处理大数据。


虽然Lab41本身并不是一个开源项目,但它提出了一些有趣的问题,进而引出了一些开源代码,并对开源社区做出了一定的贡献。它展示了开源原则、风险投资和政府优先事项的交叉点,这是一个非常独特的东西。

Vault
Vault可以保护、存储和严格控制对现代计算中的令牌、密码、证书、API密钥和其他机密内容的访问。


如果你看看下面这张有关全球数据泄露的交互信息图的话,就能马上理解为什么Vault如此重要了。
2397007-76533d0347436258.png


凡信
凡信是一个开源的高仿微信项目,截止目前已经更新了3个大版本,从基础的好友聊天做起,到朋友圈、红包功能等功能愈发完善,直播、阅后即焚等新功能层出不穷,整个项目完全免费,Android/ios/服务端所有代码全部开源。

 由于凡信的1.0和2.0都是基于环信SDK 2.x系列开发,而当前环信官方力推的是3.x的系列SDK,在此背景下,作者决定将凡信迁移至3.x的demo上。迁移的同时,对存储机制和网络接口做了一定的优化。与此同时,针对时下火热的直播APP,结合环信的聊天室功能和ucloud,做了两个模块-观看直播和进行直播;针对IM场景中常见的发红包/抢红包,集成了由环信提供的红包SDK,对于想做红包以及账户管理的开发者,是一种非常值得推荐的解决方案,一是开发者不用头疼于安全问题,以及开发中逻辑不严谨导致的资金转移丢包的问题。
继续阅读 »
摘要:本文介绍了在开源界比较有名的八个项目。如果你对其中的某个项目不了解的话,赶快来学习一下吧。以下是译文。
原文:Top Open Source Projects In 2017
作者:William Belk 
翻译:雁惊寒

2397007-9583dc6fe2d5d8f2.png

今天,让我们一起来看一下2017年开源界的八个顶级玩家。下面列出的几个开源项目反映了开源社区在过去几年来发展的成熟度。这里列出的所有项目(Lab41除外)都是在2014年及以后发布的,每个项目都在各自的社区里发挥着重要的作用。
 
TensorFlow

Google的TensorFlow发布于2015年,它是一个可扩展的基于神经元的机器学习库。我们可以使用TensorFlow构造流水线来对图像和文本这类东西进行分类,甚至还可以构造出更复杂的问题场景,例如“X类型的用户会买Y吗?”。

许多行业目前对于机器学习的研究或应用还只是流于表面。尽管在我们的意识中一直认为自己可以用AI来实现任何目的,但机器学习还是会受到计算资源和数据训练的限制。在未来的几年里,数据的训练可能依然是大家忽略的问题,许多人低估了能够解决复杂问题所需的可靠训练数据的数量。也就是说,机器学习是为真实场景服务的,并且会很快出现在我们每天使用的很多应用程序之中,隐匿于应用程序的底层。我们还将看到许多有趣的项目和展望,这些来源于机器学习的东西说明了目前还存在着太多的公开数据可供使用。

如果你想了解更多有关TensorFlow的内容,请查阅这篇来自于Google的博文

Hyperledger

Hyperledger发布于2015年,由Linux基金会赞助,旨在推动区块链技术在未来商业的应用。 Hyperledger开发了模块化的工具,可以作为分布式区块链基础来解决各种商业问题,包括合同安全、匿名账户和身份管理,以及基于社区的历史交易记录。

Hyperledger已经使得IBM、思科、红帽、VMWare,摩根大通、富国银行、埃森哲等公司对其产生了巨大的兴趣。

Node.js / React Native

我们得承认 Node.js 社区的胜利,它现在无处不在。Node.js使得新一代程序员在服务器端编码方面摆脱了束缚。我们在谈论React Native的时候,不能不承认Node.js将继续在软件工程领域保持强劲的势头,特别是对于消费者和移动应用。

React Native于2015年推出,并且许下了一个美好的愿望:只使用一个代码库就能将应用程序部署到多个平台上。例如,使用单个代码库来为苹果iOS、Android和Web编译应用程序。

这为什么是一个诱人的想法呢?对于消费者网站而言,我们可以使用最常用的语言:javascript。我们无需把团队根据不同语言的特点拆分开来,例如javascript、ruby/python/php、java、Objective C。我们可以快速地进行构建。我们可以利用本地设备组件来解决像图像处理这样的“硬骨头”。我们可以只维护单个应用程序,然后将其核心应用分发到每一个需要的平台上。

React Native还有哪些酷炫的地方呢? 应用广泛,就像Facebook、特斯拉、Airbnb、Instagram、腾讯、彭博和Uber一样。

Dolores
 
Dolores是一套“可定制”、“可私有化部署”的OA办公系统,一套完整的企业通信解决方案,一个完整的企业沟通工具(以下简称企业IM),支持以下几个功能:IM消息服务、组织架构管理、工作流集成。

   公司想自己开发一套IM系统应该从哪里开始呢? 企业通讯录怎么保持同步呢? 企业通讯录的权限管理应该怎么做?
   三个关于OA办公系统的究极问题,从开源的OA办公项目-Dolores(朵拉)诞生迎刃而解了。Dolores项目遵循Apache Licence 2.0 开源协议,可以直接拿来用,也可以修改代码来满足需要并作为开源或商业产品发布/销售。

Kubernetes

当Google在2014年发布Kubernetes的时候,这个项目的前途看起来很光明。该项目的目标非常远大,试图解决在多个层次、组和角色之间对分布式服务器容器协调的问题。例如,一家公司可能在四个城市的三个环境层(开发、预备、生产)上运行了200多个容器,这管理起来非常头疼。

我们必须要承认,在过去的几年里,虚拟服务器协作在大型企业的复杂部署中占有举足轻重的地位。这是Amazon Web Services目前如此成功的其中一个原因。即使像Docker这种虚拟化的容器部署逐渐兴起,但问题依然存在。公司必须依靠脆弱的开源项目、昂贵的专有平台或者依靠广泛的内部工具来管理虚拟集群和容器。

在大规模的容器协作方面,Kubernetes似乎明显处于领先地位,并与纽约时报、高盛、SoundCloud、Box、Comcast 和 易趣 等用户建立了合作关系。

Lab41
Lab41是一个“挑战实验室”,在那里美国情报界与他们在学术界工业界中的同行一起处理大数据。


虽然Lab41本身并不是一个开源项目,但它提出了一些有趣的问题,进而引出了一些开源代码,并对开源社区做出了一定的贡献。它展示了开源原则、风险投资和政府优先事项的交叉点,这是一个非常独特的东西。

Vault
Vault可以保护、存储和严格控制对现代计算中的令牌、密码、证书、API密钥和其他机密内容的访问。


如果你看看下面这张有关全球数据泄露的交互信息图的话,就能马上理解为什么Vault如此重要了。
2397007-76533d0347436258.png


凡信
凡信是一个开源的高仿微信项目,截止目前已经更新了3个大版本,从基础的好友聊天做起,到朋友圈、红包功能等功能愈发完善,直播、阅后即焚等新功能层出不穷,整个项目完全免费,Android/ios/服务端所有代码全部开源。

 由于凡信的1.0和2.0都是基于环信SDK 2.x系列开发,而当前环信官方力推的是3.x的系列SDK,在此背景下,作者决定将凡信迁移至3.x的demo上。迁移的同时,对存储机制和网络接口做了一定的优化。与此同时,针对时下火热的直播APP,结合环信的聊天室功能和ucloud,做了两个模块-观看直播和进行直播;针对IM场景中常见的发红包/抢红包,集成了由环信提供的红包SDK,对于想做红包以及账户管理的开发者,是一种非常值得推荐的解决方案,一是开发者不用头疼于安全问题,以及开发中逻辑不严谨导致的资金转移丢包的问题。 收起阅读 »

春华秋实,环信Android/ios V3.3.4SDK发布,同一账号可在电脑手机间互传消息与文件

春华秋实,听说秋天APP和环信更配!环信发布了V3.3.4版本SDK ,同一账号可在电脑手机间互传消息与文件,并增加消息撤回接口和回调,同时Android端更新了新版环信推送(HMS)。


微信图片_20170807161714.jpg


Android V3.3.4 2017-08-04新功能
  • 新增加API请查看链接3.3.4api修改
  • 增加接口支持获取历史消息(消息漫游);
  • 新增PC与移动端互发消息和文件的功能;
  • 增加消息撤回的接口和回调;
  • 支持华为新版推送功能(HMS);

ios V3.3.4 2017-08-04
新功能:
  • 新增:PC端和手机端登录同一个账号,两个设备之间互发消息;
  • 新增:消息漫游,从服务器分页获取历史消息;
  • 新增:消息撤回。


功能修复及优化:
  • 优化删除一组会话时,回调只返回一次;
  • iOS SDK不再支持i386;
  • 修复录制音频文件时,音频权限判断。

 版本历史:Android SDK更新日志  ios SDK更新日志
下载地址:SDK下载
继续阅读 »
春华秋实,听说秋天APP和环信更配!环信发布了V3.3.4版本SDK ,同一账号可在电脑手机间互传消息与文件,并增加消息撤回接口和回调,同时Android端更新了新版环信推送(HMS)。


微信图片_20170807161714.jpg


Android V3.3.4 2017-08-04新功能
  • 新增加API请查看链接3.3.4api修改
  • 增加接口支持获取历史消息(消息漫游);
  • 新增PC与移动端互发消息和文件的功能;
  • 增加消息撤回的接口和回调;
  • 支持华为新版推送功能(HMS);

ios V3.3.4 2017-08-04
新功能:
  • 新增:PC端和手机端登录同一个账号,两个设备之间互发消息;
  • 新增:消息漫游,从服务器分页获取历史消息;
  • 新增:消息撤回。


功能修复及优化:
  • 优化删除一组会话时,回调只返回一次;
  • iOS SDK不再支持i386;
  • 修复录制音频文件时,音频权限判断。

 版本历史:Android SDK更新日志  ios SDK更新日志
下载地址:SDK下载
收起阅读 »

月薪五千和五万销售的区别:一只丑桔引发的大单子(环信真实案例改编)

​​ 
timg.jpg

 这是一个初冬的早晨。王向东迈着轻快的步伐,走进了“黄桃园”集团大楼,直奔物业管理公司CEO陶福成办公室。与陶总交换名片后,陶总看着名片,抬头说:“你就是那个什么环信公司的销售经理?你在电话上说有一笔大生意要谈?简单说说吧,我只有十分钟时间。”陶总抬手看了眼手表。

王向东从包里拿出一只丑桔,放到大班台上,说:“这是丑桔,想必陶总吃过。”陶总微微点了下头。“我要和陶总谈的生意与丑桔有关。”陶总好奇地问:“我一个物业公司,怎么会和丑桔生意有关呢?”

“我先问陶总一个经营上的问题。现在由于人工费用上涨很快,物业公司从业主收来的物业费却多年没有做相应的调整,物业公司的利润逐年下滑,甚至出现亏损,不知是不是属实?”陶总点了下头,心里却想你个毛头小子还和我说盈亏,真不知天高地厚。

“所以物业公司不得不想别的办法,拓展收入来源来弥补物业费的亏空。”陶总一笑:“所以你想推荐丑桔生意?”王向东指着台上的丑桔说:“是的!咱们算笔账。陶总物业公司管理着三个高档小区,一共有3万2千住户。”陶总眼睛从半眯状到睁大状。“丑桔是新开发的一个水果品种,口味独特,很受欢迎,超市里卖到24块每公斤。如果能以18块每公斤卖给您的住户,想必一定卖的很好。如果直接和原产地进货,进货价格是10块每公斤,这样的话毛利是8块每公斤。假设有1万5千住户每户购买一箱20公斤,总共30万公斤,毛利240万。”陶总深深点了下头:“240万不少,但对于我这样的物业公司来说,还真不是什么了不起的收入。”

“如果我说丑桔贡献240万,精品东北大米贡献300万,陕西红富士苹果贡献300万。。。。。。这些收入合起来贡献2000万毛利,够不够大?”“够大!但是我要把这个生意做成,需要店面,仓库,运输,配送,押款。。。。。。费用支出多大,你知道吗?”

“知道。但如果我有办法把这些费用降到零呢?”陶总瞪大了眼睛:“什么办法?”“就是利用移动互联技术,构建客服平台,起到一石三鸟作用。”“哪三鸟?”“一是解决咱们物业管理老本行与住户的交流和住户服务请求和相应;二是形成电子商务平台,网上推广产品;三是网上缴费,既交物业费,又是电子商务资金流通道。”

陶总站起来,拉住王向东的手:“快说说,你能帮我建设这个什么客服平台吗?”“可以,环信就是这方面的专家。”

陶总快步走到门口,对秘书说:“马上通知总裁办主任,客服部主管,IT部主管,财务部主管到我这里开会!”

几分钟后,主管们到齐。陶总说:“来,跟大家介绍一下这位小兄弟,王向东,他可是给我们带来了好东西,先听听他的介绍。”王向东站起来谦逊地个跟每个主管打了招呼,才坐下简要地介绍了刚才跟陶总交流的内容。陶总站起来说:“王兄弟带来的方案,揭开了困扰我们好长时间的难题,有了这个客服平台,可以大幅度提高我们的物业服务质量,同时开辟了扩大收入的渠道,是个非常有价值的建议。我要求你们和小王兄弟一起尽快拿出方案,做出预算,在2个月内上线!”

所有主管都响亮地答应下来,同时心里在猜测这位“小王兄弟”后台有多硬,是陶总的什么关系?

没过几天,方案出来了,预算也出来了。一期先建设即时通讯软件平台和客户交互平台,建设费用320万;二期建设智能客服机器人系统,建设费用180万;采用vpc形式,每年支付环信托管费用50万;环信提供战略和业务咨询,每年咨询费40万。

一个由丑桔引起的“大单子”就这么发生了!(由环信真实销售案例改编,文中均为化名)
继续阅读 »
​​ 
timg.jpg

 这是一个初冬的早晨。王向东迈着轻快的步伐,走进了“黄桃园”集团大楼,直奔物业管理公司CEO陶福成办公室。与陶总交换名片后,陶总看着名片,抬头说:“你就是那个什么环信公司的销售经理?你在电话上说有一笔大生意要谈?简单说说吧,我只有十分钟时间。”陶总抬手看了眼手表。

王向东从包里拿出一只丑桔,放到大班台上,说:“这是丑桔,想必陶总吃过。”陶总微微点了下头。“我要和陶总谈的生意与丑桔有关。”陶总好奇地问:“我一个物业公司,怎么会和丑桔生意有关呢?”

“我先问陶总一个经营上的问题。现在由于人工费用上涨很快,物业公司从业主收来的物业费却多年没有做相应的调整,物业公司的利润逐年下滑,甚至出现亏损,不知是不是属实?”陶总点了下头,心里却想你个毛头小子还和我说盈亏,真不知天高地厚。

“所以物业公司不得不想别的办法,拓展收入来源来弥补物业费的亏空。”陶总一笑:“所以你想推荐丑桔生意?”王向东指着台上的丑桔说:“是的!咱们算笔账。陶总物业公司管理着三个高档小区,一共有3万2千住户。”陶总眼睛从半眯状到睁大状。“丑桔是新开发的一个水果品种,口味独特,很受欢迎,超市里卖到24块每公斤。如果能以18块每公斤卖给您的住户,想必一定卖的很好。如果直接和原产地进货,进货价格是10块每公斤,这样的话毛利是8块每公斤。假设有1万5千住户每户购买一箱20公斤,总共30万公斤,毛利240万。”陶总深深点了下头:“240万不少,但对于我这样的物业公司来说,还真不是什么了不起的收入。”

“如果我说丑桔贡献240万,精品东北大米贡献300万,陕西红富士苹果贡献300万。。。。。。这些收入合起来贡献2000万毛利,够不够大?”“够大!但是我要把这个生意做成,需要店面,仓库,运输,配送,押款。。。。。。费用支出多大,你知道吗?”

“知道。但如果我有办法把这些费用降到零呢?”陶总瞪大了眼睛:“什么办法?”“就是利用移动互联技术,构建客服平台,起到一石三鸟作用。”“哪三鸟?”“一是解决咱们物业管理老本行与住户的交流和住户服务请求和相应;二是形成电子商务平台,网上推广产品;三是网上缴费,既交物业费,又是电子商务资金流通道。”

陶总站起来,拉住王向东的手:“快说说,你能帮我建设这个什么客服平台吗?”“可以,环信就是这方面的专家。”

陶总快步走到门口,对秘书说:“马上通知总裁办主任,客服部主管,IT部主管,财务部主管到我这里开会!”

几分钟后,主管们到齐。陶总说:“来,跟大家介绍一下这位小兄弟,王向东,他可是给我们带来了好东西,先听听他的介绍。”王向东站起来谦逊地个跟每个主管打了招呼,才坐下简要地介绍了刚才跟陶总交流的内容。陶总站起来说:“王兄弟带来的方案,揭开了困扰我们好长时间的难题,有了这个客服平台,可以大幅度提高我们的物业服务质量,同时开辟了扩大收入的渠道,是个非常有价值的建议。我要求你们和小王兄弟一起尽快拿出方案,做出预算,在2个月内上线!”

所有主管都响亮地答应下来,同时心里在猜测这位“小王兄弟”后台有多硬,是陶总的什么关系?

没过几天,方案出来了,预算也出来了。一期先建设即时通讯软件平台和客户交互平台,建设费用320万;二期建设智能客服机器人系统,建设费用180万;采用vpc形式,每年支付环信托管费用50万;环信提供战略和业务咨询,每年咨询费40万。

一个由丑桔引起的“大单子”就这么发生了!(由环信真实销售案例改编,文中均为化名) 收起阅读 »