这是一篇长文,需要你有耐心看完,看前或者看后最好自己动手实践一下。
前段时间有和一个在北美的读者交流,他提到去Facebook面试的一些经历,希望我能写一个关于“如何设计一个照片上传App”的主题,因为他不太清楚面试官让面试者直接设计一个应用,主要想考察哪方面的能力。
其实大家可以站在面试官的角度想一下,如果只是问一些技术点的面试题,面试官能获得什么呢?
也许只是知道面试者哪个技术点不熟悉,哪个理解错误,那个比较常用,那个能举一返三。如果只就一个点问的话,往往只能得到面试者对于一些表面知识的认识程度。但我们知道现实中或项目中的问题往往不是孤立存在的,它们是一个复合的整体,所以有时候我们需要考察一些“隐性知识”。
而让面试者设计一个真实的App,是考察面试者对Android和应用设计开发的隐性知识掌握程序的最简单有效的手段。
和隐性知识相对应的词叫“显性知识”,诸如Activity的生命周期,四大组件的特性等都是显性知识,而如何运用和融汇这些特性就需要你具备一定的隐性知识了。说白了,隐性知识就是你应该会但是“课本”或者“文档”又没有直接告诉你的知识,比如知识之间的联系、对比或者差别等,拥有更多的隐性知识其时也是高手的特征之一。
面试题:如何设计一个照片上传app?
那这个题,我们一改常态,不用之前的面试题的分析套路。而是把自己放在一个面试官的角度,自己先实现一次这个App,然后自己总结一下你在这次实现中需要哪些能力、需要注意哪些事项。最后,再回过头来看,如果你是面试官,你希望面试者怎么回答才算是符合你的标准的?
实现案例
每个人的实现的方式都不一样,所以你其实可以不看我写的。直接动手再说。
还是先说一下我的思路。先把需求整理一下,“如何设计一个照片上传的App”,虽然题目只有简单的一句话,但我们要将它细化一下来看。
即然能上传,那就一定能浏览对吧,不然不太好确定上传成功以否(弹出上传成功的提示,而没有跳到浏览的界面,显然是不太友好且也不符合用户的习惯)。
即然能浏览,那就要有一个列表或网格(如Gallery)的样式进行,那么需要一些滑动之类的动画效果。那么为了配得起这些效果,界面的UI设计就不能太糟糕吧?
即然有列表了,那么就得有专门查看一张图片详情的界面。
。。。。。。
我们把这些主要的需求罗列一下:
- 可以浏览用户已经上传到服务器的图片;
- 可以查看某张图片的详情;
- 选择和编辑要上传的图片;(从本地或者摄像头获取图片)
- 工作线程上传一张图片到服务器;
陷性的需求:
- 框架的设计:UI和逻辑的分层设计,错误处理机制 (这点其实很重要)
- 性能要求:列表要滑动顺畅,不会出现OOM
- 应对需求变代的可扩展性:是否需要加入用户登录和注册?每张图片是否可以点赞或者添加评论?是否要加上保存和收藏图片功能?
可以还会有很多需求,如在编辑图片时添加滤镜等图片处理效果;搜索、定位、个人偏好的算法等等。
其实,需求还没有完。接收图片的服务器,是第三方的还是需要我们自己写一个呢?如果是第三方的,可能会涉及使用一些他们定的REST接口或者SDK,如Instagram。
而且如果是第三方的话,还需要涉及登录和授权之类的工作。
为了让大家了解整个过程,所以这里,我实现一个自己的服务器用来提供图片的展示和上传服务。
Node.js实现图片管理服务器
可能还需要支持:断点续传、多文件同时上传。不过我的Demo里做了一个简化,没有实现这两个功能,留给读者自己去完善吧。
Node.js服务端的设计请参考这篇文章:如何设计一个照片上传App--Node.js篇
Android客户端
我简单写了一个示例代码放在Github上,主要是用来测试和服务端的接口,实现在Android端通过OKHttp上传图片。上传进度通过扩展OKHttp来实现进度信息的获取,这样相对简单,不需要服务端那边提供额外的接口。
没有加入MVP或者MVVM的框架,一是为了简化代码(不增加大家的阅读难度),二是这个Demo主要是为了给大家展示和Node.js服务端的配合使用。
当你可以很简单就打造自己的服务端时,你的移动端设计和开发才不会那么受制于人。但是,比较完整的实现还是需要你自己动手的。
因为,我这里往往都没有面试题的直接答案。
Github示例:AndroidUploadImageDemo
示例中使用到的一些第三方库:
图片库Glide:https://github.com/bumptech/glide
网络请求封装Retrofit2:http://square.github.io/retrofit
Json数据转换Gson:https://github.com/google/gson
回到面试题
我们先来总结一下,经历这次实现过程,你觉得开发涉及到了哪些技术点或者模块,在开发中需要注意哪些事项?
相关的模块和涉及的技术点:
- Retrofit做网络请求和解析(Gson);
- Http文件上传的协义;
- 图片浏览的性能优化或者遇到的问题:如图片库的加载和ListView的展示配合,RecyclerView瀑布流展示页面跳动等问题;
- 框架的设计:UI和逻辑的分离问题;
- 无网或网络异常时的处理;
......
上面的这些,你实际动手就会遇到,要么你去解决它们,要么你可以选择其他的方式来回避它们。比如,针对性能问题,如果你只测几十张图片,可能没有什么优化的必要,但如果你在Node.js端放1000+张照片,在这样的情景下,你就有必要来改善移动端的展示性能了(而解决的方案可以根据自己的需求来定:如Node.js端加个接口,分页返回列表数据等)。
针对这类题,面试官可能会你让亲自动手实现,需要你在规定的时间内给出一个源码工程(可以更直观看到你的代码风格);也可能只是让你谈谈你的设计思路,或者可能遇到的困难的解决方案。这样题更主要是要考察面试者的综合能力。
如果你没有实际做过,那么你应该怎么回答这个面试题呢?
第一,和对方交流清楚,确定理解面试官关注和考察的重点;
第二,尽可能在谈设计思路时考虑到一些实际问题(边界、异常等),这方面的经历其实正是面试官想看到的;
第三、从用户的角度去展开和设计这个应用;
小结
恭喜你是一个有耐心的人,可以看到最后的小结部份。遗憾的是,这篇面试题没有小结,因为你亲自动手后会得到自己的小结,所以,留给你自己去总结吧。