Android面试知识点:Android

一、Android基础

1、四大组件的生命周期及简单使用方法

  • activity生命周期
    OnCreate(),OnStart(),OnResume(),OnPause(),OnStop(),OnDestory()
  • service生命周期
    service生命周期方法如下:
    在这里插入图片描述
    service生命周期调用如下:
    在这里插入图片描述
  • broadcast生命周期
  1. 动态注册方式的BroadcastReceiver:生命周期仅限于当前注册的activity,离开activity一定要解除注册,否则就会抛出非常熟悉的错误,但是这个错误不会导致app崩溃。
  2. 静态注册的BroadcastReceiver:生命周期不仅局限于activity,对比动态注册,进行了测试,发现activity关闭与否,不受影响,即使app退出了还是会收到广播。
  • ContentProvider生命周期

2、Activity的四种启动模式对比

  • standard
    standard模式是默认的启动模式,不用为配置android:launchMode属性即可,当然也可以指定值为standard。每次跳转系统都会在task中生成一个新的FirstActivity实例,并且放于栈结构的顶部,当我们按下后退键时,才能看到原来的FirstActivity实例

  • singleTop
    singleTop启动模式体现为2种,就是Activity处于栈顶和不处于栈顶。如果发现有对应的Activity实例正位于栈顶,则重复利用,不再生成新的实例。如果不是位于栈顶,就重新生成一个实例。

  • singleTask
    singleTask模式,如果发现所在Activity栈中有对应的Activity实例,则使此Activity实例之上的其他Activity实例统统出栈,使此Activity实例成为栈顶对象,显示到幕前。

  • singleInstance
    singleInstance所标识的Activity,当被启动时,系统会首先判断系统其他栈中是否已经存在此Activity实例,有则直接使用,并且其所在的Activity栈理论上只有它一个Activity元素。所以启动它的Activity与它并不在一个task中,所以才需要特别注意Back的问题。一般表示为:task1 A -> task2 B。

singleInstance表示该Activity在系统范围内“实例唯一”。由此我们发现,singInstance和singleTask主要区别在与系统范围内的“实例唯一”还是当前Activity栈“实例唯一”。

android:activity启动模式见解

3、fragment的使用

  • fragment的生命周期
    OnAttach();OnCreate();OnCreateView();OnActivityCreated();OnStart();OnResume();OnPause();OnStop();OnDestoryView();OnDestory();OnDetach();

可以看到Fragment比Activity多了几个额外的生命周期回调方法:

onAttach(Activity)当Fragment与Activity发生关联时调用。
onCreateView(LayoutInflater, ViewGroup,Bundle)创建该Fragment的视图
onActivityCreated(Bundle)当Activity的onCreate方法返回时调用
onDestoryView()与onCreateView想对应,当该Fragment的视图被移除时调用
onDetach()与onAttach相对应,当Fragment与Activity关联被取消时调用

注意:除了onCreateView,其他的所有方法如果你重写了,必须调用父类对于该方法的实现

  • fragment使用
  1. 静态使用:这是使用Fragment最简单的一种方式,把Fragment当成普通的控件,直接写在Activity的布局文件中。
  2. 动态使用:使用FragmentManager对Fragment进行了动态的加载。

基本是操作Fragment的所有的方式了,在一个事务开启到提交可以进行多个的添加、移除、替换等操作。
a、比如:我在FragmentA中的EditText填了一些数据,当切换到FragmentB时,如果希望会到A还能看到数据,则适合你的就是hide和show;也就是说,希望保留用户操作的面板,你可以使用hide和show,当然了不要使劲在那new实例,进行下非null判断。
b、再比如:我不希望保留用户操作,你可以使用remove(),然后add();或者使用replace(),这个和remove,add是相同的效果。
c、remove和detach有一点细微的区别,在不考虑回退栈的情况下,remove会销毁整个Fragment实例,而detach则只是销毁其视图结构,实例并不会被销毁。那么二者怎么取舍使用呢?如果你的当前Activity一直存在,那么在不希望保留用户操作的时候,你可以优先使用detach。

6、ContentProvider、ContentResolver、ContentObserver 之间的关系

ContentProvider是Android的四大组件之一,可见它在Android中的作用非同小可。它主要的作用是:实现各个应用程序之间的(跨应用)数据共享,比如联系人应用中就使用了ContentProvider,你在自己的应用中可以读取和修改联系人的数据,不过需要获得相应的权限。其实它也只是一个中间人,真正的数据源是文件或者SQLite等。
一个应用实现ContentProvider来提供内容给别的应用来操作, 通过ContentResolver来操作别的应用数据,当然在自己的应用中也可以。
ContentObserver(内容观察者),目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理,它类似于数据库技术中的触发器(Trigger),当ContentObserver所观察的Uri发生变化时,便会触发它。

7、广播的分类及广播使用的方式和场景

  • 使用场景
    广播作为Android组件间的通信方式,可以使用的场景如下:
  1. 同一app内部的同一组件内的消息通信(单个或多个线程之间);
  2. 同一app内部的不同组件之间的消息通信(单个进程);
  3. 同一app具有多个进程的不同组件之间的消息通信;
  4. 不同app之间的组件之间消息通信;
  5. Android系统在特定情况下与App之间的消息通信。

第一种情形:同一app内部的同一组件内的消息通信(单个或多个线程之间),实际应用中肯定是不会用到广播机制的(虽然可以用),无论是使用扩展变量作用域、基于接口的回调还是Handler-post/Handler-Message等方式,都可以直接处理此类问题,若适用广播机制,显然有些“杀鸡牛刀”的感觉,会显太“重”;
第二种情形:同一app内部的不同组件之间的消息通信(单个进程),对于此类需求,在有些教复杂的情况下单纯的依靠基于接口的回调等方式不好处理,此时可以直接使用EventBus等,相对而言,EventBus由于是针对统一进程,用于处理此类需求非常适合,且轻松解耦。可以参见文件《Android各组件/控件间通信利器之EventBus》。
第三、四、五情形:由于涉及不同进程间的消息通信,此时根据实际业务使用广播机制会显得非常适宜。下面主要针对Android广播中的具体知识点进行总结。

  • BroadcastReceiver注册类型
  1. 静态注册:直接在AndroidManifest.xml文件中进行注册。
  2. 动态注册:无须在AndroidManifest中注册组件。直接在代码中通过调用Context的registerReceiver函数,可以在程序中动态注册BroadcastReceiver。
  • 广播类型
  1. Normal Broadcast:普通广播
  2. System Broadcast:系统广播
  3. Ordered broadcast:有序广播
  4. Sticky Broadcast:粘性广播(在 android 5.0/api 21中deprecated,不再推荐使用,相应的还有粘性有序广播,同样已经deprecated)
  5. Local Broadcast:App应用内广播

最常见的增加安全性的方案是:
1.对于同一App内部发送和接收广播,将exported属性人为设置成false,使得非本App内部发出的此广播不被接收;
2.在广播发送和接收时,都增加上相应的permission,用于权限验证;
3.发送广播时,指定特定广播接收器所在的包名,具体是通过intent.setPackage(packageName)指定在,这样此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中。

android:broadcast见解

8、进程间的通讯方式(IPC)

IPC 即 Inter-Process Communication (进程间通信),是指进程间数据交互的过程。
Android底层是基于Linux,而Linux基于安全考虑,是不允许两个进程间直接操作对方的数据,这就是进程隔离

在Linux系统中,虚拟内存机制为每个进程分配了线性连续的内存空间,操作系统将这种虚拟内存空间映射到物理内存空间,每个进程有自己的虚拟内存空间,进而不能操作其他进程的内存空间,每个进程只能操作自己的虚拟内存空间,只有操作系统才有权限操作物理内存空间.进程隔离保证了每个进程的内存安全,但是在大多数情形下,不同进程间的数据通讯是不可避免的,因此操作系统必须提供跨进程通信机制。

虽然Android是基于Linux,但并不能继承Linux中的进程通信的方式,Android有着自己进程间通信方式。常用有如下几种:

名称优点缺点适用场景
Bundle简单易用只能传输Bundle支持的数据类型四大组件间的进程间通信
文件共享简单易用不适用高并发场景,并且无法做到进程间即时通信适用于无关发的情况下,交换简单的数据,对实时性要求不高的场景。
AIDL(基于Binder)功能强大,支持一对多实时并发通信使用稍复杂,需要处理好线程间的关系一对多通信且有RPC需求
Messenger(基于Binder)功能一般,支持一对多串行通信,支持实时通信不能很好地处理高并发的情形,不支持RPC,由于数据通过Message传输,因此只能传输Bundle支持的数据类型低并发的一对多实时通信,无RPC需求,或者无需要返回结果的RPC需求
ContentProvider(基于Binder)支持一对多的实时并发通信,在数据源共享方面功能强大,可通过Call方法扩展其它操作可以理解为受约束的AIDL,主要提供对数据源的CRUD操作一对多的进程间数据共享
BroadcastReceiver操作简单,对持一对多实时通信只支持数据单向传递,效率低且安全性不高一对多的低频率单向通信
Socket(TCP、UDP)功能强大,可通过网络传输字节流,支持一对多实时并发通信实现细节步骤稍繁琐,不支持直接的RPC网络间的数据交换

9、AlertDialog,PopupWindow,Activity区别

AlertDialog builder:用来提示用户一些信息,用起来也比较简单,设置标题类容和按钮即可,如果是加载的自定义的view ,调用 dialog.setView(layout);加载布局即可
popupWindow:就是一个悬浮在Activity之上的窗口,可以用展示任意布局文件。
activity:Activity是Android系统中的四大组件之一,可以用于显示View。Activity是一个与用记交互的系统模块,几乎所有的Activity都是和用户进行交互的

区别:AlertDialog是非阻塞式对话框:AlertDialog弹出时,后台还可以做事情;而PopupWindow是阻塞式对话框:PopupWindow弹出时,程序会等待,在PopupWindow退出前,程序一直等待,只有当我们调用了dismiss方法的后,PopupWindow退出,程序才会向下执行。

10、Application 和 Activity 的 Context 对象的区别

Android系统的角度来理解:Context是一个场景,代表与操作系统的交互的一种过程。从程序的角度上来理解:Context是个抽象类,而Activity、Service、Application等都是该类的一个实现。XXXActivity和getApplicationContext返回的肯定不是一个对象,一个是当前Activity的实例,一个是项目的Application的实例。如果乱用会因为内存无法回收导致的造成内存溢出

11、Android两种序列化的区别

Serializable: Java 序列化接口 在硬盘上读写 读写过程中有大量临时变量的生成,内部执行大量的i/o操作,效率很低。
Parcelable: Android 序列化接口 效率高 使用麻烦 在内存中读写(AS有相关插件 一键生成所需方法) ,对象不能保存到磁盘中

12、Android中数据存储方式

文件存储
SharedPreferences
SQLite数据库存储
ContentProvider
网络存储

  • 三级缓存

三级缓存在二级缓存的基础上加了一个内存。从服务器获取的数据库除了存在本地数据库中,同时在内存中也保存一份,这样当activity请求数据时可以先从内存中获取数据,如果内存中没有数据,或者内存中数据已经脏了的情况下,取本地数据库中的数据。当本地数据库的数据也脏了的情况下取服务器数据。取回的数据存一份本地数据库,存一份内存中。三级缓存原理如下图:
在这里插入图片描述

13、Activity-Window-View三者的差别

Activity是安卓四大组件之一,负责界面展示、用户交互与业务逻辑处理;

Window就是负责界面展示以及交互的职能部门,就相当于Activity的下属,Activity的生命周期方法负责业务的处理;

View就是放在Window容器的元素,Window是View的载体,View是Window的具体展示。

一句话介绍三者的关系:
Activity通过Window来实现视图元素的展示,window可以理解为一个容器,盛放着一个个的view,用来执行具体的展示工作。

14、Requestlayout,onlayout,onDraw,DrawChild区别与联系

调用requestLayout()方法的时机是:当前View发生了一些改变,这个改变使得现有的View失效,所以调用requestLayout()方法对View树进行重新布局,过程包括了measure()和layout()过程,但不会调用draw()过程,即不会发生重新绘制视图过程。
调用onLayout()的时机是:View需要给自己设置大小和位置了或者ViewGroup需要给子View和ViewGroup自身时调用。
onDraw()方法,View的绘制流程一共包括三步:①测量measure;②布局layout;③绘制draw;onDraw()方法就是在第三布绘制时发生,开发者已经测量好View的大小,设置好View的布局,剩下最后一步就是,具体画出这个布局。画的方法就是onDraw(),每个View都需要利用这个方法画出自己,ViewGroup除非设置了背景,否则不用调用该方法。

小结:①绘制VIew本身的内容,通过调用View.onDraw(canvas)函数实现;
②ViewGroup绘制自己的孩子通过dispatchDraw(canvas)实现,这个方法中调用drawChild()。

15、invalidate和postInvalidate的区别及使用

invalidate()得在UI线程中被调动,在工作者线程中可以通过Handler来通知UI线程进行界面更新。而postInvalidate()在工作者线程中被调用
使用invalidate()刷新界面,实例化一个Handler对象,并重写handleMessage方法调用invalidate()实现界面刷新;而在线程中通过sendMessage发送界面更新消息。
使用postInvalidate()刷新界面,使用postInvalidate则比较简单,不需要handler,直接在线程中调用postInvalidate即可。

16、ANR异常

Android中,网络访问、文件处理等耗时操作必须放到子线程中去执行,否则将会造成ANR异常。
ANR异常:Application Not Response 应用程序无响应
产生ANR异常的原因:在主线程执行了耗时操作,对Activity来说,主线程阻塞5秒将造成ANR异常,对BroadcastReceiver来说,主线程阻塞10秒将会造成ANR异常。
解决ANR异常的方法:耗时操作都在子线程中去执行
但是,Android不允许在子线程去修改UI,可我们又有在子线程去修改UI的需求,因此需要借助Handler,Handler是线程间通讯的机制

二、源码以及原理

1、描述一次网络请求的流程

补充

2、AsyncTask 使用

AsyncTask:对线程间的通讯做了包装,是后台线程和UI线程可以简易通讯:后台线程执行异步任务,将result告知UI线程。

  • AsyncTask定义了三种泛型类型参数 Params,Progress和Result。
Params启动任务执行的输入参数,比如HTTP请求的URL,任务执行器需要的数据类型 。
Progress后台任务执行的百分比,,即后台计算中使用的进度单位数据类型
Result后台执行任务最终返回的结果,比如String。

有些参数是可以设置为不使用的,只要传递为Void型即可,比如AsyncTask</VOID,>

onPreExecute()该方法在UI线程运行,当AsyncTask的execute()方法执行后,onPreExecute()会首先执行。可以在该方法中做一些准备工作,如初始化进度条的最大值。
doInBackground(Params…)将在onPreExecute()方法执行后马上执行,该方法运行在子线程中,负责执行耗时操作。在执行耗时操作的过程中可以通过不断地调用publishProgress()方法,导致onProgressUpdate()不断地被调用。
onProgressUpdate(Progress…)调用publishProgress()方法,就会导致该方法被执行,该方法运行在UI线程,例如在该方法中你可以更新进度条的显示。
onPostExecute(Result)doInBackground()方法执行后的返回结果会传给该方法,该方法运行在UI线程,在该方法中你可以显示处理结果。

使用过AsyncTask 的同学都知道一个异步加载数据最少要重写以下这两个方法:
doInBackground(Params…):后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。
onPostExecute(Result): 相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回

使用AsyncTask类,以下是几条必须遵守的准则:
1. Task的实例必须在UI thread中创建;
2. execute方法必须在UI thread中调用;
3. 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)这几个方法;
4. 该task只能被执行一次,否则多次调用时将会出现异常;

Android的AsyncTask比Handler更轻量级一些(只是代码上轻量一些,而实际上要比handler更耗资源),适用于简单的异步处理。

3、Handler机制和底层实现

  • 什么是Handler
    handler是线程通讯工具类,通俗一点讲就是用来在各个进程之间发送数据的处理对象。一个Handler允许发送和处理Message或者Runnable对象,并且会关联到主线程的MessageQueue中。每个Handler具有一个单独的线程,并且关联到一个消息队列的线程,就是说一个Handler有一个固有的消息队列。当实例化一个Handler的时候,它就承载在一个线程和消息队列的线程,这个Handler可以把Message或Runnable压入到消息队列,并且从消息队列中取出Message或Runnable,进而操作它们。

  • Message Queue消息队列
    用来存放通过Handler发布的消息,按照先进先出执行。 每个message queue都会有一个对应的Handler。Handler会向message queue通过两种方法发送消息:sendMessage或post。这两种消息都会插在message queue队尾并按先进先出执行。但通过这两种方法发送的消息执行的方式略有不同:通过sendMessage发送的是一个message对象,会被Handler的handleMessage()函数处理;而通过post方法发送的是一个runnable对象,则会自己执行。

对于Message对象,一般并不推荐直接使用它的构造方法得到,而是建议通过使用Message.obtain()这个静态的方法或者Handler.obtainMessage()获取。Message.obtain()会从消息池中获取一个Message对象,如果消息池中是空的,才会使用构造方法实例化一个新Message,这样有利于消息资源的利用。并不需要担心消息池中的消息过多,它是有上限的,上限为10个。

4、IntentService原理及作用

  • 应用场景
    Android中的Service是用于后台服务的,当应用程序被挂到后台的时候,为了保证应用某些组件仍然可以工作而引入了Service这个概念,那么这里面要强调的是Service不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程的,也就是说,在更多时候不建议在Service中编写耗时的逻辑和操作,否则会引起ANR。
    那么我们当我们编写的耗时逻辑,不得不被service来管理的时候,就需要引入IntentService,IntentService是继承Service的,那么它包含了Service的全部特性,当然也包含service的生命周期,那么与service不同的是,IntentService在执行onCreate操作的时候,内部开了一个线程,去执行你的耗时操作。

  • 使用
    IntentService是一种特殊的Service,它继承于Service并且还是个抽象类 所以我们必须创建它的子类才能使用IntentService, IntentService可以用来执行后台任务,当任务执行完后就会“自杀”
    ① 定义IntentService的子类:传入线程名称、复写onHandleIntent()方法
    ② 在Manifest.xml中注册服务
    ③ 在Activity中开启Service服务

  • 原理
    当我们的IntentService第一次启动的时候,onCreate()会执行一次, 在方法里创建了一个HandlerThread,HandlerThread继承Thread,它是一种可以使用Handler的Thread,它的run方法里通过Looper.prepare()来创建消息队列,并通过Looper.loop()来开启消息循环,所以就可以在其中创建Handler了,这里我们通过HandlerThread得到一个looper对象,并且使用它的looper对象来构造一个Handler对象,这样做的好处就是通过mServiceHandler发出的消息都是在HandlerThread中执行,所以从这个角度来看,IntentService是可以执行后台任务的。 然后在onStart()通过handler发送了一个消息,把我们的intent对象和startId发送出去,在我们上面的handleMessage()会接收到消息,并且通过onHandlerIntent()方法将对象回调给子类。

5、RecycleView原理以及与LIstview的区别

RecyclerView 能实现 ListView 很难或者根本不能实现的效果主要是因为 ListView 的布局排列是由自身去管理的,而 RecyclerView 则将这个工作交给了 LayoutManager ,LayoutManager 中定制了一套可扩展的布局排列接口,子类只要按照接口的规范来实现,就能定制出各种不同排列方式的布局了。

使用 RecyclerView 实现瀑布流布局。除了 LinearLayoutManager 之外 RecyclerView 还提供了 GridLayoutManager 用于实现网格布局,StaggeredGridLayoutManager 用于实现瀑布流布局。

6、view事件分发传递

  • 方法
方法功能activityviewGroupview
dispatchTouchEvent()用于Touch事件的颁发
onInterceptTouchEnent()用于拦截Touch事件
onTouchEvent()用于处理Touch事件
  • 事件的传递方向
    Activity –>PhoneWindow–>DectorView–>ViewGroup–>View;主要操作在ViewGroup和View中

1.如果ViewGroup没有子View,或者子View都不消费事件,或者父View拦截了事件,会将ViewGroup当做普通View处理;看ViewGroup自身是否处理事件
2.如果View重写了OnTouchListener的onTouch()方法,并且返回了true,则onTouchEvent()方法不会再执行了;由此可见onTouch()方法的优先级高于onTouchEvent();
3.如果View重写了onTouchEvent()方法,不调用super.onTouchEvent(),则onClick()方法将不执行;

  • 事件的传递顺序

在这里插入图片描述

7、view的绘制流程

  • onMeasure
  • onLayout
  • onDraw

8、内存泄漏与内存溢出(OOM)区别

  • out of memory(内存溢出)
    是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。
  • memory leak(内存泄露)
    是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。

memory leak会最终会导致out of memory!

内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。
内存泄漏是指你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果你申请到的那块内存你自己也不能再访问(也许你把它的地址给弄丢了),而系统也不能再次将它分配给需要的程序。一个盘子用尽各种方法只能装4个果子,你装了5个,结果掉倒地上不能吃了。这就是溢出!比方说栈,栈满时再做进栈必定产生空间溢出,叫上溢,栈空时再做退栈也产生空间溢出,称为下溢。就是分配的内存不足以放下数据项序列,称为内存溢出.

  • 内存泄漏解决方案
  1. 创建对象使用弱引用,虚引用
  2. 良好的代码习惯,使用完对象后及时回收
  3. leakCanary内存分析,定期检查内存泄漏点
  • 内存溢出解决方案
  1. 适当调整图像大小
  2. 在listview或Gallery等控件中一次性加载大量图片时,只加载屏幕显示的资源,尚未显示的不加载,移出屏幕的资源及时释放,采用强引用+软引用2级缓存,提高加载性能。缓存图像到内存,采用软引用缓存到内存,而不是在每次使用的时候都从新加载到内存。
  3. 采用低内存占用量的编码方式 。比如Bitmap.Config.ARGB_4444比Bitmap.Config.ARGB_8888更省内存。
  4. 及时回收图像 。如果引用了大量的Bitmap对象,而应用又不需要同时显示所有图片。可以将暂时不用到的Bitmap对象及时回收掉。对于一些明确直到图片使用情况的场景可以主动recycle回收
  5. 不要在循环中创建过多的本地变量 。慎用static,用static来修饰成员变量时,该变量就属于该类,而不是该类实例,它的生命周期是很长的。如果用它来引用一些内存占用太多的实例,这时候就要谨慎对待了。
  6. 自定义堆内存分配大小 。优化Dalvik虚拟机的堆内存分配。

9、代码去重

  1. 使用include标签引用重复布局
  2. 使用style定义样式
  3. 使用ViewStub减少整体布局的重复
  4. 多使用应用资源
  5. 代码的抽象与继承

三、图片处理

1、从网络加载一个10M的图片,说下注意事项

四、网络和安全机制

1、TCP和UDP

TCPUDP
链接面向连接,形成传输数据的通道,分为客户端和服务端将数据及源和目的封装成数据包中,不需要建立连接,不区分客户端与服务端
传输大小在连接中进行大数据量传输每个数据报的大小在限制在64k内
安全性通过3次握手完成连接,是可靠协议( 三次握手: 客户端先向服务端发起请求, 服务端响应请求, 传输数据),数据安全面向无连接,是不可靠协议,数据不安全,速度快
优点必须建立连接,效率会稍低不需要建立连接,速度快
应用场景下载,类似现实生活中的打电话视频会议、聊天程序、桌面共享等对于一些丢失数据不是很重要的软件,类似于生活中的对讲机
  • TCP的三次握手,四次挥手
    三次握手
    第一次握手:建立连接时,客户端发送syn包(syn=x)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
    第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;
    第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
    四次挥手
    第一次挥手:客户端Client发送一个FIN,用来关闭客户Client到服务器Server的数据传送,客户Client进入FIN_WAIT_1状态。
    TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
    第二次挥手:服务器Server收到FIN后,发送一个标志位ACK给客户Client,其确认序号ack为收到序号+1(与SYN相同,一个FIN占用一个序号),服务器Server进入CLOSE_WAIT状态。
    TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
    第三次挥手:客户端收到服务器的确认请求之后,此时,客户端就进入FIN_WAIT_2状态,等待服务器发送连接并释放报文(在这之前还需要接受服务器发送的最后的数据),服务器Server发送一个FIN,用来关闭服务器Server到客户Client的数据传送,服务器Server进入LAST_ACK状态。
    第四次挥手:客户Client收到FIN后,进入TIME_WAIT状态(注意此时TCP连接还没有释放,必须经过2∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。),接着发送一个标志位ACK给服务器Server,确认序号为收到序号+1,服务器只要收到客户端发出的确认,服务器Server进入CLOSED状态,完成四次挥手。可以看到,服务器结束TCP连接的时间要比客户端早一些。

2、HTTP与HTTPS的区别以及如何实现安全性

http是超文本传输协议,信息是明文传输;
https 是具有安全性的ssl加密传输协议

五、数据库

六、模块化、组件化、热修复、增量更新、插件化、Gradle

七、架构设计和设计模式

1、架构设计种类

  • MVC设计模式

C–>Controller(控制层)
即继承Activity,Fragment等的这类代码文件。

该模式是由java设计模式演化而来,通过C层让M层和V层有交互。但是相对应的,代码逻辑不够清晰。开发者需要在C层中书写控件逻辑,接口逻辑,业务逻辑等一系列代码。造成一个类文件可能包含几百上千行的代码,不方便接手项目的开发者理解和修改页面的业务逻辑。

  • MVP设计模式

P–>Presenter(交互层)
即处理本该由C层接管的一些简单逻辑交互以及网络请求和对应回调。

该模式是对MVC的一次升级,MVC本身C层的负担过于繁重。控件的交互,网络的请求,以及请求后对应的回调处理等操作全在C层中实现。这样代码量过大且不利于修改和维护,所以将C层中简单的逻辑判断以及网络请求和请求回调后的数据处理这一类的操作提到P层去实现。C层所做的事就是负责丢要处理数据到P层,然后拿到P层的回调,把处理好的数据做装填,以及一些控件的事件绑定,页面的跳转等,而P层负责去建立M层和V层的关系,把结果回调给C层。

  • MVVM设计模式

VM–>ViewModel(数据模型层)
即V层直接和M层做交互,不通过C层,进一步减轻C层的代码量,UI界面大篇幅整改的时候使用这种模式更便于修改。

该模式是对MVP或者MVC的进一步升级,如果说MVP缩减了C层的一部分代码量,那MVVM就是彻底的让C层与M层还有V层没有了关系。C层只负责做对应事件控件的绑定,其余部分不通过C层这个所谓的控制层做操作,让M层直接和V层做交互。整个页面的代码逻辑更进一步解耦,脉络也更清晰。

2、三种设计架构的区别

  • MVP与MVC区别
    MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会直接从Model中读取数据而不是通过 Controller。

  • MVVM与MVP区别
    mvvm模式将Presenter改名为View Model,基本上与MVP模式完全一致,唯一的区别是,它采用双向绑定(data-binding): View的 变动,自动反映在View Model,反之亦然。这样开发者就不用处理接收事件和View更新的工作,框架已经帮你做好了。

3、设计模式

  • 设计模式有哪些
    总体来说设计模式分为三大类:
    ① 创建型:共5种
    工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式
    ② 结构型:共7种
    适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式
    ③ 行为型:共11种
    策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式

  • 工厂模式
    在这里插入图片描述
    代码如下:

  • 单例模式
    在这里插入图片描述
    代码如下:

  • 适配器模式
    在这里插入图片描述

代码如下:

  • 观察者模式
    在这里插入图片描述
    代码如下:

八、算法

1、冒泡排序

2、二分法排序

3、快速排序

九、性能优化

1、屏幕适配

适配的关键在于两点:
(1)不同分辨率设备的适配,这点在单位的使用上用dp、sp以及图片资源存放于不同的drawable文件夹就可以解决问题;
(2)不同尺寸的适配,这点主要靠将相关值以及布局文件放置于不同的文件夹中来解决。

  • value
  1. 百分比引入:就是在项目中针对你所需要适配的手机屏幕的分辨率各自建立一个文件夹。
  • layout文件夹
    如果在不同尺寸设备上展示的布局有明显差别,仅仅用values不同已经难以控制,
    那么就可以考虑写不同的布局文件置于不同的layout文件夹下,android会根据设备
    尺寸去加载相应文件夹下的布局文件。如:layout-sw480dp,layout-sw600dp,
    layout-sw700dp等。

多用match_parent
多用weight
自定义view解决

2、动态布局的理解

动态布局:用代码来调整View位置

这里只介绍三种布局情况(注意不是方式)

1、无xml : 一个父类布局包含一个子父类布局,子父类布局中包含ImageView

2、无xml : 只有一个父类布局包含一个ImageView

3、有xlm布局: 通过布局ID 来进行动态布局添加

总结了下其实步骤如下:

无xml布局:

1、setContentView()之前new一个需要的布局layout,再将layout放入setContentView()

2、new 出需要的控件设置好参数(id、text···)

3、new LayoutParams 设置好控件的大小、位置属性(这里感觉和xml设置控件属性是一样的)

4、最后将params和控件放入之前new的layout即可

有xml布局:

1、setContentView()和以前一样放入layout.xml

2、通过findViewById()找到要进行添加的布局控件

之后的步骤和无xml布局的2、3、4一样

3、jvm了解以及内存模型和GC回收

android:Java垃圾回收机制

4、ClassLoader工作机制、双亲代理

Android动态加载基础:ClassLoader工作机制

5、进程保活

android:越来越难实现的进程保活

十、NDK、jni、Binder、AIDL、进程通信有关

1、AIDL

Android:学习AIDL,这一篇文章就够了(上)

2、JNI、NDK

Android Studio平台下JNI开发:入门使用及常见错误

十一、Framework层、ROM定制、Ubuntu、Linux之类的问题

十二、跨平台Hybrid 开发

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值