Android面试合集

Android面试合集
目录
一、.文件存储五种方式:
二、广播机制
三、服务
四、事件处理
2.Handler消息机制
五、网络编程
2.json数据解析
3.xml解析
4.基于TCP的Socket通信流程
六.动画
七、TCP/IP和UDP
八、三次握手四次挥手
三次握手过程中可以携带数据吗?
为什么需要三次握手,两次不行吗?
挥手为什么需要四次?
九、xutils框架、volley、gson、Eventbus
十、flutter介绍
十一、事件分发机制
十二、android性能优化
(一)防止程序闪退
(二)防止画面卡顿
(三)耗电优化
(四)减少安装包(APK)大小
十三、binder机制
十四、AsyncTask 异步处理的原理
十五、git原理与基本操作
十六、中间件
十七、dalvik虚拟机和art对比
十八、Activity 怎么和Service 绑定
十九.Activity与Service数据通信
二十、Service中能否进行耗时操作?
二十一、线程和进程之间的通信方式
一、Android进程间通信方式
二、Android线程间通信方式
三、Android两个子线程之间通信
二十二、自定义控件view的绘制过程
二十三、Fragment与Fragment、Activity通信的方式

一、.文件存储五种方式:

  1. 文件存储:openfileInput和openfileOutput()
  2. Sharedpreferences存储:
    写入:调用getsharedpreferences获取实例对象,该对象只能获取数据,需要调用edit方法来获取可编辑的Editor对象,最后通过putXXX()方法来写入数据
    读取:获取sharedpreferences对象,通过该对象的getXXX()方法根据相应的key值来获取value的值
    删除:调用editor对象的clear方法或者remove方法

Commit()和apply()的区别:
apply 方法进行提交会先写入内存,然后异步写入磁盘,commit
方法是直接写入磁盘。如果频繁操作的话 apply 的性能会优于 commit,apply会将最后修改内容写入磁盘。
但是如果希望立刻获取存储操作的结果,并据此做相应的其他操作,应当使用 commit。
3. SQLite数据库
创建:新建一个类继承自SQLiteOpenHelper类,重写里面的oncreate()方法和onUpgrade()方法
新增加数据:获取可续写的SQLiteDatabase对象,创建contentvalue对象,将数据添加到该对象当中,然后插入一条数据到information表,最后调用close方法关闭数据库
删除:SQLitedatabase的delete()方法
修改:首先获取了SQLiteDatabase的对象db,接着创建一个contentvalues类的对象values,通过调用put()方法来将需要修改的字段名称和字段值放入到对象values中,最后通过对象db调用updata()方法来修改数据库的数据。
查询
查询:SQLiteDatabase对象的query()方法来查询表中的数据,并返回一个Cursor对象
4. Contentprovider:四大组件之一,提供了应用程序之间的数据共享
5. 网络存储:将数据存储到服务器上
二、广播机制
1.流程:广播接收者通过binder机制在AMS中注册,广播发送者通过binder机制向AMS发送广播,AMS查找符合相应条件的广播接收者,将广播发送到相应的循环队列中,执行消息循环时获取到这个广播,会回调广播接收者的onReceive()方法并在该方法中处理。
2.可以在同一个APP内部同意组件内,在同一个APP不同组件之间,在同一个APP不同组件之间,在不同APP的组件之间通信。
3.动态注册(Activity中代码注册)的广播永远快于静态注册(配置清单注册)的广播,动态广播不是常驻型广播,会跟随activity的生命周期。
4.在同一优先级下,谁先启动快,谁先接受到广播。
5.广播的类型:无序广播:所有的广播接收者都会收到,效率高,不会被拦截
有序广播:按照优先级被依次接受(setPriority(1000)方法,值越大优先级越高),效率低,有先后顺序,可以被拦截
优先级:相同情况,谁先注册谁的优先级高,先安装的先接收
拦截广播:abortBroadcast()方法
程序中发送有序广播通过sendBroadcastReceiver()实现
无序通过sendbroad()实现
6.注册方式主要有两种.
第一种是静态注册,也可成为常驻型广播,这种广播需要在Androidmanifest.xml中进行注册,这中方式注册的广播,不受页面生命周期的影响,即使退出了页面,也可以收到广播这种广播一般用于想开机自启动啊等等,由于这种注册的方式的广播是常驻型广播,所以会占用CPU的资源。
第二种是动态注册,而动态注册的话,是在代码中注册的,这种注册方式也叫非常驻型广播,收到生命周期的影响,退出页面后,就不会收到广播,我们通常运用在更新UI方面。这种注册方式优先级较高。最后需要解绑,否会会内存泄露
三、服务
1.不提供界面的后台操作,一般由activity启动,但并不依赖于activity
作用:后台运行、跨进程访问
2.生命周期
Startservice():onCreate()、onStartCommand()(开启服务)、onDestory()
BindService():onCreate()、onBind()、onUnbind()、onDestory()
3.启动方式
(1)startservice启动的服务,即使组件被销毁,服务依旧会运行
Bindservice启动的服务,会与组件绑定,程序允许组件与服务进行交互,组件一旦退出会解绑,服务会销毁,多个组件可以绑定一个服务。
(2)本地服务通信:首先创建一个service类,该类会提供一个onBind方法,onbind的返回值是一个IBinder对象,IBinder对象会作为参数传递给ServiceConnection类中的onServiceConnection方法,这样访问者就可以通过IBinder对象与Service进行通信。
(3)远程服务通信:AIDL实现,是一种接口定义语言
(4)服务是运行在主线程中的。
4.如何保证服务不被杀死
onStartCommand方法,返回START_STICKY
提升service优先级
提升service进程优先级
Application加上Persistent属性
将APK安装到/system/app,变身系统级应用(调试使用,并不是解决办法)
服务被kill之后怎么去重启:onDestroy方法里重启service
四、事件处理
1.主要是指键盘事件与触摸事件,
主要有两种处理机制:基于毁掉机制的事件处理,基于监听接口的事件处理
2.Handler消息机制
(1)作用:跨线程通信,当子线程进行耗时操作后需要更新UI时,通过Handler将有关的UI操作切换到主线程进行。
(2)机制(四大组件)
Message:在线程之间传递的消息,可以携带少量的信息
Handler:用来处理和发送消息,处理者
MessageQueue(每个线程只有一个):消息队列,用来存储Handler发送过来的消息,存放在消息队列中
Looper(每个线程只有一个):相当于消息泵,通过looper的loop()方法抽取消息队列的消息,将其取出放到Handler的handlerMessage()方法中进行分发处理。
(3)handler消息处理流程:
在主线程创建Handler对象
重写handlerMessage()方法
子线程需要更新UI时,创建一个Message对象,通过Handler将消息发出去
消息添加到MessageQueue的队列中等待被处理
Looper在MessageQueue中取出等待消息处理消息,发回Handler的handlerMessage()方法中

五、网络编程
1.通过Http协议访问网络,需要用到HttpURLConnection
使用WebView进行网络开发,android内置了浏览器,使用了开源的webkit引擎,webview还支持js

HttpURLConnection访问网络:
(1) 创建URL对象。
(2) 调用URL对象的openConnection()方法获取HttpURLConnection对象。
(3) 调用setRequestMethod()方法设置http请求的方式。
(4) 通过setConnectTimeout()方法设置连接的超时时间。
(5) 调用getInputStream()方法获取服务器返回的输入流。
(6) 最后调用disconnect()方法关闭http连接。
2.json数据解析
Json是一个轻量级的数据交换格式,只提供数据而不负责数据的呈现,通过键值对的形式表示,json数据有两种结构,分别是对象结构和数组结构,它比xml更小更快更容易解析
三种解析方式:传统json解析(生成字符串,解析json字符串)
Gson解析
Fastjson
Android SDK提供了org.json包,存放了解析json数据的类
3.xml解析
DOM解析(使用JAXP)
SAX解析(创建解析器工厂,获得解析器,sax解析)
DOM4j解析(简单的开源库)
JDOM解析(使用xml的独特的java工具包,基于树形结构)

4.基于TCP的Socket通信流程
• TCP编程的服务端流程:
1.创建ServerSocket类对象-serverSocket
2.使用serverSocket开始一直阻塞监听,等待客户端发送来数据并且得到socket
3.根据socket的输入流读取客户端的数据,根据socket的输出流返回给客户端数据
4.关闭socket以及IO流
• TCP编程的客户端对象
1.创建客户端的socket对象
2.使用客户端的socket对象的输出流发送给服务器数据,使用客户端的socket对象的输入流得到服务端的数据
六.动画
1.补间动画(平移、缩放、旋转、改变透明度)
逐帧动画(拆分成一张一张的图片)
属性动画(属性动画可以定义任何属性的变化,补间动画只能对 UI 组件执行动画,但属性动画可以对任何对象执行动画)
七、TCP/IP和UDP
应用层、传输层、网络层、链路层
1.tcp/ip是一个网际协议群,里面包含了应用协议(HTTP),传输协议(TCP UDP),网际协议(IP),路由控制协议(RIP)
2.TCP是面向连接的,可靠的流协议,可以保证发送的顺序,只有在确保连接时会发送数据,具有重发控制
UDP 是不具备可靠性的数据报协议,是无连接的,虽然可以确保发送消息的大小,却不能保证一定会到达,通常用于对实时性要求高的通信或广播通信
八、三次握手四次挥手

  1. 第一次握手:客户端将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给服务器端,客户端进入SYN_SENT状态,等待服务器端确认。
    第二次握手:服务器端收到数据包后由标志位SYN=1知道客户端请求建立连接,服务器端将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给客户端以确认连接请求,服务器端进入SYN_RCVD状态。
    第三次握手:客户端收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给服务器端,服务器端检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,客户端和服务器端进入ESTABLISHED状态,完成三次握手,随后客户端与服务器端之间可以开始传输数据了。
  2. 中断连接端可以是客户端,也可以是服务器端。
    第一次挥手:客户端发送一个FIN=M,用来关闭客户端到服务器端的数据传送,客户端进入FIN_WAIT_1状态。意思是说"我客户端没有数据要发给你了",但是如果你服务器端还有数据没有发送完成,则不必急着关闭连接,可以继续发送数据。
    第二次挥手:服务器端收到FIN后,先发送ack=M+1,告诉客户端,你的请求我收到了,但是我还没准备好,请继续你等我的消息。这个时候客户端就进入FIN_WAIT_2 状态,继续等待服务器端的FIN报文。
    第三次挥手:当服务器端确定数据已发送完成,则向客户端发送FIN=N报文,告诉客户端,好了,我这边数据发完了,准备好关闭连接了。服务器端进入LAST_ACK状态。
    第四次挥手:客户端收到FIN=N报文后,就知道可以关闭连接了,但是他还是不相信网络,怕服务器端不知道要关闭,所以发送ack=N+1后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。服务器端收到ACK后,就知道可以断开连接了。客户端等待了2MSL后依然没有收到回复,则证明服务器端已正常关闭,那好,我客户端也可以关闭连接了。最终完成了四次握手。
    三次握手过程中可以携带数据吗?
    其实第三次握手的时候,是可以携带数据的。但是,第一次、第二次握手不可以携带数据
    为什么需要三次握手,两次不行吗?
    弄清这个问题,我们需要先弄明白三次握手的目的是什么,能不能只用两次握手来达到同样的目的。
    第一次握手:客户端发送网络包,服务端收到了。
    这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
    第二次握手:服务端发包,客户端收到了。
    这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。
    第三次握手:客户端发包,服务端收到了。
    这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。
    挥手为什么需要四次?
    因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,“你发的FIN报文我收到了”。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次挥手。
    九、xutils框架、volley、gson、Eventbus
    1.xutils框架最初源于Afinal框架,进行了大量的重构,使得该框架支持大文件上传,更全面的http请求协议,拥有更灵活的ORM
    2.GSON框架:是一个java库,可用于将Java对象转换为他们的json表示形式,实际上就是为了方便解析json
    3.volley:是谷歌推出的Android异步网络请求框架和图片加载框架
    主要特征:拓展性强,大多是基于接口的设计,可配置性强
    一定程度的http规范
    提供了简便的图片加载工具
    4.Eventbus:
    EventBus是一款针对Android优化的发布/订阅(publish/subscribe)事件总线。主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,线程之间传递消息。简化了应用程序内各组件间、组件与后台线程间的通信。优点是开销小,代码更优雅,以及将发送者和接收者解耦。比如请求网络,等网络返回时通过Handler或Broadcast通知UI,两个Fragment之间需要通过Listener通信,这些需求都可以通过EventBus实现。
  3. OKhttp:
    Android开发中是可以直接使用现成的api进行网络请求的。就是使用HttpClient,HttpUrlConnection进行操作。okhttp针对Java和Android程序,封装的一个高性能的http请求库,支持同步,异步,而且okhttp又封装了线程池,封装了数据转换,封装了参数的使用,错误处理等。API使用起来更加的方便。但是我们在项目中使用的时候仍然需要自己在做一层封装,这样才能使用的更加的顺手。
    十、flutter介绍
    Flutter是谷歌公司开发的一款开源、免费的移动UI框架,开源让我们快速的在Android和Ios上架构高质量APP,最大的特点就是跨平台,高性能。
    Flutter基于谷歌的Dart语言,国内的阿里以及闲鱼都是flutter开发的。
    十一、事件分发机制
    1.事件分发就是将一次完整的点击事件传递到某个view或者viewgroup来处理它,分发是从上往下依次传递的,就是从上往下依次遍历,直到找到能够处理它的view或者viewgroup。
    2.分发事件类型
    事件分发中的事件指的是点击事件(Touch事件),一次完整的点击包含四种事件:
    (1)ACTION.DOWN:手指触摸到屏幕
    (2)ACTION.MOVE:手指在屏幕中滑动
    (3)ACTION.UP:手指离开屏幕
    (4)ACTION.CANCEL:取消点击事件
    3.事件分发涉及到的方法
    事件分发涉及到的方法有3个:dispatchTouchEvent()(分发事件)、onInterceptTouchEvent()(拦截事件)、onTouchEvent()(处理事件)。
    Activity涉及到的方法:dispatchTouchEvent(),onTouchEvent()。
    ViewGroup涉及到的方法:dispatchTouchEvent()、onInterceptTouchEvent()、onTouchEvent()。
    View涉及到的方法:dispatchTouchEvent(),onTouchEvent()。
    由上可知,onInterceptTouchEvent()方法是ViewGroup独有的,另外两个方法是三者共有的。
    Activity的dispatchTouchEvent()方法中会默认调用ViewGroup的dispatchTouchEvent()方法,代表事件从Activity传递到了ViewGroup去进行下一步事件分发
    View:如果onInterceptTouchEvent()方法返回True,表示拦截ACTION_DOWN事件,事件停止往下传递,ViewGroup会调用它的父类View的dispatchTouchEvent()方法,在该方法里调用onTouch()—>onTouchEvent()—>onClick()方法去处理事件,并且之后的ACTION_MOVE和ACTION_UP事件都会交给该ViewGroup处理,不会再往下传递。如果onInterceptTouchEvent()方法返回False,则代表ViewGroup不处理该事件,而是向下传递事件
    十二、android性能优化
  4. 追求稳定,防止闪退
  5. 追求流畅,防止卡顿
  6. 追求续航,防止电量耗损
  7. 追求精简,防止安装包臃肿
    (一)防止程序闪退
    出现Crash应用闪退和崩溃一般有三个原因:ANR(程序无响应)、Exception(异常)、LMK(低内存杀死机制)。
    1、ANR:造成ANR程序无响应的原因主要是系统规定在四大组件中不能做过多的耗时操作。一般在Activity中不要超过5秒;BroadCast广播前台“intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND)”10秒、后台60秒;Service前台“创建一个Notification,然后使用Service的startForeground()方法即可启动为前台服务”20秒、后台服务200秒;ContentProvider的publish在10秒内没进行完。
    2、Exception:造成Crash的原因却有很多,比如:运行时异常的空指针、数组越界、未实例化、强制类型、低内存机制等等,有些时候我们在开发测试阶段都没有出现异常崩溃现象,而发布上线后到了用户手机就会出现各种奇怪闪退。所以,我们要去努力实现一个永远打不死的小强 —— 不会出现Crash闪退的APP。通常我们会使用 try - catch,在发现容易出现崩溃的代码块,主动加上try-catch 预防异常闪退。但是没加try-catch的代码块出现异常还是闪退该怎么办?我们可以通过集成AndroidCrashX,就可以捕获全局线程异常并做好统计日志,最后我们通过热修复技术修复线上bug,就可以不通过发版就可以改掉线上bug。
    3、LMK:由于Android应用的沙箱机制,每个应用程序都运行在一个独立的进程中,各自拥有独立的Dalvik虚拟机实例,系统默认分配给虚拟机的内存是有限度的。当系统内存太低依然会触发LMK(Low Memory Killer)机制,即出现闪退、崩溃现象。不同厂商不同,如:华为mate7,192m ;小米4,128m ;红米,128m 。而在,Android4.0以后,可以通过在application节点中设置属性android:largeHeap=”true”来设置最大可分配多少内存空间就可以突破一定限制。
    (二)防止画面卡顿
    (1)布局优化
    在Android种系统对View进行测量、布局和绘制时,都是通过对View数的遍历来进行操作的。如果一个View数的高度太高就会严重影响测量、布局和绘制的速度。Google也在其API文档中建议View高度不宜哦过10层。现在版本种Google使用RelativeLayout替代LineraLayout作为默认根布局,目的就是降低LineraLayout嵌套产生布局树的高度,从而提高UI渲染的效率。
    布局复用,使用标签重用layout;
    提高显示速度,使用延迟View加载;
    减少层级,使用标签替换父级布局;
    注意使用wrap_content,会增加measure计算成本;
    删除控件中无用属性;
    (2)绘制优化
    过度绘制是指在屏幕上的某个像素在同一帧的时间内被绘制了多次。在多层次重叠的 UI 结构中,如果不可见的 UI 也在做绘制的操作,就会导致某些像素区域被绘制了多次,从而浪费了多余的 CPU 以及 GPU 资源。如何避免过度绘制?
    布局上的优化。移除 XML 中非必须的背景,移除 Window 默认的背景、按需显示占位背景图片
    自定义View优化。使用 canvas.clipRect() 帮助系统识别那些可见的区域,只有在这个区域内才会被绘制。
    (3)启动优化
    启动优化工具。 应用一般都有闪屏页SplashActivity,优化闪屏页的 UI 布局,可以通过 Profile GPU Rendering 检测丢帧情况。
    (三)耗电优化
    常见耗电原因,比如应用为了保持应用进程长期在后台存活,使用各种不合理进程保活方案,导致用户电量严重耗损。
    (1)计算优化。算法、for循环优化、Switch…case替代if…else、避开浮点运算。
    (2)避免 Wake Lock 使用不当。
    Wake Lock是一种锁的机制,主要是相对系统的休眠而言的,,只要有人拿着这个锁,系统就无法进入休眠意思就是我的程序给CPU加了这个锁那系统就不会休眠了,这样做的目的是为了全力配合我们程序的运行。有的情况如果不这么做就会出现一些问题,比如微信等及时通讯的心跳包会在熄屏不久后停止网络访问等问题。所以微信里面是有大量使用到了Wake_Lock锁。系统为了节省电量,CPU在没有任务忙的时候就会自动进入休眠。有任务需要唤醒CPU高效执行的时候,就会给CPU加Wake_Lock锁。大家经常犯的错误,我们很容易去唤醒CPU来工作,但是很容易忘记释放Wake_Lock。
    (3)使用 Job Scheduler 管理后台任务。
    在Android 5.0 API 21 中,google提供了一个叫做JobScheduler API的组件,来处理当某个时间点或者当满足某个特定的条件时执行一个任务的场景,例如当用户在夜间休息时或设备接通电源适配器连接WiFi启动下载更新的任务。这样可以在减少资源消耗的同时提升应用的效率。
    (四)减少安装包(APK)大小
    代码冗余,图片优化,资源优化
    十三、binder机制
    进程间的通信机制
    Binder通信采用C/S架构,从组件视角来说,包含Client、Server、ServiceManager以及binder驱动,其中ServiceManager用于管理系统中的各种服务
    Binder通信的四个角色
    Client进程:使用服务的进程。
    Server进程:提供服务的进程。
    ServiceManager进程:ServiceManager的作用是将字符形式的Binder名字转化成Client中对该Binder的引用,使得Client能够通过Binder名字获得对Server中Binder实体的引用。
    Binder驱动:驱动负责进程之间Binder通信的建立,Binder在进程之间的传递,Binder引用计数管理,数据包在进程之间的传递和交互等一系列底层支持。
    为什么Binder只进行了一次数据拷贝?
    Linux内核实际上没有从一个用户空间到另一个用户空间直接拷贝的函数,需要先用copy_from_user()拷贝到内核空间,再用copy_to_user()拷贝到另一个用户空间。为了实现用户空间到用户空间的拷贝,mmap()分配的内存除了映射进了接收方进程里,还映射进了内核空间。所以调用copy_from_user()将数据拷贝进内核空间也相当于拷贝进了接收方的用户空间,这就是Binder只需一次拷贝的‘秘密’。
    十四、AsyncTask 异步处理的原理
    1、 AsyncTask的本质是一个静态的线程池,AsyncTask派生出的子类可以实现不同的异步任务,这些任务都是提交到静态的线程池中执行。
    2、线程池中的工作线程执行doInBackground(mParams)方法执行异步任务
    3、当任务状态改变之后,工作线程会向UI线程发送消息,AsyncTask内部的InternalHandler响应这些消息,并调用相关的回调函数
    十五、git原理与基本操作
    1.什么是git
    git就是一代码管理工具,它是分布式的,不仅有一个中心的服务器控制最新版本代码,而且每个开发者自己还有个本地仓库,所以在开发过程中都是先将代码提交到本地仓库再推送到中心服务器上的,这样的好处就是每个人都依赖于中心服务器来实现交互,但又不会被中心服务器限制,就算中心服务器挂了,也能很容易的找到最新版本的代码,而且我自己的工作依然可以顺利进行,提交到本地仓库,当中心服务器修复之后,再将自己仓库的东西推送到中心服务器。
    2.基本命令
    git init 首先在git bash中切换至你所要创建的repository目录下,初始化repository并创建
    git add README.md 添加你要上传到repository里的文件git add .则是目录下所有文件均上传
    git commit -m “first commit” 填写提交说明,双引号内是内容说明
    git remote add origin https://github.com/你的Github名/repository名.git 连接到你的GitHub远端repository
    git push -u origin master 提交至远端repository
    十六、中间件
    中间件其实就是屏蔽硬件系统差异,并提供统一接口给各种应用程序,可供二次开发的一些组件,类库。 一般都是应用和系统之间的软件层,在android上就是类似应用程序框架之上应用程序之间的那种链接部分,由于是手机这样的嵌入式系统,硬件比较特殊,可能也涉及底层的驱动及库的支持,提供驱动+库支持+系统软件框架之上支持应用程序运行的软件开发。
    操作系统、中间件、应用程序,构成了Android.
    十七、dalvik虚拟机和art对比
    Dalvik
    Android4.4及以前使用的都是Dalvik虚拟机,我们知道Apk在打包的过程中会先将java等源码通过javac编译成.class文件,但是我们的Dalvik虚拟机只会执行.dex文件,这个时候dx会将.class文件转换成Dalvik虚拟机执行的.dex文件。Dalvik虚拟机在启动的时候会先将.dex文件转换成快速运行的机器码,又因为65535这个问题,导致我们在应用冷启动的时候有一个合包的过程,最后导致的一个结果就是我们的app启动慢,这就是Dalvik虚拟机的JIT特性(Just In Time)。
    ART
    ART虚拟机是在Android5.0才开始使用的Android虚拟机,ART虚拟机必须要兼容Dalvik虚拟机的特性,但是ART有一个很好的特性AOT(ahead of time),这个特性就是我们在安装APK的时候就将dex直接处理成可直接供ART虚拟机使用的机器码,ART虚拟机将.dex文件转换成可直接运行的.oat文件,ART虚拟机天生支持多dex,所以也不会有一个合包的过程,所以ART虚拟机会很大的提升APP冷启动速度。
    ART优点:
    加快APP冷启动速度
    提升GC速度
    提供功能全面的Debug特性
    ART缺点:
    APP安装速度慢,因为在APK安装的时候要生成可运行.oat文件
    APK占用空间大,因为在APK安装的时候要生成可运行.oat文件
    十八、Activity 怎么和Service 绑定
    实现service中的onBind()函数以返回service实例给activity
    1、创建service类和activity类。
    2、在service类中定义一个内部类继承自Binder()类
    3.在activity中完成绑定,通过bindservice()
    十九.Activity与Service数据通信
    三种方式:
    1、绑定服务,利用ServiceConnection类,同时让Activity实现该类,重写该类中的两个方法,即绑定成功()和绑定失败()。
    让我们的ServiceActivity去实现ServiceConnection接口,实现接口之后,重写onServiceConnected()和onServiceDisconnected()两个方法。
    首先我们要创建好一个Binder对象,接下来在OnServiceConnected当中获取到该Binder对象。最后利用Binder当中setData()方法来向Service传递数据。
    2、简单通信,利用Intent进行传值(Intent组件在activity之间、activity与fragment之间数据通信都会用到),该方法简单,但是也只能传递较简单的数据。
    3、利用callback接口,将Handler来监听服务中的进程的变化(会有子线程到主线程的切换,因此用到了Handler)。
    二十、Service中能否进行耗时操作?
    Service默认并不会运行在子线程中,也不运行在一个独立的进程中,它同样执行在主线程中(UI线程)。也就是说,我们不要在Service中进行耗时操作,否则可能会出现主线程被阻塞(ANR)的情况。
    二十一、线程和进程之间的通信方式
    一、Android进程间通信方式
    1.Bundle
    由于Activity,Service,Receiver都是可以通过Intent来携带Bundle传输数据的,所以我们可以在一个进程中通过Intent将携带数据的Bundle发送到另一个进程的组件。
    缺点:无法传输Bundle不支持的数据类型。
    2.ContentProvider
    ContentProvider是Android四大组件之一,以表格的方式来储存数据,提供给外界,即Content Provider可以跨进程访问其他应用程序中的数据。用法是继承ContentProvider,实现onCreate,query,update,insert,delete和getType方法,onCreate是负责创建时做一些初始化的工作,增删查改的方法就是对数据的查询和修改,getType是返回一个String,表示Uri请求的类型。注册完后就可以使用ContentResolver去请求指定的Uri。
    3.文件
    两个进程可以到同一个文件去交换数据,我们不仅可以保存文本文件,还可以将对象持久化到文件,从另一个文件恢复。要注意的是,当并发读/写时可能会出现并发的问题。
    4.Broadcast
    Broadcast可以向android系统中所有应用程序发送广播,而需要跨进程通讯的应用程序可以监听这些广播。
    5.AIDL方式
    Service和Content Provider类似,也可以访问其他应用程序中的数据,Content Provider返回的是Cursor对象,而Service返回的是Java对象,这种可以跨进程通讯的服务叫AIDL服务。
    AIDL通过定义服务端暴露的接口,以提供给客户端来调用,AIDL使服务器可以并行处理,而Messenger封装了AIDL之后只能串行运行,所以Messenger一般用作消息传递。
    6.Messenger
    Messenger是基于AIDL实现的,服务端(被动方)提供一个Service来处理客户端(主动方)连接,维护一个Handler来创建Messenger,在onBind时返回Messenger的binder。
    双方用Messenger来发送数据,用Handler来处理数据。Messenger处理数据依靠Handler,所以是串行的,也就是说,Handler接到多个message时,就要排队依次处理。
    7.Socket
    Socket方法是通过网络来进行数据交换,注意的是要在子线程请求,不然会堵塞主线程。客户端和服务端建立连接之后即可不断传输数据,比较适合实时的数据传输
    二、Android线程间通信方式
    一般说线程间通信主要是指主线程(也叫UI线程)和子线程之间的通信,主要有以下两种方式:
    1.AsyncTask机制
    AsyncTask,异步任务,也就是说在UI线程运行的时候,可以在后台的执行一些异步的操作;AsyncTask可以很容易且正确地使用UI线程,AsyncTask允许进行后台操作,并在不显示使用工作线程或Handler机制的情况下,将结果反馈给UI线程。但是AsyncTask只能用于短时间的操作(最多几秒就应该结束的操作),如果需要长时间运行在后台,就不适合使用AsyncTask了,只能去使用Java提供的其他API来实现。
    2.Handler机制
    Handler,继承自Object类,用来发送和处理Message对象或Runnable对象;Handler在创建时会与当前所在的线程的Looper对象相关联(如果当前线程的Looper为空或不存在,则会抛出异常,此时需要在线程中主动调用Looper.prepare()来创建一个Looper对象)。使用Handler的主要作用就是在后面的过程中发送和处理Message对象和让其他的线程完成某一个动作(如在工作线程中通过Handler对象发送一个Message对象,让UI线程进行UI的更新,然后UI线程就会在MessageQueue中得到这个Message对象(取出Message对象是由其相关联的Looper对象完成的),并作出相应的响应)。
    三、Android两个子线程之间通信
    主线程和子线程之间的通信可以通过主线程中的handler把子线程中的message发给主线程中的looper,或者,主线程中的handler通过post向looper中发送一个runnable。但looper默认存在于main线程中,子线程中没有Looper,该怎么办呢?其实原理很简单,把looper绑定到子线程中,并且创建一个handler。在另一个线程中通过这个handler发送消息,就可以实现子线程之间的通信了。
    二十二、自定义控件view的绘制过程
    View的绘制流程:OnMeasure()——>OnLayout()——>OnDraw()
    第一步:OnMeasure():测量视图大小。从顶层父View到子View递归调用measure方法,measure方法又回调OnMeasure。
    第二步:OnLayout():确定View位置,进行页面布局。从顶层父View向子View的递归调用view.layout方法的过程,即父View根据上一步measure子View所得到的布局大小和布局参数,将子View放在合适的位置上。
    第三步:OnDraw():绘制视图。ViewRoot创建一个Canvas对象,然后调用OnDraw()。六个步骤:①、绘制视图的背景;②、保存画布的图层(Layer);③、绘制View的内容;④、绘制View子视图,如果没有就不用;
    二十三、Fragment与Fragment、Activity通信的方式
    1.直接在一个Fragment中调用另外一个Fragment中的方法
    我们可以直接在一个Fragment中调用另外一个Fragment的公开方法,前提是要先拿到另外一个Fragment的实例
    2.使用接口
    接口可以实现两个Fragment之间的通信,也可以实现Fragment和Activity之间的通信,这大概是用的比较多的一种方式,也是个人比较推荐的一种方式,使用接口来实现两个Fragment之间通信,要通过宿主Activity中转一下,如果是Fragment和宿主Activity通信则直接调用即可
    3.使用广播机制
  8. Fragment和Activity的交互:
    1、在Fragment中调用Activity中的方法:
    Fragment可以通过getActivity()方法来获得Activity的实例,然后就可以调用一些例如findViewById()之类的方法。例如:
    View listView = getActivity().findViewById(R.id.list);
    但是注意调用getActivity()时,fragment必须和activity关联(attached to an activity),否则将会返回一个null。
    另外,当碎片中需要使用Context对象时,也可以使用getActivity()方法,因此获取到的活动本身就是一个Context对象
    2、在Activity中调用Fragment中的方法:(要用到接口回调)
    activity也可以获得一个fragment的引用,从而调用fragment中的方法。获得fragment的引用要用FragmentManager,之后可以调用findFragmentById() 或者 findFragmentByTag()。
  9. Fragment与Fragment之间的通信:
    基本思路是:首先在一个Fragment中可以得到与它相关联的Activity,然后再通过这个Activity去获取另外一个Fragment的实例,这样就实现了不同Fragment之间的通信
    6.eventbus
    EventBus是一款针对Android优化的发布/订阅(publish/subscribe)事件总线。主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,线程之间传递消息。简化了应用程序内各组件间、组件与后台线程间的通信。优点是开销小,代码更优雅,以及将发送者和接收者解耦。比如请求网络,等网络返回时通过Handler或Broadcast通知UI,两个Fragment之间需要通过Listener通信,这些需求都可以通过EventBus实现。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值