一、基础/UI
安卓的数据存储方式有哪些?
(1)使用SharedPreferences存储数据 轻型的数据存储方式,存储的key-value键值对数据
(2)文件存储数据 写入和读取文件I/O
(3)SQLite数据库存储数据 轻量级嵌入式数据库,用来存储大量复杂的关系数据
(4)使用ContentProvider存储数据 主要用于应用程序之间进行数据交换,还可以选择只对哪一部分数据进行共享,可保证程序中的隐私数据不会有泄漏风险;
补间动画跟属性动画的区别
补间动画
只能够为View添加动画,功能比较单调,只有四种动画(透明度,旋转,倾斜和位移),View的属性没有改变,其位置与大小都不变
属性动画
可以为一个对象的任意属性添加动画,对象自己的属性会被真的改变。
插值器(Interpolator)决定值的变化规律(匀速、加速),即决定的是变化趋势;而接下来的具体变化数值则交给估值器
ValueAnimator 是 ObjectAnimator 的父类,他两之间的区别是,ObjectAnimator 在ValueAnimator 的基础上,通过反射技术实现了动画功能,也就像我刚刚所举的例子,子要给了 ObjectAnimator 两个值(from,to),在确定动画类型(“scale,translate”),他就能自动生成动画。
与之形成区别,虽然我们同样需要给 ValueAnimator 传递起始和最终两个值,但是 ValueAnimator 并不会自动去执行什么,而是会通过addUpdateListener的监听方法,在时间插值器的作用下,有序的返回一连串数值,然后我们就可以通过这些数值,对控件进行设置。
App里所有textveiw的字体大小以及布局都一样 你可以用什么方法去实现
使用style
Android 屏幕适配
手机像素(px):一个小黑点就是像素
手机尺寸:屏幕的对角线的长度(寸)
手机分辨率:整个屏幕一共有多少个点(像素),常见取值 480px X 800px ,320px X 480px等
屏幕像素密度(dpi)= √(宽2 + 高2)/ 屏幕尺寸
density = dpi / 160
px与px与dip的互相转换 :dp = px / density
(1)dp+自适应布局+weight比例布局直接适配
(2)dimens基于px的适配(宽高限定符适配)
(3)dimen 基于dp的适配(smallestWidth适配)
(4)今日头条适配(修改手机的设备密度 density):
通过修改density值,强行把所有不同尺寸分辨率的手机的宽度dp值改成一个统一的值; 在不同的设备中,动态修改density值,从而保证(手机像素宽度)px/density这个值始终是360dp,这样的话,就能保证UI在不同的设备上表现一致了。
布局文件里面怎么复用其他文件
include:引入重复使用的相同布局
merge:减少include布局的层级,将子元素直接添加到merge标签的parent中,对merge标签设置的属性是无效的。
ViewStub:其实就是一个宽高都为0的一个View,它默认是不可见的,只有通过调用setVisibility函数或者Inflate函数才会将其要装载的目标布局给加载出来,inflate只能被调用一次
序列化,Serializable和parceable区别
(1)读写方面:Serializable是通过使用IO流的形式将数据读写入在硬盘上,而Parcelable则是在内存中直接进行读写。
(2)Serializable在序列化的时候会产生大量的临时变量,Parcelable是以Ibinder作为信息载体的.在内存上的开销比较小
(3)Serializable效率低,而Parcelable效率高
如果是在内存中使用序列化用Parcelable,如果是磁盘中使用则用 Serializable
Android自定义控件有哪些实现方式
(1)继承现有控件(TextView/ImageView/LinearLayout),对其控件的功能进行拓展
(2)将现有控件进行组合,实现功能更加强大控件。
(3)重写View/ViewGroup实现全新的控件
自定义View,View 绘制流程
View的工作流程主要是指measure、layout、draw这三大流程,即测量、布局和绘制,其中measure确定View的测量宽/高,layout确定View的最终宽/高和四个顶点的位置,而draw则将View绘制到屏幕上
View的绘制过程遵循如下几步:
绘制背景 background.draw(canvas)
绘制自己(onDraw)
绘制 children(dispatchDraw)
绘制装饰(onDrawScollBars)
自定义 View 的一般步骤如下:
(1)创建自定义 View 的类:可以通过继承 View 或者 ViewGroup 类来创建自定义 View 的类,并实现相应的方法来实现自定义 View 的功能。
(2)提供自定义 View 的属性:在自定义 View 的类中,通过使用 @Attr、@Styleable 注解来定义自定义 View 的属性,并在 attrs.xml 文件中声明对应的属性。
(3)重写 onMeasure 方法:onMeasure 方法用于测量自定义 View 的大小,可以根据自定义 View 的属性和布局的要求来计算自定义 View 的测量值。
(4)重写 onDraw 方法:onDraw 方法用于绘制自定义 View,可以在该方法中使用 Canvas 对象进行绘制操作。
(5)处理触摸事件:如果需要处理触摸事件,可以重写 onTouchEvent 方法来处理。
(6)处理滑动事件:如果需要支持滑动操作,可以使用 Scroller 类来实现平滑滚动效果。
(7)提供动画效果:可以使用动画来为自定义 View 添加动态效果,比如使用属性动画实现 View 的平移、旋转、缩放等效果。
(8)处理自定义 View 的生命周期:可以通过重写 onAttachedToWindow、onDetachedFromWindow 等方法来处理自定义 View 的生命周期。 通过以上步骤,就可以完成自定义 View 的实现。
子线程是否可以更新UI
ViewRootImpl对象是在onResume方法回调之后才创建,在生命周期的onCreate方法里,甚至是onResume方法里都可以实现子线程更新UI,因为此时还没有创建ViewRootImpl对象,并不会进行是否为主线程的判断,子线程可以在ViewRootImpl还没有创建之前更新UI的
,访问UI是没有加对象锁的,在子线程环境下更新UI,会造成各种未知风险的
在onResume中是否可以测量宽高
在 onResume() 中直接获取或者调用创建的 Handler 的 post 方法都是获取不到 View 宽高的,需要通过 View.post 才能获取。
handler.post 的方式是不能够保证 runnable一定是在view进行了onMeasure后执行的, handler.post(Runnable) 是无法正确的获取不到 View 的真实宽高。
View.post(Runnable) 的 Message 会在 performMeaure() 之前被调用, Message 并没有立即被执行,因为此时主线程的 Handler 正在执行的 Message 是 TraversalRunnable,而 performMeaure() 方法也是在该 Message 中被执行,所以排队等到主线程的 Handler 执行到我们 post 的 Message 时,View 的宽高已经测量完毕,因此能够获取到 View 的宽高。
invalidate与requestLayout的区别
(1)调用invalidate()方法用来刷新整个视图的,当视图的内容,可见性发生变化,onDraw(Canvas canvas)方法会被调用,不会导致measure和layout方法被调用,必须在UI线程中调用,如果想在非UI线程中调用,则使用postInvalidate。
(2)requestLayout()是在view的布局发生变化时调用,布局的变化包含位置,大小,调用这个方法,会导致布局重绘,调用measure,layout,draw的过程
Andriod事件分发机制
View事件分发本质就是对MotionEvent事件分发的过程。即当一个MotionEvent发生后,系统将这个点击事件传递到一个具体的View上
点击事件的传递顺序:Activity(Window)→ViewGroup→ View
事件分发过程由三个方法共同完成:
dispatchTouchEvent:用来进行事件的分发。如果事件能够传递给当前View,那么此方法一定会被调用,返回结果受当前View的onTouchEvent和下级View的dispatchTouchEvent方法的影响,表示是否消耗当前事件
onInterceptTouchEvent:在上述方法内部调用,对事件进行拦截。该方法只在ViewGroup中有,View(不包含 ViewGroup)是没有的。一旦拦截,则执行ViewGroup的onTouchEvent,在ViewGroup中处理事件,而不接着分发给View。且只调用一次,返回结果表示是否拦截当前事件
onTouchEvent: 在dispatchTouchEvent方法中调用,用来处理点击事件,返回结果表示是否消耗当前事件

如何解决View的事件冲突 ? 举个开发中遇到的例子 ?
常见开发中事件冲突的有ScrollView与RecyclerView的滑动冲突、RecyclerView内嵌同时滑动同一方向
滑动冲突的处理规则:
对于由于外部滑动和内部滑动方向不一致导致的滑动冲突,可以根据滑动的方向判断谁来拦截事件。
对于由于外部滑动方向和内部滑动方向一致导致的滑动冲突,可以根据业务需求,规定何时让外部View拦截事件,何时由内部View拦截事件。
对于上面两种情况的嵌套,相对复杂,可同样根据需求在业务上找到突破点。
滑动冲突的实现方法:
外部拦截法:指点击事件都先经过父容器的拦截处理,如果父容器需要此事件就拦截,否则就不拦截。具体方法:需要重写父容器的onInterceptTouchEvent方法,在内部做出相应的拦截。
内部拦截法:指父容器不拦截任何事件,而将所有的事件都传递给子容器,如果子容器需要此事件就直接消耗,否则就交由父容器进行处理。具体方法:需要配合requestDisallowInterceptTouchEvent方法。
RecyclerView的缓存机制
RecyclerView拥有四级缓存,它们分别是:
(1)Scrap缓存:包括mAttachedScrap和mChangedScrap,又称屏内缓存,不参与滑动时的回收复用,只是用作临时保存的变量。
mAttachedScrap:只保存重新布局时从RecyclerView分离的item的无效、未移除、未更新的holder。
mChangedScrap:只会负责保存重新布局时发生变化的item的无效、未移除的holder。
(2)CacheView缓存:mCachedViews又称离屏缓存,用于保存最新被移除(remove)的ViewHolder,已经和RecyclerView分离的视图,这一级的缓存是有容量限制的,默认最大数量为2。
(3)ViewCacheExtension:mViewCacheExtension又称拓展缓存,为开发者预留的缓存池,开发者可以自己拓展回收池,一般不会用到。
(4)RecycledViewPool:终极的回收缓存池,真正存放着被标识废弃(其他池都不愿意回收)的ViewHolder的缓存池。这里的ViewHolder是已经被抹除数据的,没有任何绑定的痕迹,需要重新绑定数据。
RecyclerView的回收原理
(1)如果是RecyclerView不滚动情况下缓存(比如删除item)、重新布局时。
把屏幕上的ViewHolder与屏幕分离下来,存放到Scrap中,即发生改变的ViewHolder缓存到mChangedScrap中,不发生改变的ViewHolder存放到mAttachedScrap中。
剩下ViewHolder会按照mCachedViews > RecycledViewPool的优先级缓存到mCachedViews或者RecycledViewPool中。
(2)如果是RecyclerView滚动情况下缓存(比如滑动列表),在滑动时填充布局。
先移除滑出屏幕的item,第一级缓存mCachedViews优先缓存这些ViewHolder。
由于mCachedViews最大容量为2,当mCachedViews满了以后,会利用先进先出原则,把旧的ViewHolder存放到RecycledViewPool中后移除掉,腾出空间,再将新的ViewHolder添加到mCachedViews中。
最后剩下的ViewHolder都会缓存到终极回收池RecycledViewPool中,它是根据itemType来缓存不同类型的ArrayList,最大容量为5。
RecyclerView的复用原理
当RecyclerView要拿一个复用的ViewHolder时:
如果是预加载,则会先去mChangedScrap中精准查找(分别根据position和id)对应的ViewHolder。
如果没有就再去mAttachedScrap和mCachedViews中精确查找(先position后id)是不是原来的ViewHolder。
如果还没有,则最终去mRecyclerPool找,如果itemType类型匹配对应的ViewHolder,那么返回实例,让它重新绑定数据。
如果mRecyclerPool也没有返回ViewHolder才会调用createViewHolder()重新去创建一个。
这里有几点需要注意:
在mChangedScrap、mAttachedScrap、mCachedViews中拿到的ViewHolder都是精准匹配。
mAttachedScrap和mCachedViews没有发生变化,是直接使用的。
mChangedScrap由于发生了变化,mRecyclerPool由于数据已被抹去,所以都需要调用onBindViewHolder()重新绑定数据才能使用。
RecyclerView的性能优化
(1)使用notifyItemChange、notifyItemInserted、notifyItemMoved和notifyItemRemoved等方法替代notifyDataSetChanged方法
(2)DiffUtil/AsyncListDiffer进行局部刷新 (减少全局刷新)
(3)setHasFixedSize (避免 requestLayout 浪费)
确定Item的改变不会影响RecyclerView的宽高的时候可以设置setHasFixedSize(true),这样RecyclerView在onMeasure阶段可以直接计算出高度,不需要多次计算子ItemView的高度。
(4)减少布局嵌套 (减少onCreateViewHolder时间)
减少item的过度绘制, 减少布局层级,尽量少的布局嵌套,尽量少的控件
(5)onBindViewHolder方法里面只做纯粹的数据绑定操作,去除耗时操作
(6)当两个数据源大部分相似时,使用swapAdapter代替setAdapter。这是因为setAdapter会直接清空RecyclerView上的所有缓存,但是swapAdapter会将RecyclerView上的ViewHolder保存到pool中,这样当数据源相似时,就可以提高缓存的复用率
(7)setItemViewCacheSize (加大RecyclerView缓存)
加大RecyclerView缓存, 比如cacheview大小默认为2,可以设置大点,用空间来换取时间,提高流畅度,此方法是拿空间换时间,要充分考虑应用内存问题,根据应用实际使用情况设置大小
(8)recycledViewPool.setMaxRecycledViews (增加RecycledViewPool缓存数量)
每个类型默认缓存5个,此方法是拿空间换时间,要充分考虑应用内存问题,根据应用实际使用情况设置大小
Android与JS的交互方式
(1)Android调用JS代码的方法有2种:
WebView的loadUrl:页面刷新,没有有返回值
WebView的evaluateJavascript:不会使页面刷新,有返回值
(2)JS调用Android代码的方法

SurfaceView和View的区别
(1)View需要在UI线程对画面进行刷新,而SurfaceView可在子线程进行页面的刷新
(2)View适用于主动更新的情况,而SurfaceView适用于被动更新,如频繁刷新,这是因为如果使用View频繁刷新会阻塞主线程,导致界面卡顿
(3)SurfaceView在底层已实现双缓冲机制,而View没有,因此SurfaceView更适用于需要频繁刷新、刷新时数据处理量很大的页面(如视频播放界面)
Android各版本的更新适配
Android5.0 Material Design设计风格
Android6.0 动态权限
Android7.0 一个屏幕可以多个APP展示
Android8.0 禁用了后台server ,禁用静态广播,需要动态注册
Android10.0 文件读写需要 requestLegacyExternalStorage=“true”
Android11.0 禁止根目录存储(降编译版本可解决,但不建议)
进程间通信,线程间通信
线程间通信方式:Handler、RxJava、HandlerThread、IntentService、协程
进程间通信方式:

AIDL 的全称是什么?如何工作?能处理哪些类型的数据
(1)AIDL使用方法
服务端:1.创建aidl接口;2.实现接口,并向客户端开放接口;3.创建服务,返回binder。
客户端:1.绑定服务;2.实现ServiceConnection绑定监听;3.在绑定成功的回调中,将IBinder转换成AIDL的接口代理对象。
客户端和服务端绑定成功后,就可以通过AIDL的接口代理对象,就像直接调用本地方法一样,调用服务端的方法了。需要注意的是,AIDL间传递的对象要实现Parcelable接口。
(2)AIDL支持的数据类型
Java基本数据类型(int,boolean等)
引用数据类型,比如:String与CharSequence,当然也可以使用自定义数据类型。
自定义的数据类型,但是有个条件,那就是数据需要实现了 Parcelable 接口。
List, Map和Parcelables类型, 这些类型内所包含的数据成员也只能是基本数据类型、String等其他支持的类型。
APK的打包流程
1.通过AAPT工具进行资源文件(包括AndroidManifest.xml、布局文件、各种xml资源等)的打包,生成R.java文
件。
2.通过AIDL工具处理AIDL文件,生成相应的java文件。
3.通过Javac工具编译项目源码,生成Class.文件。
4.通过DX工具将所有的Class文件转换成DEX文件,该过程主要完成ava字节码转换成Dalvik字节码,压缩常量池以及清除冗余信息等工作。
5.通过ApkBuilder.工具将资源文件、DEX文件打包生成APK文件。
6.利用KeyStore对生成的APK文件进行签名。
7.如果是正式版的APK,还会利用ZipAlig工具进行对齐处理,对齐的过程就是将APK文件中所有的资源文件举例文件的起始距离都偏移4字节的整数倍,这样通过内存映射访问APK文件的速度会更快。
常用加密算法
(1)DES
概述:对称加密算法。
优点:算法公开,计算量小,加密速度快,加密效率高。
缺点:双方使用相同的密钥,不能保证安全。
(2)AES
概述:对称加密算法。
优点:算法公开,计算量小,加密速度快,加密效率高。
缺点:双方使用相同的密钥,不能保证安全。
(3)SHA
概述:非对称加密算法。安全分散算法,数字签名工具。这种加密是在缓存key时使用的著名图像加载框架Glide。
优点:破解难度大,不可逆。
缺点:可通过穷举法破解。
(4)RSA
概述:非对称加密算法,最流行的公钥密码算法,使用长度可变的密钥。
优点:不可逆,可用于数据加密,也可用于数字签名。
缺点:RSA非对称加密内容长度有限,1024位key最多只能加密127位数据。
(5)MD5
概述:非对称加密算法。整个过程:Message-Digestalgorithm,翻译成新闻摘要算法。
优点:不可逆、压缩、不易修改、易计算。
缺点:穷举法可以破解。
APP应用启动流程
1、启动APP进程: 当我们点击Launcher桌面程序的APP图标时,Launcher程序会调用startActivity()函数,通过Binder跨进程通信,发送消息给system_server进程。在system_server进程中,由AMS通过socket通信告知Zygote进程fork出一个子进程(APP进程)。
2、开启APP主线程: APP进程启动后,会实例化一个ActivityThread,并执行其main函数,同时会创建ApplicationThread、Looper、Handler对象,开启主线程消息循环Looper.loop()。
3、创建并初始化Application和Activity: ActivityThread的main函数通过调用attach方法进行 Binder 通信,通知system_server进程执行AMS的attachApplication方法。在attachApplication方法中,AMS分别通过bindApplication、scheduleLaunchActivity方法,通知APP进程的主线程Handler,对APP进程的Application和Activity进行初始化,并执行Application、Activity的生命周期。
4、UI布局和绘制: 主线程Handler初始化Activity时,会执行创建PhoneWindow、初始化DecorView的操作,并且添加布局到DecorView的ContentView中。ContentView,对应着Activity的setContentView中设置的layout.xml布局文件所在的最外层父布局
类加载
当一个ClassLoader去加载一个类的时候,它会去判断该类是否已经加载,如果没有,它不会马上去加载,而是委托给父加载器进行查找,
这样递归一直找到最上层的ClassLoader类,如果找到了,就直接返回这个类所对应的Class对象,如果都没有加载过,就从顶层的ClassLoader去开始依次向下查找,
每个加载器会从自己规定的位置去查找这个类,如果没有,最后再由请求发起者去加载该类。PathClassLoader
双亲委派机制的好处:
1:避免重复加载,如果已经加载过一次Class,就不需要再次加载,而是先从缓存中直接读取。
2:更加安全,因为虚拟机认为只有两个类名一致并且被同一个类加载器加载的类才是同一个类,所以这种机制保证了系统定义的类不会被替代。
二、Android组件
1.Activity
Activity生命周期
onCreate:当Activity第一次被运行时调用此方法,可用于加载布局视图,获取控件命名空间等一些初始化工作。
onRestart:当Activity被重新启动的时候,调用此方法
onStart :已经从不可见到可见状态,但还是无法与用户进行交互。
onResume :出现在前台工作了,与用户可以进行交互
onPause :表示Activity正在暂停,但Activity依然可见,可以执行一些轻量级操作,但一般不会进行太多操作,因为这样会影响用户体验。
onStop :表示Activity即将暂停,此时Activity工作在后台,已经不可见了,可以与onPause方法一样做一些轻量级操作,但依然不能太耗时。
onDestroy :活动即将被销毁。
Android中Activity的启动模式
Standard(标准模式) 标准模式是 Activity 的默认启动模式。每次启动 Activity 都会创建一个新的实例。
SingleTop(栈顶复用模式) 模式表示如果当前 Activity 在栈顶,则直接复用该 Activity,不会创建新的实例。如果不在栈顶,则创建新的实例,并加入任务栈的栈顶。适用于需要及时更新数据的情况,比如聊天界面、通知界面等。
SingleTask(栈内复用模式)如果当前任务栈中不存在该 Activity,则创建新的实例,并放在栈顶。如果存在,则将该 Activity 上面的所有 Activity 弹出栈,使其处于栈顶位置。适用于需要保持唯一性的 Activity,比如主界面、登录界面等。
SingleInstance(单实例模式)表示 Activity 是全局的,独立于其他任务栈。在该模式下,系统会创建一个新的任务栈来存放该 Activity 的实例,并且该任务栈中只能存在该 Activity 的实例。适用于需要和其他应用程序隔离的 Activity,比如电话界面、相机界面等。
2.Fragment

Activity与fragment通信方式
(1)使用接口回调
Activity 可以定义一个接口,在 Fragment 中实现该接口,并在 Activity 中获取 Fragment 实例后将该接口传递给 Fragment,这样 Fragment 就可以通过接口回调的方式与 Activity 进行通信
(2)使用广播
Activity 可以通过发送广播的方式通知 Fragment 进行相应的操作,Fragment 可以注册广播接收器并在接收到广播时执行相应的操作
(3)使用事件总线
事件总线是一种常用的通信方式,常见的事件总线包括 EventBus、RxJava、LiveData。
Activity 可以发送事件,Fragment 可以订阅事件并执行相应的操作
(4)直接调用方法
如果 Fragment 与 Activity 之间的关系比较紧密,也可以直接调用 Activity 中的方法进行通信。Activity 可以获取 Fragment 实例并调用其方法,或者 Fragment 可以通过 getActivity() 方法获取 Activity 实例并直接调用其方法。需要注意的是,直接调用方法可能会导致耦合性较高,建议在必要时才使用
3.BroadcastReceiver
广播有几种形式
(1)普通广播:开发者自身定义 intent的广播(最常用),所有的广播接收器几乎会在同一时刻接受到此广播信息,接受的先后顺序随机;
(2)有序广播:发送出去的广播被广播接收者按照先后顺序接收,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递,且优先级(priority)高的广播接收器会先收到广播消息。(3)有序广播可以被接收器截断使得后面的接收器无法收到它;
(3)本地广播:仅在自己的应用内发送接收广播,也就是只有自己的应用能收到,数据更加安全,效率更高,但只能采用动态注册的方式;
(4)粘性广播:这种广播会一直滞留,当有匹配该广播的接收器被注册后,该接收器就会收到此条广播;
广播的两种注册方式

4.Service
Service的生命周期
(1)onCreate():如果service没被创建过,调用startService()后会执行onCreate()回调;如果service已处于运行中,调用startService()不会执行onCreate()方法。也就是说,onCreate()只会在第一次创建service时候调用,多次执行startService()不会重复调用onCreate(),此方法适合完成一些初始化工作;
(2)onStartComand():服务启动时调用,此方法适合完成一些数据加载工作,比如会在此处创建一个线程用于下载数据或播放音乐;
(3)onBind():服务被绑定时调用;
(4)onUnBind():服务被解绑时调用;
(5)onDestroy():服务停止时调用;
Service的两种启动方式?区别在哪?
startService():通过这种方式调用startService,onCreate()只会被调用一次,多次调用startSercie会多次执行onStartCommand()和onStart()方法。如果外部没有调用stopService()或stopSelf()方法,service会一直运行。
bindService():如果该服务之前还没创建,系统回调顺序为onCreate()→onBind()。如果调用bindService()方法前服务已经被绑定,多次调用bindService()方法不会多次创建服务及绑定。如果调用者希望与正在绑定的服务解除绑定,可以调用unbindService()方法,回调顺序为onUnbind()→onDestroy();
设计一个音乐播放器,service怎么启动
startService与bindService同时启动,可通过调用 startService()启动该服务,让服务无限期运行;此外,还可通过调用 bindService() 使客户端绑定到服务。Activity 便可启动服务进行音乐播放,即使用户离开应用,音乐播放也不会停止。 然后,当用户返回应用时,Activity 可绑定到服务,重新获得回放控制权。
Service不被杀死
(1)提高Service的优先级
在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,1000是最高值
(2)在onDestroy方法里重启Service
当service走到onDestroy()时,发送一个自定义广播,当收到广播时,重新启动service;
(3)提升Service进程的优先级
进程优先级由高到低:前台进程 一 可视进程 一 服务进程 一 后台进程 一 空进程
可以使用startForeground将service放到前台状态,这样低内存时,被杀死的概率会低一些;
Android系统中Service和IntentService的区别,IntentService的原理
Service 是长期运行在后台的应用程序组件,不是一个单独的进程,它和应用程序在同一个进程中,也不是一个线程,它和线程没有任何关系,
所以它不能直接处理耗时操作。如果有耗时操作就必须开启一个单独的线程来处理。
IntentService 是继承于 Service 并处理异步请求的一个类,在 IntentService 内有一个工作线程来处理耗时操作,
启动 IntentService 的方式和启动传统 Service 一样,具有高优先级,适合高优先级的后台任务,且不容易被系统杀死,任务执行后会自动停止。
可以多次启动,每个耗时操作都会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,执行完第一个再执行第二个
IntentService在onCreate里面初始化了一个HandlerThread,每次调用onStartCommand的时候,通过mServiceHandler发送一个消息,
消息中包含我们的intent。然后在该mServiceHandler的handleMessage中去回调onHandleIntent(intent);当依次执行完任务后,
回调用 stopSelf销毁我们的Service.当任务完成销毁Service回调onDestory,在onDestroy中释放了我们的Looper
5.ContentProvider
AIDL可使用的参数类型
基本数据类型、引用数据类型、自定义数据类型(必须实现Parcelable接口)
A跟B在同一个进程里,A能创建B吗,进程间通信有哪些,他们之间的区别,进程间通信的内存交换方式有哪些,进程间通信机制
可以创建。
不同的进程之间以某种方式进行数据交换就是进程通信。
进程间通信有:管道、消息队列、共享内存和 Socket 、Binder等 IPC 机制。
(1)管道/消息队列:信息复制两次,额外的CPU消耗;不合适频繁或信息量大的通信;
(2)共享内存:无须复制,共享缓冲区直接附加到进程虚拟地址空间,速度快;但进程间的同步问题操作系统无法实现,必须各进程利用同步工具解决;
(3)Socket:作为更通用的接口,传输效率低(涉及io读写),主要用于不通机器或跨网络的通信;
(4)Binder:是 Android系统中跨进程通讯(IPC)的一种方式,Android中ContentProvider、Intent、aidl都是基于Binder。1…Binder使用mmap机制,只拷贝了一次数据,性能上仅次于共享内存;2.采用Client/Server架构,实现面向对象的调用方式,调用如同调用Java对象,使用简单;3.为每个App分配了UID/PID来鉴别身份标识,通信时检测UID/PID进行有效性检测,提高了安全性)
该博客围绕Android开发展开,介绍了基础/UI方面的数据存储、动画、屏幕适配等知识,还阐述了Android组件如Activity、Fragment、BroadcastReceiver、Service和ContentProvider的特性、生命周期、启动模式及通信方式等,同时涉及事件分发、缓存机制和进程间通信等内容。
933

被折叠的 条评论
为什么被折叠?



