一、前言
Android和iOS是移动端两大平台,Android开源、易上手、成本低受、跨平台;iOS作为苹果的封闭系统,简单、流畅、高效。本人从iOS转Android,结合一些资料和自己的理解进行一些总结。
二、基本对比
1、Android和iOS简介
Android是一种基于Linux的自由及开放源代码的操作系统,由Google公司和开放手机联盟领导及开发,主要使用于移动设备,如智能手机、平板电脑、谷歌眼镜等。
iOS是由苹果公司开发的移动操作系统 。设计给iPhone、iPod touch、iPad、AppleWatch以及Apple TV等产品上。iOS与苹果的Mac OS X操作系统一样,属于类Unix的商业操作系统。
2、开发语言
2.1、Android常用的开发语言是Java,Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特点。Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等。
Kotlin 是一个用于现代多平台应用的静态编程语言,Google IO 2017宣布了 Kotlin 会成为 Android 官方开发语言。
2.2、iOS常用开发语言是Object-C,Objective-C在C的基础上,加入面向对象特性而成的编程语言。
Swift是苹果公司在2014上发布的全新开发语言。Swift内在依然是Object-C,但Swift大大地降低了开发门槛。
常规的C和C++亦可用于iOS开发。但使用C和C++做ios开发的人越来也少。
3、开发环境和工具
Android常用Android Studio和Eclipse,可以在Windows、Mac、Linux等多平台安装并开发。
iOS使用XCode开发,只在Mac系统平台下使用。虽然可以在其他平台使用虚拟机开发,但其难度和操作大。
三、技术对比
1、UI界面
1.1、创建和布局
Android有两种方式绘制View,一是使用xml文件,你可以在xml文件中用代码声明你的界面,也可以直接在可视化的界面上拖拽,控件可以通过R文件生成唯一对应的id,在Java 代码中就能通过id来找到控件并处理逻辑。二是在Java中使用代码绘制View和布局。
iOS提供了三种方式来布局和绘制View,一是使用storyboard,二是使用xib文件(nib),三是纯代码布局。前两种方式是不需要代码的,将View和Controller剥离开来,而且不需要在类似xml的源码中添加代码,只需要在视图上鼠标操作就可以。第三种是使用代码来绘制View与布局。使用代码布局更自由,而且能达到一切想要的效果。
二者都有可视化布局方式,能够拖拽设置属性完成界面的简单布局,Android通过修改对应的xml代码修改属性,而iOS直接通过属性设置完成。二者都有相对布局、约束布局和绝对布局,Android还有线性布局、框架布局、网格布局等方式。特别注意的是,iOS没有Android中View的长宽属性wrap_content,这使得在动态宽高变化的时候,需要自己计算。
1.2、控件
两个平台提供的官方UI控件及属性基本类似,基本能满足简单APP的搭建。在Android中基本都有和iOS对应的控件,Android还提供了更多的常用控件,如选框、菜单、吐司等,不同的是他们的API不同,使用方法不同,某些外观能明显看得出苹果的设计风格。iOS的大多数控件都比Android高度封装化,比如创建一个需要层次化流程的界面,iOS使用UITarBarController+UINavigationController非常简单方便创建,虽然Android有TabHost,但是想要创建与iOS的搭配效果,需要更多的自定义代码。
Android所有的UI界面都是由View及其派生类组合而成,开发过程中不会直接使用View,而是使用其派生类和自定义View;iOS中UIView是大部分UI控件的基类,开发的时候经常直接或自定义使用UIView。
高级控件的实现有较大的不同,如ListView和UITableView的表格视图,Android的ListView使用了Adapter适配器来处理显示,而iOS使用dataSource和delegate代理方法代替Adapter的作用。
Android还有Fragment(碎片),表示Activity中的某部分界面或者行为,可以自己加载布局文件,必须与Activity配合使用。Fragment有自己的生命周期,依赖于Activity,使用Fragment能够更加动态和灵活设计UI。
2、控制器
控制器controller是控制UI和处理逻辑,iOS中是通过UIController管理,对应Android的是Activity,二者作用相当,其生命周期也相似。
Android的Activity是由Activity栈进管理,当来到一个新的Activity后,此Activity将被加入到Activity栈顶,之前的Activity位于此Activity底部。可以设置Activity的taskAffinity和launchMode,以改变Activity入栈的形式。
iOS没有UIViewController启动模式,但提供了三总对视图的管理方式:
a、UITabBarController:以平行的方式管理视图,每个加入到UITabBarController的视图都会进行初始化即使当前不显示在界面上,相对比较占用内存;
b、UINavigationController:以栈的方式管理视图,各个视图的切换就是压栈和出栈操作,出栈后的视图会立即销毁;
c、UIModalController:以模态窗口的形式管理视图,当前视图关闭前其它视图上的内容无法操作。
3、数据存储
Android存储数据有以下几种方式:
a、Shared Preferences:是用来存储一些Key/Value类似的成对的基本数据类型,保存用户的简单数据。
b、内部存储与外部存储:内部存储指手机内置存储空间,外部存储指SD卡,通过文件或文件夹操作存储数据。
c、Sqlite3:开源嵌入式关系型数据库,可移植性好、易使用、内存开销小。
iOS是沙盒存储,数据都在APP的目录下,存储方式有以下几种:
a、NSUserDefaults:原理同Shared Preferences,用来保存应用程序设置和属性、用户保存的数据。
b、NSKeyedArchiver:归档采用归档的形式来保存数据,该数据对象需要遵守NSCoding协议。对象对应的类必须提供encodeWithCoder和initWithCoder方法,对对象进行编码和解码。
c、属性列表:保存数据到沙盒文件目录。
d、Sqlite3:同Android。
e、Core Data:是对SQLite的封装,提供了更高级的持久化方式。
4、多线程
在主线程进行耗时操作会带来非常差的体验感,iOS和Android都需要通过多线程处理。
iOS有以下几种方式:
NSThread这套方案是经过苹果封装后的,并且完全面向对象的。所以你可以直接操控线程对象,非常直观和方便。NSThread轻量级,使用简单需要自己管理线程的生命周期、线程同步、加锁、睡眠以及唤醒等。线程同步对数据的加锁会有一定的系统开销。
GCD是苹果为多核的并行运算提出的解决方案,会自动合理地利用更多的CPU内核,最重要的是它会自动管理线程的生命周期,完全不需要我们管理,我们只需要告诉干什么就行。它使用C语言,由于使用了Block,使得使用起来更加方便,而且灵活。很多App都会使用这套方案。它有两个概念:任务和队列。任务分同步和异步。同步任务会在当前线程执行,不会另开线程,会阻塞当前线程,直到block中的任务执行完毕(block在当前线程中执行)。异步任务会另开线程,在别的线程执行。当前线程会直接往下执行,不会阻塞当前线程。(block在新线程中执行)。队列用于存放任务。一共有两种队列,串行队列一次只执行一个线程,FIFO。并行队列:一次可以执行多个线程。
NSOperation和NSOperationQueue。NSOperation 是苹果公司对 GCD的封装,完全面向对象,所以使用起来更好理解。NSOperation 和NSOperationQueue分别对应GCD的任务和队列,它的用法和GCD很像。与GCD不同的是它的任务能被取消,队列可以暂停、恢复,NSOperation还可以被子类化。
Android有以下几种方式:
Runnable/Thread 是Java中的,可以扩展继承Thread类来创建一个线程,也可以继承Runnable接口来创建一个线程,再结合Android中的Handler即可以在子线程中更新主线程UI了。
ExecutorServie线程池也是Java中的概念。它的作用是通过重复利用已经创建的线程来避免创建和销毁线程造成的消耗,同时提高响应速度和线程的可管理性。当Android中有一些不需要更新UI的操作,通常采用这个方法。
IntentService它是继承于Service并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统Service一样。当任务执行完后,IntentService会自动停止,而不需要我们去手动控制。另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行。它处理业务流程非常方便。
AsyncTask是Android提供的轻量级的异步类,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程。它最重要的两个方法,一个是doInBackground(params):处理耗时事务,并把结果返回。一个是onPostExecute(result)可以使用在doInBackground得到的结果处理操作UI。很多人都推荐使用它处理需要更新UI的操作。
Service作为四大组件之一,用于在后台管理和处理一些耗时的逻辑线程或者某些需要长期运行的线程。这里要说明的是Service不是运行在后台线程的,它仍然是运行在UI主线程,所以如果要用它处理耗时任务,你还是得在其中创建新线程。它的作用是能在后台对线程进行良好的管理,对外提供AIDL接口。Service的一个经常的应用是保持着心跳连接。
5、进程间通信
Android的进程间通信方式有很多,如ContentProvider,Activity,广播和AIDL等,不过这些方式的本质都是binder。
Content Provider是Android四大组件之一,它提供了一种在多个应用程序之间数据共享的方式。应用程序可以利用Content Provider完成查询数据,修改数据,添加数据,删除数据。需要创建ContentResolver对象与ContentProvider进行交互,通过指定的URI确定要访问的ContentProvider数据集。
Activity很好理解,就是可以在自己的App跳转到别的程序的界面。但跨进程访问并不需要指定Context对象和Activity的Class对象,而需要指定的是要访问的Activity所对应的Action,有些Activity还需要指定一个Uri。
广播,前面说过广播可以在系统级,所以广播能跨进程通信,一些系统通知经常会用到它,例如通知时区改变、电池电量低、拍摄了一张照片或者用户改变了语言选项等等。
AIDL实际上是一种接口定义语言。通过这种语言定义接口后,Eclipse插件会自动生成相应的Java代码接口代码。它需要创建AIDL文件和一个Service来配合使用。
Binder。这是最底层的进程通信了。主要是有ServiceManager这样一个东西来控制,所有的服务都要通过它来注册,提供它的binder地址,其它程序如果需要哪种服务就向它申请,在ServiceManager获得了对端地址之后,你们两就通过Binder驱动进行通信了。
对于iOS来说,为了避免数据冲突和更好的提供更好的安全机制,iOS提供了沙盒机制。尽管如此,iOS还是提供了若干今晨间通信机制,如URL Scheme、剪切版、CoreCFMessagePort和CFNotificationCenter等等。
URL Schema就是iOS内的应用调用协议,应用A可以声明自定义的调用协议,就如http/https那样,当另一个应用B打算在应用内打开应用A时,可以打开使用A自定义的协议开头的URL来打开A,除了协议头,URL中还可以附加其它参数。
剪切版很好理解,用户可以跨应用拷贝了一段文字,图片,文档等。在代码中对应的类是:UIPasteboard。
CFMessagePort,通过mach port实现的。它需要消息接收者和消息发送者。消息发送者需要通过CFMessagePortCreateLocal、CFMessagePortCreateRunLoopSource、CFRunLoopAddSource来注册监听,并自己实现回调方法。发送者通过CFMessagePortCreateRemote生成一个Remote的CFMessagePortRef,并通过CFMessagePortSendRequest发送数据。遗憾的是iOS7以后不能用这个方法了。
CFNotificationCenter通知可以是系统级别的,它的原理和NSNotificationCenter一样。CFNotificationCenter只提供类方法CFNotificationCenterGetDistributedCenter获取通知发布中心,需要通过CFNotificationCenterAddObserver添加所要指定监听消息名和观察者到通知发布中心,当消息接收到的时候函数指针指向的函数将被执行一次。发送着只需要通过CFNotificationCenterPostNotification发送消息名、对象还有user info就可以了。
6、消息处理机制
Android里的消息处理机制:消息是存放在一个消息队列中,应用程序的主线程围绕这个消息队列进入一个无限循环的,直到应用程序退出。Looper就是消息处理机制的关键,每一个线程都有唯一的Looper,主线程中的Looper默认开启。如果队列中有消息,应用程序的主线程就会把它取出来,并分发给相应的Handler进行处理;如果队列中没有消息,应用程序的主线程就会进入空闲等待状态,等待下一个消息的到来。
这里要注意的是其它线程不是默认开启的。但是如果你需要线程在处理完一些事情后,不要自己停止,那么就需要使用Looper。Looper由四个部分组成:
Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。
Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。
MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。
Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。
iOS也有类似的东西名叫runloop,它的作用其实和looper 是一样,每个线程只有一个Runloop,在主线程中默认启动,一直循环接收消息。当你需要在其它线程干一些其它事时也可以自己启动。不能自己创建RunLoop,CFRunLoopGetMain和 CFRunLoopGetCurrent可以获得Runloop。RunLoop负责处理两种消息事件,输入源事件和计时器事件。它具体的作用是维护线程的生命周期,让线程不自动退出;创建常驻线程,执行一些会一直存在的任务。
四、总结
Android和iOS作为移动端的OS,市场占有率超90%。一个属于Google一个属于Apple,虽然是两个公司,但是很多的风格元素和技术特点也越来越相似。从宏观上讲,iOS和Android最大的不同应该是一个底层是Linux系统,一个是苹果特有的封装系统。苹果特有的系统能够保证在相同配置下,在显示、动画和运行效率上都优于Android系统。还有一个点是,一个是开源另一个闭源,开源可以拥有更多的自由和创造力,闭源提供标准化规则和建议保证质量。总之,未来两个平台二分天下或者一方独领,我们都充满了期待。
参考链接
https://blog.csdn.net/xoperxoper/article/details/52282540
https://www.jianshu.com/p/f56c0a921c32
https://www.jianshu.com/p/e162b76e3e6f
https://www.jianshu.com/p/042f0660510a