Android 经典问题

Dalvik和Sun JVM

共同点

  • 都是解释执行 byte code(字节码)
  • 都是每个 OS 进程运行一个 VM,并执行一个单独的程序
  • 在较新版本中(Froyo / Sun JDK 1.5)都实现了相当程度的 JIT compiler(即时编译) 用于提速

不同点

  • dvm执行的是.dex格式文件,jvm执行的是.class文件,android程序编译完之后生产.class文件,然后,dex工具会把.class文件处理成.dex文件,然后把资源文件.dex文件等打包成.apk文件。apk就是android package的意思。jvm执行的是.class文件。
  • dvm是基于寄存器的虚拟机 而jvm执行是基于虚拟栈的虚拟机。寄存器存取速度比栈快的多,dvm可以根据硬件实现最大的优化,比较适合移动设备。
  • .class文件存在很多的冗余信息,dex工具会去除冗余信息,并把所有的.class文件整合到.dex文件中。减少了I/O操作,提高了类的查找速度。

IPC进程间通信

在一个应用中存在多个进程的情况(不讨论两个应用之间的多进程情况),开启多进程:在Androidmanifests文件中指定android:process属性除此之外没有其他办法

进程名:以“:“开头的进程属于当前应用的私有进程,其他的应用不可以和它跑在同一个进程中,而进程名不以”:“开头的属于全局进程,其他应用通过shareUID方式可以和它跑在同一个进程中。Android给每一个进程都分配一个独立的虚拟机,所以运行在不同进程中的四大组件,只要他们之间需要通过内存来共享数据,都会共享失败,这也是多进程所带来的主要影响。

使用多进程会造成问题:

  • 静态成员和单例模式完全失效
  • 线程同步机制完全失效
  • SharedPreferences的可靠性下降
  • Application会多次创建

SharedPreferences的可靠性降低,因为 SharedPrefrences不支持两个进程同时执行写操作,可能会导致一定几率的数据丢失,这是因为sharedPrefrences底层是通过读写xml实现的。

实现跨进程通信的方式:

  • 通过Intent来传递数据(通过Bundle来绑定数据)
  • 共享文件SharedPrefereneces
  • 基于BinderMessengerAIDL以及Socket

序列化静态成员变量属于类不属于对象,所以不会参与序列化过程,其次transient关键字标记的成员变量不参与序列化过程。 实现了Parcelable接口的类都是可以直接序列化的,Android中已经实现了parcelable类的有:IntentBundleBitmap等,同时 listmap 也可以序列化,前提是他们的每个元素都能序列化实现了parcelable接口的类都可以通过IntentBinder来传递

Binder类:实现了IBinder接口,从IPC角度来说,BinderAndroid中一种垮进程通信方式,还可以理解为一种虚拟的物理设备,该通信在Linux中是没有的。Binder是连接各种managerActivityManagerwindowManager)和相应的ManagerService的桥梁

binder驱动是整个流程的核心

  • Server将自己的binder通过binder驱动SM中进行注册。
  • binder驱动会建立一个binder实体的数据节点和实体的引用。
  • Binder驱动再把名字和引用打包发给SM
  • Client通过binder驱动拿着他所需要的binder名字SM请求binder
  • SM在自己的查找表里面找到对应的引用之后再通过binder驱动返回给client
Android 经典问题_第1张图片
Binder流程图

Intent传递数据

根据API文档,Intent/Bundle支持传递基本类型的数据和基本类型的数组数据,以及String/CharSequence。而对于其它类型的数据貌似无能为力,其实不然,我们可以在Intent/Bundle的API中看到Intent/Bundle还可以传递 Parcelable(包裹化,邮包)和Serializable(序列化)类型的数据,以及它们的数组/列表数据。

数据存储

Android数据存储方式SharedPreferencesSQLiteContentProviderFile
SharedPreferences键值对的形式存储,底层是xml文件。并且可以设置权限,是否和其他应用共享该项文件FileAndroid分为内部存储外部存储内部存储中属于APP私有,其他任何应用都不能访问,APP卸载时自动删除外部存储又分为两类:公共文件私有文件私有文件:本属于您的应用且应在用户卸载您的应用时删除的文件。尽管这些文件在技术上可被用户和其他应用访问(因为它们在外部存储上),它们是实际上不向您的应用之外的用户提供值的文件。当用户卸载您的应用时,系统会删除应用外部专用目录中的所有文件。

Android动画

View动画
View动画注意事项:View动画执行之后并未改变View的真实布局属性值。切记这一点,譬如我们在Activity中有一 个Button在屏幕上方,我们设置了平移动画移动到屏幕下方然后保持动画最后执行状态呆在屏幕下方,这时如果点 击屏幕下方动画执行之后的Button是没有任何反应的,而点击原来屏幕上方没有Button的地方却响应的是点击Button的事件。
View动画有四种变换效果,对应Animation的四个子类:TranslateAnimation(平移),ScaleAnimation(缩放),AlphaAnimation(透明度动画),RotateAnimation(旋转),一般采用XML的方式来定义动画,可读性更好。

帧动画
对应AnimationDrawale来使用帧动画,通过XML来定义个AnimationDrawable,然后把xml作为Drawable作为view的背景来播放动画就可以了。

注意
帧动画使用比较简单,比较容易引起OOM,所以尽量避免使用过多尺寸较大的图片

属性动画
主要由ValueAnimatorObjectAnimatorAnimatorSet类实现。

Bitmap加载
Bitmap代表一张图片,BitmapFactory提供了四类方法:decodeFiledecodeResourcedecodeStreamdecodeByteArray加载bitmap

Retrofit优点

  • 采用动态代理机制反射,使代码写起来特别简单,看起来也很清晰。
  • 可以配合OkHttp拦截器,很方便的在headertoken或者处理cookie等等。
  • 可配合RxJava,可以让多个接口调用组合变的更简单。

RequestLayout,invalidate和postInvalidate

  • requestLayout:当view确定自身已经不再适合现有的区域时,该view本身调用这个方法要求parent view重新调用他的onMeasureonLayout来对重新设置自己位置。
    特别的当viewlayoutparameter发生改变,并且它的值还没能应用到view上,这时候适合调用这个方法。
  • invalidateinvalidate内部最终会调用到performTraversals(视图绘制的入口),但由于没有设置强制视图重新测量的标志位,所以只会执行onDraw方法。
  • postInvalidate:是在非UI线程使用。

Rxjava

一个词:异步
RxJavaGitHub 主页上的自我介绍是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一个在 Java VM上使用可观测的序列来组成异步的、基于事件的程序的库)。这就是 RxJava ,概括得非常精准。
RxJava默认规则中,事件的发出和消费都是在同一个线程的。在不指定线程的情况下, RxJava 遵循的是线程不变的原则,即:在哪个线程调用 subscribe(),就在哪个线程生产事件;在哪个线程生产事件,就在哪个线程消费事件。如果需要切换线程,就需要用到 Scheduler (调度器)。
RxJava 的异步实现,是通过一种扩展的观察者模式来实现的。

变换(map(),flatmap()):
Map行为:

  • 创建了一个新的 Observable
  • 创建了一个新的 OnSubscribe: 其中的 call 方法是整个调用链的关键. 它调用了上一级 Observable.onSubscribe.call, 同时, 还将结果通过transform 对 ‘第一步’ 处理后的结果进行变形, 然后将变形后的结果再转发给‘第三步’ 中 subscribe(Subscriber…) 中的 Subscriber 处理. 那我们马上看一下 ‘第三步’。

Glide优点

  • 默认Bitmap格式是RGB_565内存占用更少,原因在于Picasso是加载了全尺寸的图片到内存,然后让GPU来实时重绘大小。而Glide加载的大小ImageView的大小是一致的,因此更小。
  • 磁盘缓存
  • Picasso和Glide在磁盘缓存策略上有很大的不同。Picasso缓存的是全尺寸的,而Glide缓存的是跟ImageView尺寸相同
  • Glide可以加载GIF动态图,而Picasso不能。
  • 除了gif动画之外,Glide还可以将任何的本地视频解码成一张静态图片。

Material Design

  • TextInputLayout 必须把EditText包含起来,不能单独使用。


        


  • FloatingActionButton继承自ImageView
  • NavigationView实现DrawerLayout导航菜单界面,通过
app:headerLayout="@layout/navigation_header"
        app:menu="@menu/drawer_view" 

来设置.

SQLite

public long insert (String table, String nullColumnHack, ContentValues values) 插入数据
参数介绍 :

  • 参数① table : 数据库中的表名, 要插入数据的表;
  • 参数② nullColumnHack : 该参数是可选的, 数据库表中不允许插入一行空的数据, 插入数据至少有一列不为null才能插入, 如果后面的valuesnull, 并且不知道列的名称, 那么插入操作会失败, 为了避免这种情况, 就出现了本参数, 为了防止 valuesnull的情况;
  • 参数③ ContentValues : 相当于一个Map集合,键是列名,值是对应列名要插入的数据;

插入原则 : 不管第三个 ContentValues参数是否为null, 执行insert()方法都会添加一条记录, 如果values参数为null, 会添加一个除主键之外其它字段都为null的记录;
nullColumnHack参数作用分析SQL语句 : 在SQL语句中在表名后面必须跟着一个列名, 例如 " insert into appale_info(name) values("乔帮主")", 这是values参数不为null的情况下,如果values参数为null, 那么导致表名 "apple_info" 后面的列名也为null, 这样SQL语句就不合法了, 因此这里必须加上一个默认的列名, 以防values参数为null;

HttpURLConnection

设置请求头或响应头
HTTP请求允许一个key带多个用逗号分开的values,但是HttpURLConnection只提供了单个操作的方法:

  • setRequestProperty(key,value)
  • addRequestProperty(key,value)

setRequestPropertyaddRequestProperty的区别就是,setRequestProperty会覆盖已经存在的key的所有values,有清零重新赋值的作用。而addRequestProperty则是在原来key的基础上继续添加其他value

发送URL请求
建立实际连接之后,就是发送请求,把请求参数传到服务器,这就需要使用outputStream把请求参数传给服务器:

  • getOutputStream

获取响应
请求发送成功之后,即可获取响应的状态码,如果成功既可以读取响应中的数据,获取这些数据的方法包括:

  • getContent
  • getHeaderField
  • getInputStream

对于大部分请求来说,getInputStreamgetContent是用的最多的。
相应的信息头用以下方法获取:

  • getContentEncoding
  • getContentLength
  • getContentType
  • getDate
  • getExpiration
  • getLastModifed

任何网络连接都需要经过socket才能连接,HttpURLConnection不需要设置socket,所以,HttpURLConnection并不是底层的连接,而是在底层连接上的一个请求。这就是为什么HttpURLConneciton只是一个抽象类,自身不能被实例化的原因。HttpURLConnection只能通过URL.openConnection()方法创建具体的实例。虽然底层的网络连接可以被多个HttpURLConnection实例共享,但每一个HttpURLConnection实例只能发送一个请求。请求结束之后,应该调用HttpURLConnection实例的InputStreamOutputStreamclose()方法以释放请求的网络资源,不过这种方式对于持久化连接没用。对于持久化连接,得用disconnect()方法关闭底层连接的socket

ViewStub、include、merge

好文章

Json

一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性。可在不同平台之间进行数据交换。JSON采用兼容性很高的文本格式,同时也具备类似于C语言体系的行为。

优点

  • 数据格式比较简单,易于读写,格式都是压缩的,占用带宽小
  • 易于解析
  • 支持多种语言,包括ActionScript, C, C#, ColdFusion, Java, JavaScript, Perl, PHP, Python, Ruby等服务器端语言,便于服务器端的解析;
  • 因为JSON格式能直接为服务器端代码使用,大大简化了服务器端和客户端的代码开发量,且完成任务不变,并且易于维护。

缺点

  • 没有XML格式这么推广的深入人心和喜用广泛,没有XML那么通用性;
  • JSON格式目前在Web Service中推广还属于初级阶段

Android中Parcelable和Serializable

作用

Serializable的作用是为了保存对象的属性到本地文件、数据库、网络流、rmi以方便数据传输,当然这种传输可以是程序内的也可以是两个程序间的。简单易用,这种方法的缺点是使用了反射,序列化的过程较慢。这种机制会在序列化的时候创建许多的临时对象,容易触发垃圾回收

而Android的Parcelable的设计初衷是因为Serializable效率过慢,为了在程序内不同组件间以及不同Android程序间(AIDL)高效的传输数据而设计,这些数据仅在内存中存在Parcelable是通过IBinder通信的消息的载体。

效率

Parcelable的性能比Serializable好,在内存开销方面较小,所以在内存间数据传输时推荐使用Parcelable,如activity间传输数据,而Serializable可将数据持久化方便保存,所以在需要保存或网络传输数据时选择Serializable,因为android不同版本Parcelable可能不同,所以不推荐使用Parcelable进行数据持久化

从上面的设计上我们就可以看出优劣了。

  • 整个读写全是在内存中进行,所以效率比JAVA序列化中使用外部存储器会高很多;
  • 读写时是4字节对齐的
  • 如果预分配的空间不够时,会一次多分配50%;
  • 对于普通数据,使用的是mData内存地址,对于IBinder类型的数据以及FileDescriptor使用的是mObjects内存地址。后者 是通过flatten_binder()unflatten_binder()实现的,目的是反序列化时读出的对象就是原对象而不用重新new一个新对象。

后期持续更新。。。。。。

你可能感兴趣的:(Android 经典问题)