IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

iOS到Android到底有多远

jaminzzhang 2016-02-20 11:46:24 累计浏览 4,273 次
本机暂存

在iOS开发混了4年之后,又重拾荒废了4年的Android,感慨时间过得太快,有时间我会回顾下2010当年的iOS/Android平台的萌芽期历史;

从重拾摸索,再到上线两个App,四五个月时间。这段时间的学习和研究,颇多冲击和体会,所以就有了这篇文章。本文主要从iOS转Android开发角度,对比两个平台应用开发的异同。希望对想学习Android开发的iOS开发者,或者想兼Android、iOS开发的同学,有所帮助。另,Objc也做过一期Android的专题,讲的还可以:objc#Android#




1 语言

从iOS到Android开发,首先遇到的难题就是编程语言的改变,由于在大学时,跟着实验室老师做项目就是用Java写J2EE,所以Java的基础知识还记得,简单看看代码基本就上手了。

编程语言的争论对比由来已久,本文并不想引发月经般的口水战,没有全能的语言,只能说在不同语言有不同的适应场景。作为比Java早生整整13年的Objective-C(Objective-C: 1982, Java: 1995,来源于Wiki),整体上来说,在语言特性方面落后于Java太多,那么多年才发展到版本2,而Java已然来到了版本9。从iOS到Android,对比Objective-C和Java,更深刻理解Objective-C语言的局限性:


1.1 泛型

泛型是现代编程语言非常重要而有用的特性,能够提高代码复用率,并约束参数类型提高安全性。泛型是一个非常强大特性,以至于有泛型编程这以课题。可惜Obective-C直到前不久的iOS9发布,才更新对Collection类型支持泛型(官方文档并没有太多的说明泛型,自建类也是可以模仿Collection的泛型来实现泛型的支持,但支持得并不太理想);


1.2 枚举

Objective-C是C的超集,完全兼容C语言,所以其枚举还一直沿用着C语言的枚举,但现有的面向对象的高级语言,已经将枚举从一个基本数据类型升级为类,这大大增强了枚举的扩展性。如OC的枚举只能是整型类型,如果需要获得枚举对应的数据(如枚举的名称),只能自己添加映射的代码;但Java的枚举,可以扩展出字段name,来对应枚举的名称;


1.3 抽象abstract

抽象类和抽象方法是OOP中重要的概念,而OC一直没有支持该特性,这对于面向对象的抽象封装是非常大的限制。


1.4 方法访问控制

OC无法使用public/private/protected/final等关键字来控制方法的访问权限。这其实是由OC是动态语言所决定的。从根本上来说,OC是不存在private方法的,因为所有的方法都可以用performSelector来进行访问,当然Java也可以通过反射实现类似的功能,所以从安全性上来说是基本一致的,不同的只是模块封装。

当然,跟Java相比,OC也有非常多的优势,如比GC更高效的内存管理,更简单易用的多线程,更为明确的语义风格等。但从长远来看,OC已落后Java一个身位,跟不上当前iOS/OSX系统的发展,而由于设计理念和历史包袱存在,重新发明一种新的编程语言势在必行,才有了Swift的横空出世、应运而生。Swift确实是新一代的编程语言,吸收了多种面向对象高级编程语言以及脚本语言的优点。随着Swift 2.0的发布并开源,该语言日趋稳定,建议iOS开发同学可以开始深入学习了,Swift替换Objective-C,很可能比你想象的要快。

反观Android这边,Java方兴未艾,而Go作为Google的明星编程语言,去年开始支持Android NDK的开发,而并没有取代Java的计划;以Java现有的基数以及在服务端的占有率,Go想在要在Android平台上取代Java,可能需要等到Go在Server端超过Java才有可能。



2 系统平台

不管是Windows、iOS、Android还是Blackberry,做应用开发都只能依托于这些系统平台,能做的不能做的,都由平台决定。这既是开发者的福利,也是开发者的悲哀。福利是因为有个完善的平台,开发者能够很容易就能够实现一些复杂的功能,如GPS、陀螺仪、图片处理等;说是悲哀,是开发者已经限定在这个平台的圈子内,就像人的生死,平台已有生死,当一个平台灭亡时,往往有一大批的开发者要么一起死亡,要么面临转型。所以,优秀的开发者都不应该禁锢在某个平台上,多去思考和学习与平台不相关的技术思想。iOS/Android有一天也会像Smbian一样死去,但多线程、算法、内存管理、网络、设计模式这些思想不会死去;也许OpenGL/OpenCV等也会死去,但图形算法不会;就像今天Objective-C正慢慢被Swift取代,但Cocoa库还是在传承。

从iOS到Android,除了语言这一最直观的差异之外,还有系统平台上的差异。开发iOS应用 ,和开发Android应用之间,有哪些平台设计上的异同呢?


2.1 Context

在开发Android应用过程中,你会发现,不管是第三方库还是系统的API,基本都会有Context做为初始化的参数,或者是传递参数:如public TextView(Context context)SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) 等;

Context,故名思议,就是程序的上下文,在Android开发中,主要有Application、Activity、Service、BroadcastReceiver、ContentProvider这几种Context,类图如下:

Context

引自http://blog.csdn.net/qinjuning/article/details/73106


具体的相关实现这里不赘述,很多的API,之所以引用context,主要是为了取得整个App的上下文。任何继承Context抽象类的类实例都可以通过getApplicationContext()来获取应用程序的上下文,用于访问应用相关资源。查看android.content.Context.java的源代码,其接口所实现的功能主要是访问如安装包、资源包、图片、字符串、通知等应用相关资源。因此,假如你需要访问这些资源,要么继承ContextWrapper,要么使用context来进行初始化(参数传递)。

在这一方面,iOS采用了去中心化的方式。iOS将访问资源都进行了模块划分及封装,如使用使用[NSBundle mainBundle]访问应用程序包资源;可以使用NSSearchPathForDirectoriesInDomains()来查找路径;如取应用内图片,Android需要由context取:context.getResources().getDrawable(id),而iOS则是[UIImage imageNamed:@“image_name"]等。两种方式对比,个人觉得各有优劣:iOS访问更为方便,设计上有更大的自由度;而Android则让访问比较可控。


2.2 Activity

Activity就相当于iOS的ViewController,用法也基本上大同小异,上一节(Context)也介绍了Activity是继承自Context。与iOS的ViewController的差异,主要有以下几点:

1)与iOS的UIViewController需要App内部使用UINavigationController来管理不同,Android自己管理了Activity栈,用户操作进入某个新的界面,一般会push一个新的Activity到栈顶,而用户按Android的返回键,最顶的Activity会被Pop。具体的栈管理机制,可以查看文档《Tasks and Back Stack

2)UIViewController可以嵌套多个UIViewController,但Activity一般不能嵌套多个Activity。说一般,是因为之前Android有个ActivityGroup的组件,可以实现嵌套。但该组件在API level 13 已被废弃。现在一般使用 Fragment 实现不同界面组合嵌套。


2.3 Intent

Intent,官方文档的描述: an abstract description of an operation to be performed。是用来向其他App组件请求操作的消息对象。简单的来说,Intent就是封装数据和Action的消息体。主要用于:

1)启动一个Activity: startActivity(Intent intent, Bundle options);

2)发送广播: sendBroadcast(Intent intent)

3)启动服务: startService(Intent intent)

在iOS方面,并没有与Intent相对应的组件,iOS并没有封装消息体,一般都是使用Dictionary来传递信息,而切换到新的ViewController,一般都是直接通过接口约定好的对象参数来传递。

另外,Intent一般使用Extras来传递Action所需要的附加信息数据,而Extras中的数据类型只能是基础数据类型、字符串和序列化(Serializable/Parcelable)数据,而不支持其他对象数据直接传递,主要原因是Intent不只是为用于进程内的传递,也支持跨进程传递,所以无法直接传递对象。如果需要传递对象数据,就需要让对象的类实现(Serializable/Parcelable)序列化接口,由于Serializable序列化性能较低,推荐使用Parcelable。但由于Java是自动支持Serializable,所以实现Serializable非常方便,只需要在类中声明实现Serializable接口就可以了;而Parcelable就要复杂多了。希望Android能够改进这一点。

2.4 其他

当然,两个平台设计上有较大差异的地方绝对不止上述几处,本文只简叙了常用的几种场景,更多差异对比,等待你深入挖掘体会。


3 架构

所幸的是,我在开发出了iOS版应用之后开发Android版的,所以架构基本上可以直接沿用,只需要针对相应的语言特性做一些调整。现有的移动应用,基本都是从典型的MVC架构上来衍生或者演变,无论在iOS流行的MVVM还是Andorid上流行的MVP,本质上没有太大的差别,而(MV)VM与(MV)P相比,更倾向于数据绑定而已。

架构,其实就是对软件整体结构和组件的抽象,最终的目的,都是通过解耦来实现软件的健壮性、扩展性和可维护性等。虽架构设计是脱离语言的结构抽象,但实现架构设计还是要依赖于平台,最终落实到语言实现;


3.1 架构范式(architectural pattern):

前面已经说了,无论iOS还是Android,MVC都是这两个平台应用的基本架构设计范式,以下两张图可以说明一切:

iOS的MVC:

iOS MVC


Android的MVC

Android

上图略有不同(在于Model与View的交互,标准的MVC中,两者是有交互的,但实现中,两者的交互比较少),但基本逻辑是一致的,都可以一一代入。所以,无论是iOS开发工程师转Android,或者是Android开发工程师转iOS,只要过了语言关,看几个示例,基本就理解了一个App的大体架构。


3.2 接口

两个平台基本没有太大的差别,由于Android支持泛型和抽象类,所以Android的接口设计会比较灵活。这种灵活性,只有深入使用体验才会有深的体会,这里不深入讲解。但架构设计中,往往会忽略的就是接口的规范性和一致性。将接口进行统一的规范,会让整个架构实现变得非常一致,团队的每一个人只要了解了一个模块的架构设计,就基本了解了全局架构计。这主要体现在:

  • 命名一致:如,获取数据的方法,是使用 getXxxx(callBack),还是用 fetchXxxx(callBack)/loadXxxx(callBack)等等,诸如此类的一般性操作;统一命名,甚至于继承同样的父接口,能够让层与层间交互统一,形成统一的代码规范。

  • 回调一致:制定统一的回调机制,在回调机制中可以加入线程切换的逻辑。如我们界面经常需要向业务逻辑层发起操作或者获取数据,一般会在业务逻辑层使用异步线程来处理,完成之后在主线程回调,让应用在主线程上去更新界面。


3.3 回调

回调其实也属于接口设计,由于平台上的差异,iOS的回调多使用委托(delegate)和Block,如:

而Java由于不支持Block,但支持匿名类(Anonymous class),所以Java的大部分回调也是委托和匿名类(都是代理)。如:

//Anonymous classpublic abstract class WQBasicListener<T> {/* * Callback */public abstract void onFinish(T resultObj);/* * Callback * * @param error        cause of task failure */public abstract void onFailure(WQError error);/* * Callback */public abstract void onCancel();}public void callBack(WQBasicListener<String> listener) {    String str = ...    if (null != listener) {        listener.onFinish(str);    }}

Block与匿名类,两者非常相似,同属于闭包(closures)的概念,都是传递代码块给被调用者进行回调;区别是:Block更为简单易用,而匿名类则作为类对象来传递,可以进行泛化和封装等,更为强大。


3.4 多线程

我们为什么要用多线程?这是非常简单的问题,但非常多的开发同学其实都无法正确回答。对于一个应用进程来讲,资源其实是限定的,那把任务放在一个线程中串行执行,与切分成几个任务再一个一个去执行有什么区别呢?其实,对于限定的资源来说,多线程:一、合理规划调度任务;简单的来说,就是可以让主要的任务先执行,不重要的任务等到比较空闲的时候再执行。就如应用先保证主线程渲染,其他加载数据的等任务等稍后异步再处理;二、支持并行;现在的CPU早已经进入了多核时代,多核就意味着任务可正真并行,而不是单一的流水线切分时间片。

现在的移动开发领域,基本上不存在单线程的应用,在进行架构设计时,笔者认为多线程设计也是多线程设计中只要的一环,也是区分初级程序员和合格程序员最重要的因素之一。逻辑业务越复杂,就越需要抽象,越需要简单的多线程设计方案。而由于平台的不同,iOS与Android的多线程实现方式也是有很大的不同,但基本的概念和设计理念是一样的:

  • 永远不要阻塞主线程:iOS和Android都一样,界面渲染都有个帧率,就是隔多少毫秒刷新一次界面,这样就能够保证App在用户眼睛里不会存在卡顿和拖影等。永远不要阻塞主线程,把一切耗时的操作都搬到异步线程中去。写完代码,iOS可以用Instruments的Time Profiler + Core Animation跑一下,看看帧率是否正常,主线程的任务占比;对应Android就是DDMS。

  • 按模块设计线程:子模块有自己独立的线程,可以保证模块中数据的线程安全,还能够让模块中的任务按照循序执行,避免了死锁的产生。当然,当涉及到模块间的交互时,能够使用异步就不要使用同步;如涉及到多线程访问的时候,最好使用细粒度的锁;这些措施都能够保证死锁的发生。

  • 根据任务复杂度划分线程:在进行模块设计的时候,不可能每个模块的业务逻辑复杂度都是一样的,总有一些模块会比较复杂,或者经常被调用,此时,就需要考虑负载均衡;当该模块任务是CPU密集型任务,则有两种方案:一、在划分细粒度的任务,放到不同的线程中执行;二、使用多线程来支持任务并行。但需要注意的是,这两种方法都需要关注避免死锁,以及数据的线程安全。

  • 合理的线程池机制:线程池就是为了线程的复用,减少创建线程的消耗的同时,让线程调度更为合理。这方面两个平台都提供了不错的Api支持,iOS这边有Operation Queue和GCD,而Android则有Executor。iOS由于有GCD的存在,让线程池的调用变得非常简单,所以iOS基本上很少直接创建使用某个线程,而是直接使用GCD;而Executor与Operation Queue的用法基本一致,在Android上,自己创建线程并管理线程周期的逻辑会比较常见。



4 IDE

IDE,作为开发者必备的工具,其易用性和稳定性实实在在的影响着开发者的效率和心情。截止到2015年6月30日,两家自家的IDE发展都可圈可点。

  • iOS,Xcode基本是唯一的选择。说基本是因为还有AppCode。我是之前看一位大牛同事用才知道的。AppCode,JB出品,确实是非常Cool而高效的工具,如果是之前就使用JetBrains家IDE的同学,基本是上手即用,而且有一堆通用的插件直接使用,这对于使用Android Studio/IntelliJ IDEA开发Android的同学来说也是极大的福音,至少在IDE这一块不需要太长的时间摸索熟悉。但对于初中级开发者,个人还是会推荐Xcode,原因基本上就等同于现在会推荐你使用Android Studio,而不是IntelliJ IDEA,更不是Eclipse一样。毕竟是苹果自家的工具,不仅集成有非常多的关键功能特性,如新语言特性支持、Debug辅助等,最主要的是有大量的用户和WWDC等资源来学习和解决问题,更容易iOS开发中的关键功能和特性;当然,Xcode如语法提示弱,版本控制支持渣,经常性无缘无故Crash等诸多问题还是让人深恶痛绝的。建议有一定经验的开发者,AppCode与Xcode结合使用。至于Visual Studio?等它发布了再说。

  • Android家的IDE主要就是Eclipse和Android Studio,由于Eclipse从一开始就是Android官方指定的IDE,知道三天前(2015年6月27日),Google宣布终止对Eclipse的支持。个人一直知道Android Studio必然会代替Eclipse,这一天来得并不算早。笔者在大学的时候,用过MyEclipse折腾J2EE;到2010年的时,短暂使用Eclipse开发Android两个月,后续断断续续使用了下,对Eclipse一直感觉一般;所以在2014年末重新拾起Android的时候,就抛弃Eclipse,直接使用Android Studio v0.8,现在Android Studio的稳定版本已到1.2,发展迅速。Android Studio是Google和JetBrains合作,以IntelliJ IDEA为基础开发的IDE,即整合了IntelliJ IDEA强大的功能,又有Google自家的支持,前景一片大好。2V1,对比Eclipse的优势,笔者不多说,各位可自己Google下。现在还在使用Eclipse的同学,该转到Android Studio了。

以Xcode与Android Studio两者对比,由于Android Studio直接是从IntelliJ IDEA发展而来,在代码编辑方面会有压倒性的优势;而且整合了非常强大的Gradle构建工具,有着强大而易用的依赖管理和多工程构建;而这方面,Xcode就只能掩面了;不仅项目工程依赖管理复杂,而且一直没有支持整合CocoaPoads来作第三方库依赖。但Xcode在深入整合的Debug工具,以及强大的Instruments分析工具,较Java的DDMS要更为强大易用。从发展来看,个人对这两个IDE都非常有信心,



5总结

iOS到Android,到底有多远?其实就是要看你在原本的路上走了多远。作为某个平台上的应用开发者,除了深入理解平台之外,我们尽量多关注平台无关的基础知识,这些才能决定你能走多远。

技术的深度与广度,一直是程序员矛盾点,不知道该如何取舍。其实走深度,到了某个瓶颈,你会发现需要其他知识来支持;而深入到了一定阶段,又会发现拓展到了其他知识体系上。比如深入研究iOS系统,必然会研究到XUN,BSD,然后拓展到UNIX;而研究Android内核,又会拓展到了Linux;在这做JS都有Reat Native这样怪物的今天,你还觉得。所以,建议初级开发者,一开始选择一个自己喜欢的平台,沉下心来研究,慢慢堆砌自己的城墙,希冀着成为长城的那一天。


ps:研究Android时间并不长,有错漏的地方还望同学不吝指正。

同分类推荐文章

  1. 「置顶」我做了什么 (2026-05-05 12:13:28)
  2. 万字长文推演:手机不再从 App 开始,Agent OS 如何接管任务入口 (2026-04-28 14:57:22)
  3. Android Perfetto 系列 10 - Binder 调度与锁竞争 (2025-11-16 15:33:30)

查看更多 移动开发 文章 →

建议继续学习

  1. SmartSprites - 命令行形式的CSS Sprites生成器 (累计阅读 123,896)
  2. 情绪版(Mood board)操作流程的新思考 (累计阅读 41,753)
  3. Java开发岗位面试题归类汇总 (累计阅读 22,157)
  4. android 开发入门 (累计阅读 19,529)
  5. 我的PHP,Python和Ruby之路 (累计阅读 13,150)
  6. HashMap解决hash冲突的方法 (累计阅读 12,655)
  7. Android 连接SSID隐藏网络以及 LEAP 认证的方法 (累计阅读 9,539)
  8. 一个大二学生有关如何成为一名软件工程师的疑问及答复 (累计阅读 9,181)
  9. 让安卓手机通过代理翻墙的方法 (累计阅读 9,116)
  10. Java程序员应该知道的10个eclipse调试技巧 (累计阅读 8,014)