2018年Android面试整理

Android 知识复习

Activity 的生命周期

2018年Android面试整理_第1张图片

onStart和onResume,onStop和OnPause ,对用户的实质不同

onStart 对应onStop 这个过程是用户是否可见

onResume对应onPause 这个过程是否在前台

activity启动模式

  1. standard,singleTop,singleTask,singInstance

standard:重新创建一个activity。

singTop:如果activity栈顶端是该activity,就复用该activity,否则就创建一个新的

singleTask:如果栈中有该activity,弹出该activity上面的activity,复用这个activity,否则创建一个新的。

SingleIntance:单例模式activity

  1. 试用场景

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接口的实例哦)

 

  1. 文件

优点:使用简单

缺点:不支持并发

  1. AIDL(基于binder)

优点:试用于各种场景

缺点:使用复杂

  1. ContentProvider(binder)

优点:试用于各种场景,数据访问方面强大

缺点:使用复杂

  1. Bundle

优点:使用简单

缺点:只能传输bundle能存储的数据类型, (binder,boolean,byte,char,double,charSequence,float,double,int,short,long,string,Parcelable,seralizalbe)

  1. Messager(基于binder)
  2. Socket

 

View体系

View:所有控件的父类

事件的分发在acitivity:

2018年Android面试整理_第2张图片

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会被调用看,可见其优先级最低。     

        2018年Android面试整理_第3张图片

在view中事件的传递

2018年Android面试整理_第4张图片

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文件的节点中配置广播接收者。

动态注册

  1. 第一种不是常驻型广播,也就是说广播跟随程序的生命周期。
  2. 第二种是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行

项目框架

Volley原理 https://blog.csdn.net/nugongahou110/article/details/46829605

butterknife 原理 https://blog.csdn.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.LooperLooper创建的时候会创建一个MessageQueue,调用loop()方法的时候消息循环开始,loop()也是一个死循环,会不断调用messageQueuenext(),当有消息就处理,否则阻塞在messageQueuenext()中。当Looperquit()被调用的时候会调用messageQueuequit(),此时next()会返回null,然后loop()方法也跟着退出。
  • 3.Handler:在主线程构造一个Handler,然后在其他线程调用sendMessage(),此时主线程的MessageQueue中会插入一条message,然后被Looper使用。
  • 4.系统的主线程在ActivityThreadmain()为入口开启主线程,其中定义了内部类Activity.H定义了一系列消息类型,包含四大组件的启动停止。
  • 5.MessageQueueLooper是一对一关系,HandlerLooper是多对一

其他收集 https://blog.csdn.net/huangqili1314/article/details/79824830

你可能感兴趣的:(android知识回顾)