2018年Android面试整理
Android 知识复习
Activity 的生命周期
onStart和onResume,onStop和OnPause ,对用户的实质不同
onStart 对应onStop 这个过程是用户是否可见
onResume对应onPause 这个过程是否在前台
activity启动模式
- standard,singleTop,singleTask,singInstance
standard:重新创建一个activity。
singTop:如果activity栈顶端是该activity,就复用该activity,否则就创建一个新的
singleTask:如果栈中有该activity,弹出该activity上面的activity,复用这个activity,否则创建一个新的。
SingleIntance:单例模式activity
- 试用场景
singleTop适合接收通知启动的内容显示页面。例如,某个新闻客户端的新闻内容页面,如果收到10个新闻推送,每次都打开一个新闻内容页面是很烦人的。
singleTask适合作为程序入口点。例如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。之前打开过的页面,打开之前的页面就ok,不再新建。
singleInstance适合需要与程序分离开的页面。例如闹铃提醒,将闹铃提醒与闹铃设置分离。singleInstance不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -> B (singleInstance) -> C,完全退出后,在此启动,首先打开的是B
Android进程间通信(Inter_Process Communication)
线程:cup调度的最小单位,是一种有限的系统资源。
进程:一般指一个执行单元,pc和移动设备上的一个程序或者一个应用。
为什么有多进程通信:Android为每一个进程都分配一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,这导致在不同的虚拟机中访问同一个类的对象会产生多个副本。
Binder:是Android中的一个类,实现了IBinder接口,是Android跨进程通信的一种方式,可以理解为一种虚拟的物理设备,其设备驱动是dev/binder。从Android Framework角度来说,binder是serviceManager连接各种Manager和相应的ManagerService的桥梁。从应用层来说,binder是客户端和服务器端进行通信的媒介,在bindService时,服务端会返回一个包含服务端业务调用的Binder对象,通过这个对象,客户端就可以获取服务端的数据。
AIDL的实现:首先新建一个AIDL文件,第二步实现AIDL文件生成的java接口Stub,第三步定义自己的service为了让其他应用可以通过bindService 交互,实现onBind()方法,返回对应的Stub作为binder, 第四步,同一个应用中的Activity为该Service中赋值,使用service
客户端:
第1步:客户端要想使用该服务,肯定要先知道我们的服务在aidl文件中到底对外提供了什么服务,对吧?所以,第一步,我们要做的就是,将aidl文件拷贝一份到客户端的程序中(这里一定要注意,包路径要和服务端的保持一致哦,例如服务端为cn.com.chenzheng_java.remote.a.aidl,那么在客户端这边也应该是这个路径)。
第2步:我们都知道,想要和service交互,我们要通过bindService方法,该方法中有一个ServiceConnection类型的参数。而我们的主要代码便是在该接口的实现中。
第3步:在ServiceConnection实现类的onServiceConnected(ComponentName name, IBinder service)方法中通过类似remoteServiceInterface = RemoteServiceInterface.Stub.asInterface(service);方式就可以获得远程服务端提供的服务的实例,然后我们就可以通过remoteServiceInterface 对象调用接口中提供的方法进行交互了。(这里的关键是通过*.Stub.asInterface(service);方法获取一个aidl接口的实例哦)
- 文件
优点:使用简单
缺点:不支持并发
- AIDL(基于binder)
优点:试用于各种场景
缺点:使用复杂
- ContentProvider(binder)
优点:试用于各种场景,数据访问方面强大
缺点:使用复杂
- Bundle
优点:使用简单
缺点:只能传输bundle能存储的数据类型, (binder,boolean,byte,char,double,charSequence,float,double,int,short,long,string,Parcelable,seralizalbe)
- Messager(基于binder)
- Socket
View体系
View:所有控件的父类
事件的分发在acitivity:
viewgorup的事件的传递:首先调用该viewgorup的dispatchTouchEvent(),如果该viewgorup的onInterceptTouchEvetn返回true,表示拦截该事件。那么事件就会交给该viewgorup的ontouchEvent方法处理,如果viewgorup的onInterceptTouchEvent返回false,该事件就不会被该viewgorup拦截,传给他的子元素,接着调用子元素的dispatchTouchEvent.当该view需处理事件时,如果它设置了onTouchListener,那么OnTouchListener中的onTouch会被回调,如果OnTouch返回false,则当前viewgorup的onTouchEvent方法被调用,如果返回true,那么onTouchEvent不会不被调用,可见onTouchListener优先级高于onTouchEvent。在onTouchEvent方法中如果设置了OnclickListenter那么onclick会被调用看,可见其优先级最低。
在view中事件的传递
view的绘制过程
Activity启动时,ActivityThread.handleResumeActivity()方法中建立了它们两者的关联关系。View的绘制起点是从rootviewImpl中的requestLayout(),其中又会调用scheduleTraversals(),该方法会向主线程发送一个“遍历”消息,最终会导致ViewRootImpl的performTraversals()方法被调用,接着会调用performMeasure();其中会调用measure(),对于decorView来说,实际执行测量工作的是FrameLayout的onMeasure()方法, 但其提供了measureChildren(),这之中会遍历子View然后循环调用measureChild()这之中会用getChildMeasureSpec()+父View的MeasureSpec+子View的LayoutParam一起获取本View的MeasureSpec,然后调用子View的measure()到View的onMeasure()-->setMeasureDimension(getDefaultSize(),getDefaultSize()),getDefaultSize()默认返回measureSpec的测量数值,所以继承View进行自定义的wrap_content需要重写。
performLayout()会调用最外层的ViewGroup的layout(l,t,r,b),本View在其中使用setFrame()设置本View的四个顶点位置。在onLayout(抽象方法)中确定子View的位置,如LinearLayout会遍历子View,循环调用setChildFrame()-->子View.layout()。
performDraw()会调用最外层ViewGroup的draw():其中会先后调用background.draw()(绘制背景)、onDraw()(绘制自己)、dispatchDraw()(绘制子View)、onDrawScrollBars()(绘制装饰)。
MeasureSpec由2位SpecMode(UNSPECIFIED、EXACTLY(对应精确值和match_parent)、AT_MOST(对应warp_content))和30位SpecSize组成一个int,DecorView的MeasureSpec由窗口大小和其LayoutParams决定,其他View由父View的MeasureSpec和本View的LayoutParams决定。ViewGroup中有getChildMeasureSpec()来获取子View的MeasureSpec。
三种方式获取measure()后的宽高:
-
- 1.Activity#onWindowFocusChange()中调用获取
- 2.view.post(Runnable)将获取的代码投递到消息队列的尾部。
- 3.ViewTreeObservable.
Service
启动方式
starService():
生命周期:onCreate()->onStartCommand()->onDestory()
特点:一旦服务开启跟调用者(开启者)就没有任何关系了。
开启者退出了,开启者挂了,服务还在后台长期的运行。
开启者不能调用服务里面的方法。
bindService():
生命周期:onCreate()->onbind()->onUnbind()->onDestory()
特点:bind的方式开启服务,绑定服务,调用者挂了,服务也会跟着挂掉。
绑定者可以调用服务里面的方法。
Broadcast
静态注册
直接在AndroidManifest.xml文件的<application>节点中配置广播接收者。
动态注册
- 第一种不是常驻型广播,也就是说广播跟随程序的生命周期。
- 第二种是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行
项目框架
Volley原理 https://blog.****.net/nugongahou110/article/details/46829605
butterknife 原理 https://blog.****.net/ta893115871/article/details/52497297
数据存储
Sharedpreferences
- 根据Context获取SharedPreferences对象( SharedPreferences sp = Context.getSharedPreferences("SP", MODE_PRIVATE);)
-
利用
edit()
方法获取Editor
对象(Editor editor = sp.edit();) -
通过
Editor
对象存储key-value键值对数据。(editor.putString(“key”,value); -
通过
commit()
方法提交数据。(editor.commit();)
消息机制
- 1.MessageQueue:读取会自动删除消息,单链表维护,在插入和删除上有优势。在其next()中会无限循环,不断判断是否有消息,有就返回这条消息并移除。
- 2.Looper:Looper创建的时候会创建一个MessageQueue,调用loop()方法的时候消息循环开始,loop()也是一个死循环,会不断调用messageQueue的next(),当有消息就处理,否则阻塞在messageQueue的next()中。当Looper的quit()被调用的时候会调用messageQueue的quit(),此时next()会返回null,然后loop()方法也跟着退出。
- 3.Handler:在主线程构造一个Handler,然后在其他线程调用sendMessage(),此时主线程的MessageQueue中会插入一条message,然后被Looper使用。
- 4.系统的主线程在ActivityThread的main()为入口开启主线程,其中定义了内部类Activity.H定义了一系列消息类型,包含四大组件的启动停止。
- 5.MessageQueue和Looper是一对一关系,Handler和Looper是多对一
其他收集 https://blog.****.net/huangqili1314/article/details/79824830