第一天----Android笔记

WeChat–Android面试题基础精选,附答案

1、Activity的常用生命周期就只有如下7个

onCreate():表示Activity正在被创建,常用来初始化工作,比如调用setContentView加载界面布局资源,初始化Activity所需数据等;
onRestart():表示Activity正在重新启动,一般情况下,当前Acitivty从不可见重新变为可见时,OnRestart就会被调用;
onStart():表示Activity正在被启动,此时Activity可见但不在前台,还处于后台,无法与用户交互;
onResume():表示Activity获得焦点,此时Activity可见且在前台并开始活动,这是与onStart的区别所在;
onPause():表示Activity正在停止,此时可做一些存储数据、停止动画等工作,但是不能太耗时,因为这会影响到新Activity的显示,onPause必须先执行完,新Activity的onResume才会执行;
onStop():表示Activity即将停止,可以做一些稍微重量级的回收工作,比如注销广播接收器、关闭网络连接等,同样不能太耗时;
onDestroy():表示Activity即将被销毁,这是Activity生命周期中的最后一个回调,常做回收工作、资源释放;

从整个生命周期来看,onCreate和onDestroy是配对的,分别标识着Activity的创建和销毁,并且只可能有一次调用;
从Activity是否可见来说,onStart和onStop是配对的,这两个方法可能被调用多次;
从Activity是否在前台来说,onResume和onPause是配对的,这两个方法可能被调用多次;
除了这种区别,在实际使用中没有其他明显区别;

2、Activity A 启动另一个Activity B 会调用哪些方法?如果B是透明主题的又或则是个DialogActivity呢 ?

Activity A 的onPause() → Activity B的onCreate() → onStart() → onResume() → Activity A的onStop();
如果B是透明主题又或则是个DialogActivity,则不会回调A的onStop;

3、Activity的四种启动模式、应用场景

standard标准模式:每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否已经存在,此模式的Activity默认会进入启动它的Activity所属的任务栈中;

singleTop栈顶复用模式:如果新Activity已经位于任务栈的栈顶,那么此Activity不会被重新创建,
同时会回调onNewIntent方法,如果新Activity实例已经存在但不在栈顶,那么Activity依然会被重新创建;

singleTask栈内复用模式:只要Activity在一个任务栈中存在,那么多次启动此Activity都不会重新创建实例,
并回调onNewIntent方法,此模式启动Activity A,系统首先会寻找是否存在A想要的任务栈,
如果不存在,就会重新创建一个任务栈,然后把创建好A的实例放到栈中;

singleInstance单实例模式:这是一种加强的singleTask模式,
具有此种模式的Activity只能单独地位于一个任务栈中,且此任务栈中只有唯一一个实例;

4、Activity常用的标记位Flags

FLAG_ACTIVITY_NEW_TASK : 对应singleTask启动模式,其效果和在XML中指定该启动模式相同;
FLAG_ACTIVITY_SINGLE_TOP : 对应singleTop启动模式,其效果和在XML中指定该启动模式相同;
FLAG_ACTIVITY_CLEAR_TOP : 此标记位的Activity,当它启动时,在同一个任务栈中所有位于它上面的Activity都要出栈。这个标记位一般会和singleTask模式一起出现,在这种情况下,
被启动Activity的实例如果已经存在,那么系统就会回调onNewIntent。
如果被启动的Activity采用standard模式启动,那么它以及连同它之上的Activity都要出栈,
系统会创建新的Activity实例并放入栈中;
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS : 具有这个标记的 Activity 不会出现在历史 Activity 列表中;

5、Activity跟window,view之间的关系?

Activity在创建时会调用 attach() 方法初始化一个PhoneWindow(继承于Window),
每一个Activity都包含了唯一一个PhoneWindow。

Activity通过setContentView实际上是调用的 getWindow().setContentView将View设置到PhoneWindow上,
而PhoneWindow内部是通过 WindowManager 的addView、removeView、updateViewLayout这三个方法来管理View,WindowManager本质是接口,最终由WindowManagerImpl实现

6、Activity的启动过程?(重点)

⾸先还是得当前系统中有没有拥有这个 Application 的进程。如果没有,则需要处理 APP 的启动过程。
在经过创建进程、绑定 Application 步骤后,才真正开始启动 Activity 的⽅法。

startActivity() ⽅法最终还是调⽤的 startActivityForResult()。
在 startActivityForResult() 中,真正去打开 Activity 的实现是在 Instrumentation 的execStartActivivity() ⽅法中。

在 execStartActivity() 中采⽤ checkStartActivityResult() 检查在 manifest 中是否已经注册,如果没有注册则抛出异常。
否则把打开 Activity 的任务交给 ActivityThread 的内部类 ApplicationThread,该类实现了 IApplicationThread 接⼝。
这个类完全搞定了 onCreate()、onStart() 等 Activity 的⽣命周期回调⽅法。

在 ApplicationThread 类中,有⼀个⽅法叫 scheduleLaunchActivity(),
它可以构造⼀个 Activity 记录,然后发送⼀个消息给事先定义好的 Handler。

这个 Handler 负责根据 LAUNCH_ACTIVITY 的类型来做不同的 Activity 启动⽅式。
其中有⼀个必要的⽅法 handleLaunchActivity() 。
在 handleLaunchActivity() 中,会把启动 Activity 交给 performLaunchActivity() ⽅法。

在 performLaunchActivity() ⽅法中,⾸先从 Intent 中解析出⽬标 Activity 的启动参数,
然后⽤ClassLoader 将⽬标 Activity 的类通过类名加载出来并⽤ newInstance() 来实例化⼀个对象。

创建完毕后, 开始调⽤ Activity 的 onCreate() ⽅法,⾄此,Activity 被成功启动。

7、Fragment的生命周期?

Fragment从创建到销毁整个生命周期中涉及到的方法依次为:onAttach()→onCreate()→onCreateView()→onActivityCreated()→
onStart()→onResume()→onPause()→onStop()→
onDestroyView()→onDestroy()→onDetach(),

其中和Activity有不少名称相同作用相似的方法,而不同的方法有:
onAttach():当Fragment和Activity建立关联时调用;
onCreateView():当fragment创建视图调用,在onCreate之后;
onActivityCreated():当与Fragment相关联的Activity完成onCreate()之后调用;
onDestroyView():在Fragment中的布局被移除时调用;
onDetach():当Fragment和Activity解除关联时调用;

8、Activity和Fragment都可包含布局、可有自己的生命周期

Fragment相比较于Activity多出4个回调周期,在控制操作上更灵活;

Fragment可以在XML文件中直接进行写入,也可以在Activity中动态添加;

Fragment可以使用show()/hide()或者replace()随时对Fragment进行切换,
并且切换的时候不会出现明显的效果,用户体验会好;
Activity虽然也可以进行切换,但是Activity之间切换会有明显的翻页或者其他的效果,
在小部分内容的切换上给用户的感觉不是很好;

9、Fragment中add与replace的区别(Fragment重叠)

add不会重新初始化fragment,replace每次都会。
所以如果在fragment生命周期内获取获取数据,使用replace会重复获取;

添加相同的fragment时,replace不会有任何变化,add会报IllegalStateException异常;
replace先remove掉相同id的所有fragment,然后在add当前的这个fragment,
add是覆盖前一个fragment。所以如果使用add一般会伴随hide()和show(),避免布局重叠;

使用add,如果应用放在后台,或以其他方式被系统销毁,再打开时,hide()中引用的fragment会销毁,
所以依然会出现布局重叠bug,可以使用replace或使用add时,添加一个tag参数;

10、Service的生命周期涉及到六大方法

onCreate():如果service没被创建过,调用startService()后会执行onCreate()回调;
如果service已处于运行中,调用startService()不会执行onCreate()方法。
也就是说,onCreate()只会在第一次创建service时候调用,
多次执行startService()不会重复调用onCreate(),此方法适合完成一些初始化工作;

onStartComand():服务启动时调用,此方法适合完成一些数据加载工作,
比如会在此处创建一个线程用于下载数据或播放音乐;

onBind():服务被绑定时调用;
onUnBind():服务被解绑时调用;
onDestroy():服务停止时调用;

11、Service的两种启动模式

startService():通过这种方式调用startService,onCreate()只会被调用一次,
多次调用startSercie会多次执行onStartCommand()和onStart()方法。
如果外部没有调用stopService()或stopSelf()方法,service会一直运行。

bindService():如果该服务之前还没创建,系统回调顺序为onCreate()→onBind()。
如果调用bindService()方法前服务已经被绑定,多次调用bindService()方法不会多次创建服务及绑定。
如果调用者希望与正在绑定的服务解除绑定,可以调用unbindService()方法,回调顺序为onUnbind()→onDestroy();

12、如何保证Service不被杀死 ?

onStartCommand方式中,返回START_STICKY或则START_REDELIVER_INTENT

START_STICKY:如果返回START_STICKY,表示Service运行的进程被Android系统强制杀掉之后,
Android系统会将该Service依然设置为started状态(即运行状态),
但是不再保存onStartCommand方法传入的intent对象

START_NOT_STICKY:如果返回START_NOT_STICKY,表示当Service运行的进程被Android系统强制杀掉之后,
不会重新创建该Service

START_REDELIVER_INTENT:如果返回START_REDELIVER_INTENT,其返回情况与START_STICKY类似,
但不同的是系统会保留最后一次传入onStartCommand方法中的Intent再次保留下来并再次传入到重新创建后的Service的onStartCommand方法中

提高Service的优先级:
在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,
1000是最高值,如果数字越小则优先级越低,同时适用于广播;

在onDestroy方法里重启Service:
当service走到onDestroy()时,发送一个自定义广播,当收到广播时,重新启动service;

提升Service进程的优先级
进程优先级由高到低:前台进程 一 可视进程 一 服务进程 一 后台进程 一 空进程

可以使用startForeground将service放到前台状态,这样低内存时,被杀死的概率会低一些;

系统广播监听Service状态

将APK安装到/system/app,变身为系统级应用

注意:以上机制都不能百分百保证Service不被杀死,除非做到系统白名单,与系统同生共死

13、Service默认并不会运行在子线程中,也不运行在一个独立的进程中,它同样执行在主线程中(UI线程)。

换句话说,不要在Service里执行耗时操作,除非手动打开一个子线程,否则有可能出现主线程被阻塞(ANR)的情况;

14、广播有几种形式 ? 都有什么特点 ?

普通广播:开发者自身定义 intent的广播(最常用),所有的广播接收器几乎会在同一时刻接受到此广播信息,
接受的先后顺序随机;

有序广播:发送出去的广播被广播接收者按照先后顺序接收,同一时刻只会有一个广播接收器能够收到这条广播消息,
当这个广播接收器中的逻辑执行完毕后,广播才会继续传递,
且优先级(priority)高的广播接收器会先收到广播消息。
有序广播可以被接收器截断使得后面的接收器无法收到它;

本地广播:仅在自己的应用内发送接收广播,也就是只有自己的应用能收到,数据更加安全,效率更高,
但只能采用动态注册的方式;

粘性广播:这种广播会一直滞留,当有匹配该广播的接收器被注册后,该接收器就会收到此条广播;

15、广播发送和接收的原理了解吗 ?(Binder机制、AMS)

在这里插入图片描述

17、Android平台实现数据持久存储的常见几种方式:

SharedPreferences存储:一种轻型的数据存储方式,本质是基于XML文件存储的key-value键值对数据,
通常用来存储一些简单的配置信息(如应用程序的各种配置信息);

SQLite数据库存储:一种轻量级嵌入式数据库引擎,它的运算速度非常快,占用资源很少,
常用来存储大量复杂的关系数据;

ContentProvider:四大组件之一,用于数据的存储和共享,不仅可以让不同应用程序之间进行数据共享,
还可以选择只对哪一部分数据进行共享,可保证程序中的隐私数据不会有泄漏风险;

File文件存储:写入和读取文件的方法和 Java中实现I/O的程序一样;

网络存储:主要在远程的服务器中存储相关数据,用户操作的相关数据可以同步到服务器上;

18、SharedPrefrences的apply和commit有什么区别?

apply没有返回值而commit返回boolean表明修改是否提交成功。

apply是将修改数据原子提交到内存, 而后异步真正提交到硬件磁盘,
而commit是同步的提交到硬件磁盘,因此,在多个并发的提交commit的时候,
他们会等待正在处理的commit保存到磁盘后在操作,从而降低了效率。
而apply只是原子的提交到内容,后面有调用apply的函数的将会直接覆盖前面的内存数据,
这样从一定程度上提高了很多效率。

apply方法不会提示任何失败的提示。 由于在一个进程中,sharedPreference是单实例,
一般不会出现并发冲突,如果对提交的结果不关心的话,建议使用apply,
当然需要确保提交成功且有后续操作的话,还是需要用commit的。

19、Android中进程和线程的关系

线程是CPU调度的最小单元,同时线程是一种有限的系统资源
进程一般指一个执行单元,在PC和移动设备上一个程序或则一个应用

一般来说,一个App程序至少有一个进程,一个进程至少有一个线程(包含与被包含的关系),
通俗来讲就是,在App这个工厂里面有一个进程,线程就是里面的生产线,
但主线程(主生产线)只有一条,而子线程(副生产线)可以有多个

进程有自己独立的地址空间,而进程中的线程共享此地址空间,都可以并发执行

20、在AndroidMenifest中给四大组件指定属性android:process开启多进程模式,在内存允许的条件下可以开启N个进程

21、View的绘制流程?

View的工作流程主要是指measure、layout、draw这三大流程,即测量、布局和绘制,

measure确定View的测量宽/高,
layout确定View的最终宽/高和四个顶点的位置,
draw则将View绘制到屏幕上

View的绘制过程遵循如下几步:
绘制背景 background.draw(canvas)
绘制自己(onDraw)
绘制 children(dispatchDraw)
绘制装饰(onDrawScollBars)

22、MotionEvent是手指接触屏幕后所产生的一系列事件。

典型的事件类型有如下:
ACTION_DOWN:手指刚接触屏幕
ACTION_MOVE:手指在屏幕上移动
ACTION_UP:手指从屏幕上松开的一瞬间
ACTION_CANCELL:手指保持按下操作,并从当前控件转移到外层控件时触发

正常情况下,一次手指触摸屏幕的行为会触发一系列点击事件,考虑如下几种情况:
点击屏幕后松开,事件序列:DOWN→UP
点击屏幕滑动一会再松开,事件序列为DOWN→MOVE→……→MOVE→UP

23、View事件分发本质就是对MotionEvent事件分发的过程。即当一个MotionEvent发生后,系统将这个点击事件传递到一个具体的View上

点击事件的传递顺序:Activity(Window)→ViewGroup→ View

事件分发过程由三个方法共同完成:
dispatchTouchEvent:用来进行事件的分发。如果事件能够传递给当前View,那么此方法一定会被调用,
返回结果受当前View的onTouchEvent和下级View的dispatchTouchEvent方法的影响,表示是否消耗当前事件

onInterceptTouchEvent:在上述方法内部调用,对事件进行拦截。
该方法只在ViewGroup中有,View(不包含 ViewGroup)是没有的。
一旦拦截,则执行ViewGroup的onTouchEvent,在ViewGroup中处理事件,而不接着分发给View。
且只调用一次,返回结果表示是否拦截当前事件

onTouchEvent: 在dispatchTouchEvent方法中调用,用来处理点击事件,返回结果表示是否消耗当前事件

24、自定义View如何考虑机型适配 ?

合理使用warp_content,match_parent
尽可能的是使用RelativeLayout
针对不同的机型,使用不同的布局文件放在对应的目录下,android会自动匹配。
尽量使用点9图片。
使用与密度无关的像素单位dp,sp
引入android的百分比布局。
切图的时候切大分辨率的图,应用到布局当中。在小分辨率的手机上也会有很好的显示效果。

WeChat–Android中高级面试33题

25、Activity生命周期?

onCreate() -> onStart() -> onResume() -> onPause() -> onStop() -> onDetroy()

26、service 启动方式一种是通过startService()方式进行启动,另一种是通过bindService()方式进行启动。不同的启动方式他们的生命周期是不一样.

通过startService()这种方式启动的service
生命周期:调用startService() --> onCreate()–> onStartConmon()–> onDestroy()。

第一:当通过startService被调用以后,多次在调用startService(),onCreate()方法也只会被调用一次,
而onStartConmon()会被多次调用,当我们调用stopService()的时候,onDestroy()就会被调用,从而销毁服务。
第二:当我们通过startService启动时候,通过intent传值,在onStartConmon()方法中获取值的时候,
一定要先判断intent是否为null。

通过bindService()方式进行绑定,这种方式绑定service
生命周期:bindService–>onCreate()–>onBind()–>unBind()–>onDestroy()

bindservice 这种方式进行启动service好处是更加便利activity中操作service,
如果要在activity中调用,在需要在activity获取ServiceConnection对象,
通过ServiceConnection来获取service中内部类的类对象,
然后通过这个类对象就可以调用类中的方法,当然这个类需要继承Binder对象

27、app启动的过程有两种情况,第一种是从桌面launcher上点击相应的应用图标,第二种是在activity中通过调用startActivity来启动一个新的activity。

我们创建一个新的项目,默认的根activity都是MainActivity,而所有的activity都是保存在堆栈中的,
我们启动一个新的activity就会放在上一个activity上面,而我们从桌面点击应用图标的时候,
由于launcher本身也是一个应用,当我们点击图标的时候,系统就会调用startActivitySately(),

一般情况下,我们所启动的activity的相关信息都会保存在intent中,比如action,category等等。
我们在安装这个应用的时候,系统也会启动一个PackaManagerService的管理服务,

这个管理服务会对AndroidManifest.xml文件进行解析,从而得到应用程序中的相关信息,
比如service,activity,Broadcast等等,然后获得相关组件的信息。

当我们点击应用图标的时候,就会调用startActivitySately()方法,而这个方法内部则是调用startActivty(),
而startActivity()方法最终还是会调用startActivityForResult()这个方法。

而在startActivityForResult()这个方法。因为startActivityForResult()方法是有返回结果的,
所以系统就直接给一个-1,就表示不需要结果返回了。

而startActivityForResult()这个方法实际是通过Instrumentation类中的execStartActivity()方法来启动activity,
Instrumentation这个类主要作用就是监控程序和系统之间的交互。

而在这个execStartActivity()方法中会获取ActivityManagerService的代理对象,
通过这个代理对象进行启动activity,启动会就会调用一个checkStartActivityResult()方法,
如果说没有在配置清单中配置有这个组件,就会在这个方法中抛出异常了。

当然最后是调用的是Application.scheduleLaunchActivity()进行启动activity,
而这个方法中通过获取得到一个ActivityClientRecord对象,

而这个ActivityClientRecord通过handler来进行消息的发送,
系统内部会将每一个activity组件使用ActivityClientRecord对象来进行描述,

而ActivityClientRecord对象中保存有一个LoaderApk对象,
通过这个对象调用handleLaunchActivity来启动activity组件,
而页面的生命周期方法也就是在这个方法中进行调用。

28、什么情况下用动态注册,广播是分为有序广播和无序广播。

第一种是静态注册,也可成为常驻型广播,这种广播需要在Androidmanifest.xml中进行注册,
这中方式注册的广播,不受页面生命周期的影响,
即使退出了页面,也可以收到广播这种广播一般用于想开机自启动啊等等,
由于这种注册的方式的广播是常驻型广播,所以会占用CPU的资源。

第二种是动态注册,而动态注册的话,是在代码中注册的,
这种注册方式也叫非常驻型广播,受到生命周期的影响,
退出页面后,就不会收到广播,我们通常运用在更新UI方面。
这种注册方式优先级较高。最后需要解绑,否会会内存泄露

29、Activity像一个工匠(控制单元),Window像窗户(承载模型),View像窗花(显示视图)LayoutInflater像剪刀,Xml配置像窗花图纸。

1:Activity构造的时候会初始化一个Window,准确的说是PhoneWindow。
2:这个PhoneWindow有一个ViewRoot,这个ViewRoot是一个View或者说ViewGroup,是最初始的根视图。
3:ViewRoot通过addView方法来一个个的添加View。比如TextView,Button等
4:这些View的事件监听,是由WindowManagerService来接受消息,并且回调Activity函数。
比如onClickListener,onKeyDown等。

30、栈与队列的区别:

队列先进先出,栈先进后出

对插入和删除操作的"限定":
栈是限定只能在表的一端进行插入和删除操作的线性表。
队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。

遍历数据速度不同

31、四种LaunchMode及其使用场景

standard 模式
这是默认模式,每次激活Activity时都会创建Activity实例,并放入任务栈中。使用场景:大多数Activity。

singleTop 模式
如果在任务的栈顶正好存在该Activity的实例,就重用该实例( 会调用实例的onNewIntent()),否则就会创建新的实例并放入栈顶,即使栈中已经存在该Activity的实例,只要不在栈顶,都会创建新的实例。使用场景如新闻类或者阅读类App的内容页面。

singleTask 模式
如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的onNewIntent())。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移出栈。如果栈中不存在该实例,将会创建新的实例放入栈中。使用场景如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。

singleInstance 模式
在一个新栈中创建该Activity的实例,并让多个应用共享该栈中的该Activity实例。一旦该模式的Activity实例已经存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例( 会调用实例的 onNewIntent())。其效果相当于多个应用共享一个应用,不管谁激活该Activity 都会进入同一个应用中。使用场景如闹铃提醒,将闹铃提醒与闹铃设置分离。singleInstance不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -> B (singleInstance) -> C,完全退出后,在此启动,首先打开的是B。

32、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子视图,如果没有就不用;
⑤、还原图层(Layer);
⑥、绘制滚动条。

自定义控件:
1、组合控件。这种自定义控件不需要我们自己绘制,而是使用原生控件组合成的新控件。如标题栏。
2、继承原有的控件。这种自定义控件在原生控件提供的方法外,可以自己添加一些方法。如制作圆角,圆形图片。
3、完全自定义控件:这个View上所展现的内容全部都是我们自己绘制出来的。比如说制作水波纹进度条。

33、Android跨进程通信,像intent,contentProvider,广播,service都可以跨进程通信。

intent:
这种跨进程方式并不是访问内存的形式,它需要传递一个uri,比如说打电话。

contentProvider:
这种形式,是使用数据共享的形式进行数据共享。

service:
远程服务,比如aidl

34、Handler的原理

Android中主线程是不能进行耗时操作的,子线程是不能进行更新UI的。
所以就有了handler,它的作用就是实现线程之间的通信。

handler整个流程中,主要有四个对象,
handler,Message,MessageQueue,Looper。
当应用创建的时候,就会在主线程中创建handler对象,

我们通过要传送的消息保存到Message中,
handler通过调用sendMessage方法将Message发送到MessageQueue中,
Looper对象就会不断的调用loop()方法

不断的从MessageQueue中取出Message交给handler进行处理。
从而实现线程之间的通信。

35、Binder机制原理

在Android系统的Binder机制中,是有Client,Service,ServiceManager,Binder驱动程序组成的,
其中Client,service,Service Manager运行在用户空间,

Binder驱动程序是运行在内核空间的。
而Binder就是把这4种组件粘合在一块的粘合剂,其中核心的组件就是Binder驱动程序,

Service Manager提供辅助管理的功能,
而Client和Service正是在Binder驱动程序和Service Manager提供的基础设施上实现C/S之间的通信。

其中Binder驱动程序提供设备文件/dev/binder与用户控件进行交互,
Client、Service,Service Manager通过open和ioctl文件操作相应的方法与Binder驱动程序进行通信。

而Client和Service之间的进程间通信是通过Binder驱动程序间接实现的。
而Binder Manager是一个守护进程,用来管理Service,并向Client提供查询Service接口的能力。

36、内存泄露检测工具 ------>LeakCanary

内存溢出out of memory:
是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;
比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。
内存溢出通俗的讲就是内存不够用。

内存泄露memory leak:
是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,
但内存泄露堆积后果很严重,无论多少内存,迟早会被占光

37、Fragment与Fragment、Activity通信的方式

1.直接在一个Fragment中调用另外一个Fragment中的方法
2.使用接口回调
3.使用广播
4.Fragment直接调用Activity中的public方法

38、Android UI适配

字体使用sp,
dp,多使用match_parent,wrap_content,weight
图片资源,不同图片的的分辨率,放在相应的文件夹下可使用百分比代替。

39、app优化

app优化:
工具:Hierarchy Viewer 分析布局
工具:TraceView测试分析耗时

App启动优化
布局优化、响应优化、内存优化、电池使用优化、网络优化

App启动的方式有三种:
冷启动:App没有启动过或App进程被killed, 系统中不存在该App进程, 此时启动App即为冷启动。
热启动:热启动意味着你的App进程只是处于后台, 系统只是将其从后台带到前台, 展示给用户。
介于冷启动和热启动之间,一般来说在以下两种情况下发生:
(1)用户back退出了App, 然后又启动.
App进程可能还在运行, 但是activity需要重建。
(2)用户退出App后, 系统可能由于内存原因将App杀死, 进程和activity都需要重启, 但是可以在onCreate中将被动杀死锁保存的状态(saved instance state)恢复。

启动优化:
Application的onCreate(特别是第三方SDK初始化),首屏Activity的渲染都不要进行耗时操作,
如果有,就可以放到子线程或者IntentService中。

布局优化
尽量不要过于复杂的嵌套。可以使用,,

响应优化
Android系统每隔16ms会发出VSYNC信号重绘我们的界面(Activity)。

页面卡顿的原因:
(1)过于复杂的布局.
(2)UI线程的复杂运算
(3)频繁的GC
导致频繁GC有两个原因:
1、内存抖动, 即大量的对象被创建又在短时间内马上被释放.
2、瞬间产生大量的对象会严重占用内存区域。

电池使用优化(
工具:Batterystats & bugreport
(1)优化网络请求
(2)定位中使用GPS, 请记得及时关闭

网络优化
网络连接对用户的影响:流量,电量,用户等待,可在Android studio下方logcat旁边那个工具Network Monitor检测

API设计:
App与Server之间的API设计要考虑网络请求的频次, 资源的状态等. 以便App可以以较少的请求来完成业务需求和界面的展示.

Gzip压缩:
使用Gzip来压缩request和response, 减少传输数据量, 从而减少流量消耗.

图片的Size:
可以在获取图片时告知服务器需要的图片的宽高, 以便服务器给出合适的图片, 避免浪费.

网络缓存:
适当的缓存, 既可以让我们的应用看起来更快, 也能避免一些不必要的流量消耗.

40、OKhttp:

Android开发中是可以直接使用现成的api进行网络请求的。
就是使用HttpClient,HttpUrlConnection进行操作。
okhttp针对Java和Android程序,封装的一个高性能的http请求库,支持同步,异步,
而且okhttp又封装了线程池,封装了数据转换,封装了参数的使用,错误处理等。
API使用起来更加的方便。但是我们在项目中使用的时候仍然需要自己在做一层封装,这样才能使用的更加的顺手。

41、Retrofit:

Retrofit是Square公司出品的默认基于OkHttp封装的一套RESTful网络请求框架,
RESTful是目前流行的一套api设计的风格, 并不是标准。
Retrofit的封装可以说是很强大,里面涉及到一堆的设计模式,可以通过注解直接配置请求,可以使用不同的http客户端,
虽然默认是用http ,可以使用不同Json Converter 来序列化数据,同时提供对RxJava的支持,
使用Retrofit + OkHttp + RxJava + Dagger2可以说是目前比较潮的一套框架,但是需要有比较高的门槛。

42、RecyclerView可以完成ListView,GridView的效果,还可以完成瀑布流的效果。同时还可以设置列表的滚动方向(垂直或者水平);

RecyclerView中view的复用不需要开发者自己写代码,系统已经帮封装完成了。
RecyclerView可以进行局部刷新。
RecyclerView提供了API来实现item的动画效果。
在性能上:
如果需要频繁的刷新数据,需要添加动画,则RecyclerView有较大的优势。
如果只是作为列表展示,则两者区别并不是很大。

43、Picasso 优点

1.自带统计监控功能。支持图片缓存使用的监控,包括缓存命中率、已使用内存大小、节省的流量等。
2.支持优先级处理。每次任务调度前会选择优先级高的任务,比如 App页面中Banner的优先级高于Icon时就很适用。
3.支持延迟到图片尺寸计算完成加载
4.支持飞行模式、并发线程数根据网络类型而变。手机切换到飞行模式或网络类型变换时会自动调整线程池最大并发数,比如 wifi最大并发为4,4g 为 3,3g 为 2。这里Picasso根据网络类型来决定最大并发数,而不是CPU核数。
5.“无”本地缓存。无”本地缓存,不是说没有本地缓存,而是 Picasso自己没有实现,交给了Square的另外一个网络库 okhttp 去实现,这样的好处是可以通过请求 Response Header中的 Cache-Control 及 Expired 控制图片的过期时间。

44、Glide 优点

不仅仅可以进行图片缓存还可以缓存媒体文件。Glide 不仅是一个图片缓存,它支持 Gif、WebP、缩略图。甚至是 Video,所以更该当做一个媒体缓存。
支持优先级处理。
与 Activity/Fragment 生命周期一致,支持trimMemory。Glide 对每个 context都保持一个RequestManager,通过 FragmentTransaction 保持与Activity/Fragment生命周期一致,并且有对应的 trimMemory接口实现可供调用。
支持okhttp、Volley。Glide 默认通过 UrlConnection获取数据,可以配合okhttp或是 Volley 使用。实际 ImageLoader、Picasso 也都支持 okhttp、Volley。
内存友好。Glide的内存缓存有个active 的设计,从内存缓存中取数据时,不像一般的实现用 get,而是用 remove,再将这个缓存数据放到一个value为软引用的 activeResources map 中,并计数引用数,在图片加载完成后进行判断,如果引用计数为空则回收掉。内存缓存更小图片,Glide 以 url、view_width、view_height、屏幕的分辨率等做为联合 key,将处理后的图片缓存在内存缓存中,而不是原始图片以节省大小与 Activity/Fragment 生命周期一致,支持 trimMemory。图片默认使用默认 RGB_565 而不是 ARGB_888,虽然清晰度差些,但图片更小,也可配置到 ARGB_888。

45、MVP模式对应着Model:业务逻辑和实体模型,view:对应着activity,负责View的绘制以及与用户交互,Presenter:负责View和Model之间的交互

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值