转载

对陈同学面试问题的自己的回答

本文章大部分题目都来自陈同学的博客文章,当然,里面也加入了一点点我从别的地方摘抄的题。除了算法之外,其它的应该大部分都有写。

Activity

Q:说下Activity的生命周期?

A:Activity的生命周期是 oncreate()->onStart()->onResume()->onPause()->onStop()->onDestroy()

Q:onStart()和onResume()/onPause()和onStop()的区别?—

A:onStart()是程序刚启动时调用的,此时程序还没有显示在屏幕上。而onResume()的时候程序已经显示在屏幕上了。onPause是程序由活跃状态转向不活跃状态调用的,而onStop()的时候程序已经不可见了,从前台转向了后台。

Q:Activity A启动另一个Activity B会回调哪些方法?如果Activity B是完全透明呢?如果启动的是一个Dialog呢?

A:A会回调onPause() 紧接着B会回调onCreate()->onStart()->onResume(),接着A再回调onStop(),如果Activity B是完全透明呢则最后不会调用onStop(),Dialog同理

Q:谈谈onSaveInstanceState()方法?何时会调用?

A:这个方法是用于当程序意外关闭的时候用来储存重要信息的,系统配置发生改变时导致Activity被杀死并重新创建,或者资源内存不足导致低优先级的Activity被杀死(前台、可见非前台、后台),就会调用该方法。也就是说,这个方法只有在Activity被异常销毁并有机会重现的情况下才会调用。

Q:onSaveInstanceState()与onPause()的区别?

A:onSaveInstanceState()不能保证每次都会调用,而onPause必然会被调用,onSaveInstanceState可以用来存储一些重要信息,而onPause中不能进行耗时的大重量操作。

Q:如何避免配置改变时Activity重建?—

A:修改AndroidManifest.xml中的属性,比如最常见的我们不让程序在旋转屏幕时重新创建就需要加上 android:configChanges = “orientation|screensize”

Q:优先级低的Activity在内存不足被回收后怎样做可以恢复到销毁前状态?

A: 在onSaveInstanceState存储相关的重要数据,在onCreate中根据这些数据恢复

Q:说下Activity的四种启动模式?(有时会出个实际问题来分析返回栈中Activity的情况)

A: 分为standard默认模式、singleTop栈顶复用模式、singleTask栈内复用模式和singleInstance单实例模式。它们之间的区别是,A启动B,若B是标准模式的话,启动多少次B就会产生多少个B的实例,若B是栈顶复用模式且此时B位于任务栈的栈顶,则不会重复创建实例,否则效果与standard是一样的。而singleTask是只要B位于任务栈中,就不会重复创建。singleInstance保证了singleTask的特点之外还加了一点就是B只能单独位于一个任务栈中,就相当于全局单实例。

Q:谈谈singleTop和singleTask的区别以及应用场景

A: 区别前面已经说了。

简单说下singleTop的应用场景,比如我们点进了一个新闻App,在浏览新闻详情页,这时通知栏推送了一个消息,用户点击了这个消息,会显示详细新闻。如果我们不采用singleTop模式的话,就会产生两个新闻详情页的页面。又或者登录成功跳转到主页,按下两次登录按钮,生成了两个主页。(这一般是网络延迟造成的)。

singleTask的应用场景是:当我们的程序已经调用很深了,这时候要返回首页,使用singleTask就可以清空上面的栈

Q:onNewIntent()调用时机?

A:这个方法要和我们的Activity的启动模式联系起来。比如singleTop模式,当我们要启动的Activity已经处于栈顶,那么就会调用这个方法。再比如singleTask模式,当我们要启动的Activity已经在栈里面的时候,也会调用这个方法。

Q:了解哪些Activity启动模式的标记位?

A:FLAG_ACTIVITY_NEW_TASK及singleTask、FLAG_ACTIVITY_SINGLE_TOP即singleTop模式、FLAG_ACTIVITY_CLEAR_TOP表示启动A时,它上面的Activity全部出栈

Q:如何启动其他应用的Activity?

A: 通过隐式Intent,填入其它应用Activity相应的Action就可以

Q:Activity的启动过程?—

A:startActivity最后都会调用到startActivityForResult,在startActivityForResult有Instrumentation的exeStartActivity,这个方法里有一句代码:ActivityManagerNative.getDefault().startActivity。ActivityManagerNativet其实是实现了IActivityManager接口的,而ActivityManagerServie继承了ActivityManagerNative,也就是说AMS是服务端,ActivityManagerNative.getDefault是会返回一个Binder,通过它我们就可以调用AMS里面的startActivity了。接下来就是ActivityStackSupervisor和ActivityStack之间的相互调用,最后会调用ActivityStackSupervisor的realStartActivityLocked方法,这个方法里有一句代码,app.thread.scheduleLauchActivity。app.thread就是IApplicationThread。ApplicationThreadNative继承了这个接口,而ApplicationThread则实现了ApplicationThreadNative,所以最终逻辑交给了ApplicationThread。ApplicationThread最终会发送一个消息给Handler - H。H会相应调用handleLaunchActivity。这个方法主要完成了以下工作,取得要启动的Activity的相关信息,使用类加载器生成Activity,检测是不是有创建Application,否则就创建。用ContextImpl调用Activity的atttach方法,完成数据初始化,创建视图。最后调用onCreate

Q:ActivityThread的main方法主要做了哪些操作?—

A:是整个应用程序的入口,主要就是开启了mainLooper循环,创建一个Handler。

Fragment

Q:谈一谈Fragment的生命周期?——

A:onAttach()->onCreate()-> onCreateView()->onStart()->onResume()->onPause()->onStop()->onDestroyView()->onDestroy()->onDetach()

Q:Activity和Fragment的异同?—-

A:Fragment是依附在Activity上的,Fragment的生命周期方法比Activity多了几个,分别是onAttach()/onDetach(),onCreateView()和onDestroyView。

从灵活性上说,可以用hide/show/replace动态对fragment进行流畅切换,而Activity则有明显的动画效果

Q:Activity和Fragment的关系?

A:Fragment是依附在Activity上的,当Fragment可见,且该Activity处于运行状态那么Fragment也是运行状态。当Activity处于停止状态,Fragment也是停止状态,当Activity处于暂停状态,Fragment也是暂停状态。Fragment可以直接在XML里面创建,而Activity不可以。

Q:何时会考虑使用Fragment?

A:

Service

Q:谈一谈Service的生命周期?

A:分情况说吧,第一种是直接启动Service,那么生命周期是onCreate()->onStartCommand()->onDestroy()

第二种是绑定Service,那么生命周期就是9nCreate()->onBind()->onUnBind()->onDestroy()

第三种是既启动Service又绑定Service,那么生命周期就是onCreate()->onStartCommand()->onBind()->onUnBind()->onDestroy()

Q:Service的两种启动方式?区别在哪?

A:startService()和bindService()。

区别一:就是通过startService启动的,即使Actvitiy被销毁了,它也会存在,除非调用stopService()或者在Service内部调用stopItSelf()才会销毁。而通过bindService启动的,只要Activity被销毁了,它也就跟着销毁了

区别二:startService()不能跟Service展开交互,而bindService可以

Q:一个Activty先start一个Service后,再bind时会回调什么方法?此时如何做才能回调Service的destory()方法?

A:会调用oncreate()->onStartCommand()->onBind()方法,先unbindService()再stopService()

Q:Service如何和Activity进行通信?

A:通过bindServie()进行通信

Q:用过哪些系统Service?

A:

Q:是否能在Service进行耗时操作?如果非要可以怎么做?

A:不能,因为Service默认是UI线程的,需要开启线程执行耗时操作

Q:AlarmManager能实现定时的原理?

A:

Q:前台服务是什么?和普通服务的不同?如何去开启一个前台服务?

A:普通情况下,我们启动的都是普通服务,前台服务就是Service在运行的时候会在通知栏显示。在Service内(一般是onCreate里)通过Notification开启,startForeground()

Q:是否了解ActivityManagerService,谈谈它发挥什么作用?

A:它在四大组件的创建过程中发挥了很大作用,主要就是发送一个消息给handler H,通知它完成创建四大组件的工作。

Q:如何保证Service不被杀死?—

A:有几种方案,第一种:在onStartCommand里flages设为START_STICKY。onStartCommand()的参数里有几个flag,分别是START_STICKY,它会在Service被杀死后尝试启动Service,它不会保留之前的Intent。START_NOT_STICKY,如果Service被杀死后没有Intent传来,那么它不会重新创建。START_REDELIVER_INTENT,如果会在Service被杀死后尝试启动Service,并保留最后之前最后一个传入的Intent,第二种是在onDestroy的时候再启动Service。第三种与第二种差不多,就是在onDestroy的时候发送一个广播,接收器收到之后启动Service。

Broadcast Receiver

Q:广播有几种形式?什么特点?

A:普通广播、有序广播、粘性广播、本地广播。有序广播有优先级,其中的接收者可以截断广播。粘性广播则是只要发出消息,无论什么时候注册接收器都会听到。本地广播仅限在本应用中传播,提高了安全性。

Q:广播的两种注册形式?区别在哪?

A:静态注册和动态注册。静态注册的广播不会随着应用退出而退出,它会一直存在。动态注册的广播则会随着应用的退出而退出。

ContentProvider

Q:ContentProvider了解多少?

A:

数据存储

Q:Android中提供哪些数据持久存储的方法?

A:Room、Realm、SharePreferences、SqlLite,文件写入

Q:Java中的I/O流读写怎么做?—

A:FileInputStream,BufferStream,ObjectStream

Q:SharePreferences适用情形?使用中需要注意什么?

A:储存一些轻量级的数据,只能存储基本类型和String类型的数据,提交后记得要apply()。sp不要存储超大的Value,(尽管它是可以存储的),原因就在于所有的key和value都是常驻内存的,value过大会极大地影响到App的性能。

Q:了解SQLite中的事务处理吗?是如何做的?

A:不怎么了解,因为一般用的是Romm和Realm

Q:使用SQLite做批量操作有什么好的方法吗?

A:略

Q:如果现在要删除SQLite中表的一个字段如何做?

A:略

Q:使用SQLite时会有哪些优化操作?

A:略

IPC

Q:Android中进程和线程的关系?区别?

A:进程包括线程,是一个1对多的关系。普通情况下,我们一个应用只有一个进程,进程内有多个线程

Q:为何需要进行IPC?多进程通信可能会出现什么问题?—

A:多进程下,访问一个变量会得到一个副本,IPC就是为了解决不同进程数据传输、共享数据的问题的。

1.SharedPreference可靠性下降

2.Application会多次创建

3.静态和单例会失效

4.线程同步失效

Q:什么是序列化?Serializable接口和Parcelable接口的区别?为何推荐使用后者?—

A:序列化就是把我们的对象转化成字节流,一般我们写数据到数据库、文件、网络传输等就需要用到序列化。序列化可以解决跨平台的问题,可以解决对象流重新恢复下多生成对象的问题。Parcelable是谷歌自己出的一个序列化机制,它的优点是效率较高,是内存读写,放在Intent里面传递或者IPC里面是十分适合的。Serializable接口是使用IO硬盘读写,内存读写显而易见地要比硬盘读写效率高得多。

Q:Android中为何新增Binder来作为主要的IPC方式?

A:内存复制只需要一份,可以加入权限分辨与限制

Q:使用Binder进行数据传输的具体过程?

A:首先客户端调用方法,Stub里面的Proxy的transact被调用,stub的onTransact被调用,根据code和_data执行相应的方法,接着向reply中写入结果返回值,Proxy再返回reply的值给客户端。

Q:Binder框架中ServiceManager的作用?

A:

Q:Android中有哪些基于Binder的IPC方式?简单对比下?—

A:Message和AIDL,Message只能传递消息,不能调用方法,再者它只支持串行通信,而且只能传递Bundle支持的数据类型,AIDL则能调用方法,支持并发通信,支持自定义的数据类型(只要该数据类型实现了序列化)。

Q:是否了解AIDL?原理是什么?如何优化多模块都使用AIDL的情况?

A:AIDL底层用了Binder。使用Binder线程池,之前我们创建一个AIDL就要对应地给出一个服务端Service,当有多个AIDL的时候,就是有多个Binder,每个都配一个Service开销非常大。所以我们采用Binder线程池的做法,定义一个接口,根据请求返回对应的Binder,远程Service就只返回Binder线程池,然后我们在BinderPool内连接上远程服务,在BinderPool内实现接口,根据请求返回不同的Binder。

View

Q:MotionEvent是什么?包含几种事件?什么条件下会产生?

A:MotionEvent指的是用户一次按下抬起的过程,它包括down、move、up这三个事件。

Q:scrollTo()和scrollBy()的区别?

A:scroolTo是绝对移动,scrollBy是相对移动

Q:Scroller中最重要的两个方法是什么?主要目的是?

A:scrollTo和srcollBy,一个根据原点坐标滑动,一个根据自身坐标滑动

Q:谈一谈View的事件分发机制?

A:用一句话来概括就是,父布局决定是否拦截事件,如果拦截事件,那么事件就交给父布局处理,如果父布局不拦截事件,那么事件就交给子布局处理。如果没有人处理的话,事件会再交给上一级处理。

Q:如何解决View的滑动冲突?

A:有两个方法,一个是外部拦截,一个是内部拦截。外部拦截主要就是重写onInterceptTouchEvent(),首先父容器不能拦截ACTION_DOWN,否则所有的事件都会交给它处理,一般我们的拦截逻辑是在ACTION_MOVE里面写的。内部拦截就是子布局通过parent.requestDisallowInterceptTouchEvent()来完成的,同样的,父布局不能拦截ACTION_DOWN,且默认拦截ACTION_MOVE和UP,当子布局需要拦截某个手势的时候,只需要在requestDisallowInterceptTouchEvent()里写入true。

Q:谈一谈View的工作原理?

A:View有三大流程,measure过程、layout过程、draw过程。measure过程简单概括就是父布局调用performMeasure->measure->onMeasure,在onMeasure里会调用所有子元素的Measure方法,遍历测量子布局,最终完成最自己的测量。layout过程跟measure差不多,父布局调用performLayout->layout->onLayout,在onLayout里会调用子元素的layout,最后会完成自己的layout,draw过程跟上面的差不多。

Q:MeasureSpec是什么?有什么作用?—

A:有32位,高2位储存模式,低30位储存尺寸。它被用于储存View的测量数据。它很大程度上决定了View最后的尺寸。

Q:自定义View/ViewGroup需要注意什么?—-

A:注意wrap_content的实现,和滑动冲突处理,draw里支持padding,有线程或者动画要在onDetachedFromWindow时调用,否则会内存泄漏,不要使用Handler,因为View里自带view.post的方法。

Q:onTouch()、onTouchEvent()和onClick()关系?

A:如果有设置OnTouchListener的话,就会执行onTouch,如果onTouch返回了false,那么就会执行onTouchEvent,如果此时有设置OnclickListener,那么将会再执行onClick

Q:SurfaceView和View的区别?

A:

Q:invalidate()和postInvalidate()的区别?

A:前者是在UI线程中调用,后者是在非UI线程中调用。它们的作用都是刷新界面。

Drawable等资源

Q:了解哪些Drawable?适用场景?

A:

Q:mipmap系列中xxxhdpi、xxhdpi、xhdpi、hdpi、mdpi和ldpi存在怎样的关系?

Q:dp、dpi、px的区别?—

A:dp称为密度无关像素。dpi成为屏幕像素密度。px是像素。我们手机都有各种分辨率,比如720x1080指的是,宽有720像素,长有1080像素,那么手机dpi的计算就是求出屏幕对角线的像素,除以对角线的英寸。倘若没有dp的话,我们设定控件用px来设定,那么在不同的屏幕分辨率下显示效果是不同的。比如这个有一个控件长占屏幕的一半,在320x480的屏幕上,px值应该是160,在480x800的屏幕上,px值应该是240。这样屏幕适配就会很麻烦。dp的出现就是为了解决这个问题,它与px的互换公式是 dp = (dpi/160)* 1px。所以它能让控件在不同的分辨率上有相同的显示效果

Q:res目录和assets目录的区别?

A:Assets存放一些配置文件、资源文件。assets不会生成资源对应的ID,而是通过AssetManager类的接口获取

res存放资源文件,会自动生成对应ID映射到R文件中,访问时直接使用资源ID就好

Animation

Q:Android中有哪几种类型的动画?

A:属性动画。View动画,帧动画

Q:帧动画在使用时需要注意什么?

A:帧动画就是切换图像,这时候要注意压缩图片,否则容易造成OOM

Q:View动画和属性动画的区别?

A:View动画并没有改变View的真正位置,属性动画是真正改变了View的位置。

Q:View动画为何不能真正改变View的位置?而属性动画为何可以?

A:属性动画改变的是View的位置属性的值,所以能真正改变View的位置

Q:属性动画插值器和估值器的作用?

A:插值器是根据时间流逝的百分比来计算当前属性值改变的百分比,估值器是根据当前属性改变的百分比计算出当前属性值。

Window

Q:Activity、View、Window三者之间的关系?

A:一个Activty对应一个Window,Window就是Activity展示的舞台,而Window的实质就是View

Q:Window有哪几种类型?

A:应用窗口(Activity)、子窗口(Dialog)、系统窗口(Toast、SnackBar)

Q:Activity创建和Dialog创建过程的异同?

A:WindowManager交给WindowManagerImpl来处理,用addView完成创建,具体的逻辑是先判断参数是不是合法,接着创建ViewRootImpl,将Vuew添加到列表中,通过ViewRootImpl完成Window的添加过程,具体逻辑是WindowSession,这是一个Binder调用,最后是WindowManagerService完成界面添加。

对建立的View数据进行遍历,找出这个View,最后也是ViewRootImpl执行了删除操作,删除有两种方式,一种是同步,一种是异步,最后都会调用doDie方法,完成界面删除。

Handler

Q:谈谈消息机制Handler?作用?有哪些要素?流程是怎样的?—

A:简单概括就是Handler机制里有一个Handler、一个MessageQueue、一个Looper。Handler发送消息就会插入到MessageQueue中,而Looper会不断调用MessageQueue的next方法获取消息,然后交给Handler的diapatchMessage中处理,而这个行为是运行在创建Handler所使用的Looper中调用执行的,所以成功切换到指定的线程中执行了。diapatchMesage中,如果检查到消息里有runnable,则执行runnable,如果没有runnable,有CallBack监听器,那么执行CallBack里面的handleMessage方法,否则就执行Handler的handleMessage方法。

Q:为什么系统不建议在子线程访问UI?

A:在子线程中访问UI会导致UI的状态不确定

Q:一个Thread可以有几个Looper?几个Handler?

A:可以有一个Looper,多个Handler

Q:如果在主线程中同时创建10个Handler,会发生什么事?

A:没有什么事,无非就是自己发的Message自己处理而已

Q:如何将一个Thread线程变成Looper线程?Looper线程有哪些特点?—

A:Looper.prepare(),Looper.loop()

Q:可以在子线程直接new一个Handler吗?那该怎么做?

A:不可以,要先创建Looper,并开启Looper循环

Q:Message可以如何创建?哪种效果更好,为什么?——

A:可以通过三种方法创建。

第一种:直接生成实例Message m = new Message

第二种:通过Message.obtain

第三种:通过mHandler.obtain

后两者效果更好,因为后两者是直接在消息池中取出一个消息,Android默认的消息池中消息数量是10.这样做就可以避免多生成实例。

Q:这里的ThreadLocal有什么作用?

A:ThreadLocal用来给不同的线程提供对应的Looper

Q:主线程中Looper的轮询死循环为何没有阻塞主线程?—

A:主线程本来就是Looper死循环的过程,如果Looper推出循环了,那么程序运行也就结束了。主线程就是死循环的,当一个消息来到,主线层就被唤醒,消息处理了,主线层就沉睡了,这不会对CPU性能有多大的损耗。主线程中的死循环不会造成死循环,只有死循环中处理的事件出现了很大的耗时才会造成ANR。

Q:使用Hanlder的postDealy()后消息队列会发生什么变化?

A:如果队列中只有这个消息,那么消息不会被发送,而是计算到时唤醒的时间,先将Looper阻塞,到时间就唤醒它。如果此时要加入新消息,如果该消息没有delay时间或者delay时间更短,则插入到头部。

线程

Q:Android中还了解哪些方便线程切换的类?

A:Handler、new Thread、AsyncTask

Q:说一下AsyncTask的实现?—

A:首先呢,把任务的相关参数包装成FutureTask对象,接着AsyncTask第一个线程池SerialExecutor闪亮登场,把这个FutureTask插入到队列中,并顺序执行任务,这时AsyncTask第二个线程池THREAD_POOL闪亮登场,它的工作就是执行这个任务,并发送消息给Handler,Handler会根据传来的消息类型分辨出此时是PROGRSS还是RESULT,并根据类型执行对应的方法,PROGRESS就执行onProgressUpdate(),RESULT还要进一步判断是真的完成了,还是终断再也不执行,完成就调用onPostExecute(),终断不执行就调用onCancelled()

Q:AsyncTask相比Handler有什么优点?不足呢?—

A:AsyncTask比Handler代码上要简单得多,处理任务是可控的。不足就是处理多个任务时,而且需要UI变更,就有点复杂。Handler处理多个任务就比较清晰,如果只是处理一个的话,代码量就有点儿多。

Q:使用AsyncTask需要注意什么?—

A:需要及时关闭,否则容易造成内存泄漏。在destroy的时候尽量cancel掉它,防止内存泄漏。不要手动去调用onProgressUpdate等方法。要在UI线程创建,execute要在UI线程调用,一个AsyncTask只能调用一次

Q:AsyncTask中使用的线程池大小?

A:THREAD_POOL_EXECUTOR的核心线程是CPU数+1,任务队列128,非核心线程是CPU数,总线程是2*CPU数+1

Q:HandlerThread有什么特点?

A:已经开启好了Looper循环,普通Thread是在run中执行一个耗时任务,而它需要结合Handler来处理串行的任务。

Q:快速实现子线程使用Handler(有点问题)——–

A:Looper.prepare Looper.loop?

Q:IntentService的特点?

A:运行完程序就会自动关闭,它在内部已经使用了HandlerThread和Handler,所有的Intent都会交给Handler处理,最终在HandlerThread中执行,执行完都调用stopItself

Q:为何不用bindService方式创建IntentService?—

a:消息的发送是在onStartCommand中执行的,而且IntentService的onBind方法本来就返回了null。

Q:线程池的好处、原理、类型?

A:避免重复大量地重建线程,对线程进行管理,实现资源利用

Q:ThreadPoolExecutor的工作策略?

A:有核心线程优先使用核心线程,核心线程满了,任务队列可用就放进任务队列,任务队列满了,有非核心线程使用非核心线程。有超时时长设置的话,一旦空闲的非核心线程超过这个时间就会被回收。否则就等待被重用。

比较常见的有四种线程池:

1.FixThreadPool:只有核心线程

2.CacheThreadPool只有无上限的非核心线程,超时时间是1分钟

3.ScheduledThreadPool有核心线程和无上限的非核心线程,超时时间为0

4.SingleThreadExecutor只有一个核心线程

Q:什么是ANR?什么情况会出现ANR?如何避免?在不看代码的情况下如何快速定位出现ANR问题所在?—

A:程序没有响应。Activity5s无反应。前台Service20s无反应,后台Service200s无反应,广播10s。大重量的工作应当交给子线程,而不是在主线层中,主线层主要执行UI相关的操作,对于请求网络,数据库操作这些繁重工作应当在子线程中进行。

Bitmap

Q:加载图片的时候需要注意什么?—

A:需要压缩图片大小,设定bitmapFactory.Options中设定inJustDecodeBitmapBitmap为false,主要目的是为了不加载图片来获得图片大小,拿到大小后,根据ImageView所需要的大小计算出inSampleSize,最后设inJustDecodeBitmapBitmap为true,加载图片。

Q:LRU算法的原理?—

A:大概了解了一下,貌似用的是链表,新的数据,如果没有在链表中存在的话,就插入到链表顶端,如果有存在,则移动到链表顶端。链表要满的时候就移除底端的数据。

Q:Android中缓存更新策略?

A:

性能优化

Q:项目中如何做性能优化的?—

A:

1.布局优化:

能用LinearLayout和FrameLayout就不要用RelativeLayout,毕竟RelativeLayout控件的测绘比较耗时

多用Include复用布局,用merge减少层级,用viewstub去按需加载八百年才用的功能:如进度条等

复杂布局尝试使用ConsttraintLayout

2.绘制优化:

onDraw是常常要被调用的,在自定义View里面,onDraw不要做耗时的任务,也不要做过多的循环操作

onDraw不要创建新的局部变量,因为它频繁调用的特性,这种操作会产生大量的临时对象,占用过多的内存,还会导致系统频繁GC

3.内存泄漏优化:

看下面

4.资源优化

使用Lint工具检查无用的资源,开启shrinkResource = true

能用xml表示的图片就尽量用xml

压缩图片

5.线程

有大量线程应考虑用线程池,线程池可以重用线程,避免了大量线程的创建和销毁,还能控制并发数。

6.列表

滑动的时候不加载图片

Q:了解哪些性能优化的工具?

A:第一:使用LeekCanary,它的步骤是导入LeekCanary的库,然后自定义一个Application,在Applicaton中初始化LeekCanary。当手机安装了应用出现内存泄漏,LeekCanary就会以通知栏的形式通知给我们。第二:使用AS自带的profile analysis,当我们运行一段程序后,可以手动GC,看是否有一些不应该存在的类的实例。

Q:布局上如何优化?列表呢?

A:使用merge或者include。Include使用场景,不同的布局需要同一个part,这时候使用include能很大地优化布局加载。merge使用场景,父布局和子布局的根布局是一样的,我们就可以引入merge来减少布局层数。对于列表来说,需要优化的通常就是列表加载图片,这是很容易造成OOM的场景,对此我们的策略就是在滑动的时候不进行图片加载,停止滑动才进行图片加载。

Q:内存泄漏是什么?为什么会发生?常见哪些内存泄漏的例子?都是怎么解决的?—

A:内存泄漏就是有些应当回收内存不能被回收。原因是长周期的对象引用了短周期的对象,导致短周期的对象无法被回收。例子:

1.某个静态类持有了Activity的引用,由于静态类声明周期与Application一样长,导致Activity无法被回收

2.资源未关闭导致的内存泄漏,比如忘记解注册广播,Service运行了忘记stopItself,文件流忘记关闭,Rxjava没有取消订阅

3.匿名内部类和非静态内部类都会持有外部类的引用,这种情景下也容易造成内存泄漏。就拿匿名内部类来说,AsyncTask持有Activity,当Activity要结束的时候,后台任务还没有结束,那么Activity就无法回收。非静态内部类的典型情景就是Handler,当Activity内部有一个Handler内部类,这个Handler会在十分钟后发送消息,此时我们退出Activity,Activity是无法被回收的。还有一种比较典型就是我们静态实例了一个的内部类对象,由于这个对象持有外部类的引用,同时它的生命周期与Application一样长,这就会造成内存泄漏。

解决方法:

4.集合类泄漏,比如集合类添加完元素后,销毁时仍然引用着集合元素对象,这就导致集合元素对象无法被回收

1.匿名内部类的异步操作在Activity的onDestroy中要及时取消。

2.针对一些非静态内部类,可以转化成静态内部类的方式,同时内部类如果有对Activity的引用,尽量转化成弱引用

3.在遇到需要Context的调用中,要格外注意,尽量使用ApplicationContext

4.及时解注册,释放资源等

5.一些生命周期较长且内存占用较大的对象可以考虑采用弱引用。(PS:这里可以延伸阐释四种引用的区别)

6.集合类不用及时clear

Q:内存泄漏和内存溢出的区别?

A:内存泄漏一般还不会导致应用崩溃,而内存溢出就会导致应用崩溃。内存泄漏得多可能会引起内存溢出。

Q:什么情况会导致内存溢出?

A:同上。

谷歌新动态

Q:是否了解和使用过谷歌推出的新技术?

Q:有了解刚发布的Androidx.0的特性吗?

Q:Kotlin对Java做了哪些优化?

Java

基础

Q:面向对象编程的四大特性及其含义?—

A:封装:把外界不需要的信息包装起来

比如在Person里面set/get一个私有变量

继承:子类继承父类,复用父类优秀的特点

多态:多个子类继承父类,而它们又是各自不同的

抽象:把一些共有方法抽象出来,比如车都会启动,鸟都会飞

Q:String、StringBuffer和StringBuilder的区别?—

A: String是字符串常量,StringBuffer和StringBuilder是字符串变量。举个例子说明,当我们拼接一个字符串,String的话是重新生成一个实例,而StringBuffer和StringBuilder则是对当前变量进行更改。当我们需要大量的拼接字符串的行为时,不要选择String,因为销毁并重新生成实例是一个效率很低的操作。StringBuffer和StringBuilder的区别则是StringBuffer是线程安全的,它的方法都带有synchronized关键字,所以StringBuffer适用于多线程,而StringBuilder适用于单线程。

Q:String a=””和String a=new String(“”)的的关系和异同?

A:String a=””只是一个引用,如果内存里已经有””,那么就指向它,否则创建它。String a=new String(“”)每次都会创建一个新实例

Q:Object的equal()和==的区别?

A:equal()可以用于比较两个类的值是否一样(不是地址),==是基于地址的相同的判断。

Q:装箱、拆箱什么含义?

A:JAVA里有许多基本类型,它们都有对应的包装类,把基本数据类型转化成对应的包装类就是装箱,反之就是拆箱。

举例说明,把int转化成Integer就是装箱,把Integer转化成int就是拆箱。装箱后就是一个类的对象,可以有很多调用的方法,第二是在泛型里面是不可以用基本类型数据。

Q:int和Integer的区别?

A:int是基本数据类型,而Integer不是

Q:遇见过哪些运行时异常?异常处理机制知道哪些?

A:

异常:

IndexOutOfBoundsException(下标越界异常)

NullPointerException(空指针异常)

IOException(操作输入流和输出流时可能出现的异常。)

机制:try catch捕获异常、throw抛出异常

Q:什么是反射,有什么作用和应用?—

A:反射就是在运行状态,对于一个类,能获取它所有的属性和方法,能调用它的所有属性和方法。

Q:什么是内部类?有什么作用?静态内部类和非静态内部类的区别?—

A:在类内部再定义一个类。内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号

作用

1.内部类隐藏在外部类之内,这就提供了很好的隐私性,即不允许其它类随随便便就能访问它。

2.内部类可以自由访问外部类的对象

3.内部类可以继承与外部类完全不同的接口,无论外部类继承了什么接口,对内部类都没有影响

区别

就是静态内部类不会持有外部类的引用,而非静态内部类会

静态内部类无法访问外部类非静态的变量

静态内部类的实例化不需要通过生成外部类来间接生成,也就是说它跟外部类其实是独立的

Q:final、finally、finalize()分别表示什么含义?

A:final表示属性不能改变,方法无法重写,类不能继承。finally则是在try catch捕获异常模型的补充,表示总会执行,通常用来释放资源。finalize在对象被GC回收时调用。是对象最后一次逃脱回收的途径,只要对象在finalize中与其他对象建立联系,就可以逃脱被回收的命运,但是只能调用一次

Q:重写和重载的区别?

A:重写表示子类重写父类的方法,重载指的是同一个方法名,不同的参数列表。

Q:抽象类和接口的异同?

A:抽象类可以有方法不用抽象,接口所有方法都是抽象的,不能实现。抽象类的方法可以是public,protect等,而接口只能是public。抽象类中的变量有可以有多个修饰符,而接口中的变量只能是Public static final

Q:为什么匿名内部类中使用局部变量要用final修饰?

A:匿名内部类持有对外部类的引用,所以匿名内部类可以使用外部类的变量。由于外部类局部变量有可能会死亡,而匿名内部类要使用这个变量,就要把这个变量复制一份(地址或者值),这样匿名内部类其实使用的是一个拷贝。Java编译器的机制无法给内部类和外部类提供同步变更的机制,这意味着如果不是final的话,内部类改变了局部变量的值却无法与外部类同步,所以为了保证一致性,需要加上final。

Q:Object有哪些公用方法?—

A:equal(),判断两个对象是否相等

toString(),转化成字符串,否则返回句柄

clone(),克隆该对象,这里可以深入阐释浅克隆和深克隆

hashcode(),产生并一个哈希值

getClass(),获得类型

wait(),将持有这个对象锁的线程放弃掉锁,并进入等待状态

notify(),通知在等待这个对象锁的线程

notifyAll(),通知所有等待这个对象锁的线程

集合

Q:Java集合框架中有哪些类?都有什么特点

A:List,Set,Map。

List可重复集合

Set不可重复集合

Map键值对,键不可重复

Q:集合、数组、泛型的关系,并比较—–

A:集合用到了泛型。集合可以不用预先定义容量,数组需要先定义容量。

Q:ArrayList和LinkList的区别?

A:一个是用数组实现,一个是用链表实现。ArrayList查询操作占据优势,LinkList删除插入操作占据优势。

Q:ArrayList和Vector的区别?

A:一个是线程不安全,一个是线程安全

Q:HashSet和TreeSet的区别?

A:一个是无序的,一个是升序的

Q:HashMap和Hashtable的区别?

A:一个是线程不安全的,一个是线程安全的

Q:HashMap在put、get元素的过程?体现了什么数据结构?—

A:put的时候根据key和数据length计算出Index,接着如果存在相同key,那么覆盖旧值并返回,如果奴存在相同key,那么就插入链表。

get的时候根据key和数组length计算出Index,在链表中查询,如果key值相同就返回该key的value

Q:如何解决Hash冲突?

A:

Q:如何保证HashMap线程安全?什么原理?—-

A:使用HashTable。或者使用synchronizedMap,ConcurrentHashMap。前两个原理差不多,都是给通过给方法加锁来保证线程安全。而ConcurrentHashMap采取的是Segment,就是对一个key进行操作,都是通过这个key对应的Segment进行的。为了保证线程安全,只需要对这一个Segment加锁就好,不需要锁住整个类,所以效率很高。

Q:HashMap是有序的吗?如何实现有序?

A:HashMap是无序的。

Q:HashMap是如何扩容的?如何避免扩容?

A:

Q:hashcode()的作用,与equal()有什么区别?

A:hashcode主要是方便,可以直接根据类生成的hashcode来比较,但是它不能保证绝对相等,因为不同类可能产生哈希碰撞。而equal()绝对保证了相比的逻辑正确性,是绝对可靠的,但是这种方法效率较低下。因此我们在实际的操作中可以先通过哈希值进行判断,一旦hash值相同,就可以进一步用equal()进行判断。

并发

Q:开启一个线程的方法有哪些?销毁一个线程的方法呢?—

开启:

1.继承Thread类,重写run方法

2.继承Runnale,放在线程构造里

3.匿名实现Runnbale,放在线程构造里

销毁:

一般来说,run里面的方法跑完了线程就结束了。但是往往run的方法没那么容易就结束

1.设置一个标记位,可以退出run

2.使用interrupt方法。在未阻塞的状态下调用interrupt,可以通过isInterrupt()的返回值来退出run。如果在阻塞情况下调用interrupt,就需要抛出异常,在catch里面break,推出run,由于阻塞情况下,interrupt会重置isInterrupt()为false,所以用isInterrupt()是无效的。

3.使用stop方法

Q:同步和非同步、阻塞和非阻塞的概念—

A:同步:一个任务的完成要依赖另一个任务的完成。(打电话,A打电话给B,只能等待B接通,这期间无法进行操作)

异步:一个任务的完成不需要等待另一个任务的完成。(发短信,A发短信给B,之后就可以自己干自己的事了)

阻塞:指一个线程在调用结果返回之前,线程会被挂起,它跟同步最大的区别就是同步的线程是激活的

非阻塞:同理,指一个线程在调用结果返回之前,如果结果不能立刻得到,这个函数不会阻塞线程,而是立即返回

Q:Thread的join()有什么作用?

A:父线程调用子线程的join方法后,父线程挂起,同时子线程继续运行,运行完毕会唤醒父线程。

Q:Thread的yield()有什么作用?

A:停止当前线程运行,让有更高优先级的线程有运行的机会。如果没有的话,yield方法不会起作用

Q:线程的有哪些状态?—

NEW新建状态,创建线程

RUNNABLE就绪/运行状态

BLOCKED阻塞状态,表示线程阻塞于锁

WAITING无限时等待状态,表示该线程在等待被唤醒

TIMED_WAIT有限时等待状态,表示该线程在等待被唤醒或等待超时后自行唤醒

TERMINATED销毁状态

Q:什么是线程安全?保障线程安全有哪些手段?

A:就是保证操作的可预见性。加锁。

Q:ReentrantLock和synchronized的区别?—

A:ReentrantLock可以手动释放锁,而synchronized不可以

Lock可以实现并发读,而synchronized不能

Lock可以知道获取锁的情况,而synchronized不能

Lock需要手动释放锁

Q:synchronized和volatile的区别?—

A:最根本的一点,synchronized能保证对变量的操作都是原子性,而volatile不能。其它:而volatile只是告诉线程,当前工作内存的缓存是无效的,需要去主存读取。synchronized则是让当前线程可以访问该变量,其它线程无法访问。还有synchronized能用在变量和方法,而volatile只能用在变量上。

Q:synchronized同步代码块还有同步方法本质上锁住的是谁?为什么?

A:锁住的是这个对象实例。

Q:sleep()和wait()的区别?—

A:sleep()线程沉睡,但是它不会释放锁。wait()线程释放锁,并等待重新获得锁。

sleep()可以在任何地方调用。而wait()只能在同步代码块或者同步方法内调用。

sleep()要抛出异常,而wait()不用

计算机网络

基础

Q:五层协议的体系结构分别是什么?每一层都有哪些协议?

A:应用层(HTTP、WWWW、DNS、FTP)

传输层(TCP、UDP)

网络层(IP)

网络访问层(ARP)

Q:为何有MAC地址还要IP地址?

A:举一个比较通俗的例子,我们要去一个地方旅游,知道了起始位置和终点位置,这样子肯定是到达不了终点的,我们还要知道沿途要经过的城镇,这样才能走到终点,所以制定路线需要起始位置和终点位置。

TCP

Q:TCP和UDP的区别?

A:TCP是一个可靠的连接,而UDP不可靠,它发送消息不需要确认建立联系(可能有误)

Q:拥塞控制和流量控制都是什么,两者的区别?

A:

Q:谈谈TCP为什么要三次握手?为什么要四次挥手?

A:举一个例子,当没有三次握手的情况下,客户端发送建立连接的请求,由于这个请求网络延迟,迟迟没有到达服务端,客户端没有收到消息,于是又发送了一个建立连接的请求。建立连接后,先前延迟的请求到了,服务端又为这个请求建立了连接。所以我们需要三次握手。四次挥手也是为了保证能正确断开连接。一次是客户端给服务端发送消息说明它不会再发送消息,服务端回复说了解。一次是服务给客户端端发送消息说它不会再发送数据,客户端回信说已经收到。这样做的目的是如果服务端还有数据没有发送完毕,为了确保这些数据能成功到达服务端,所以采取四次挥手。

Q:播放视频用TCP还是UDP?为什么?—

A:应当用UDP,因为视频播放应当是连续的,为了观影者的观看效果,如果采用TCP的话,丢包就需要重新发送,这在也就是要停止播放视频,等待重新发送的数据,这是不可接受的,观看视频时最重要的是实时体验,虽然使用UDP会丢包,但是保证了下面视频的实时性,总的来说视频播放更看重的是传输的性能,而不是传输的可靠性、完整性。

HTTP

Q:了解哪些响应状态码?—

A:1xx:表示服务端成功接收请求,客户端可以继续提出请求

2xx:表示服务端成功接受并处理了请求 例如:200

3xx:表示需要重定向

4xx:表示客户端请求错误 例如403:forbidden表示服务端拒绝接受请求 404:表示请求页面不存在

5xx:表示服务端错误 例如 500:Internal Service Error表示服务端出现错误,503 Service Unavailable表示服务端出现异常,等待一段时间后可能恢复。

Q:get和post的区别?—

A:get请求的参数需要拼接在url里面,受到url的长度限制

post则没有,它以key-value的方式存储在http请求数据里面

Q:Http1.0、Http1.1、Http2.0的区别?

A:HTTP1.0只有短连接,HTTP1.1增加了长连接,

Q:HTTP和TCP的区别?

A:

Q:HTTP和HTTPS的区别?

A:HTTPS即HTTP+SS/TLSL,对传输进行了算法加密。(具体的一知半懂)

Q:HTTP和Socket的区别?

A:

Q:在地址栏打入 http://www.baidu.com会发生什么?

A:电脑会向本地DNS服务器查询百度的IP,查不到就向上级DNS服务器查,最后都能查到。但是需要指出的是IP只知道出发地和目的地,它不知道具体的路程。途中会经过一个又一个的路由器,因此我们需要用路由器算法决定最短路径,而路由器之间怎么传递则是ARP的工作,它会得出下一个节点的MAC地址,节点节点相互连通,我们就可以建立TCP连接了,这时候我们就可以请求数据。

Q:说一下长连接的优点和缺点

A:优点:效率高,直接复用,而不用再握手。缺点就是占用服务端资源,一旦长连接过多,就容易不堪重负。

JVM

Q:JVM内存是如何划分的?—

A:Java栈,本地方法栈,程序计数器,方法区、堆

程序计数器:记录执行到那一条指令,它是线程私有的

Java栈:当要执行某一个方法时,就会创建一个Java栈

本地方法栈:跟Java栈相似,只不过Java栈对应的是java方法,而本地方法栈对应的是Native方法(本地方法)

堆:用来存储对象和数组

方法区:存储每个类的信息、静态变量、常量、编译后的代码

Q:谈谈垃圾回收机制?为什么引用计数器判定对象是否回收不可行?知道哪些垃圾回收算法?—

A:我们说的垃圾回收机制主要面向的是堆中,堆里面主要存储的是类的对象,当一个类的实例不再被引用的时候,它就应该被回收。引用计数器的原理是,当这个实例被引用一次,那么计数器加一,一旦有人不引用这个实例,那么计数器减一。计数器为0的对象都可以被垃圾回收。但是这里面有一个严重的缺陷,一旦有两个对象互相引用,这个机制就无法生效,它们的计数器不会为0。知道一下垃圾回收算法

1.标记清除算法

把需要回收的对象标记,然后直接清除,这样做的缺点是会产生很多内存碎片

2.标记整理算法

它是在标记清除算法的基础上,把存活的对象移到左端,这样就解决了内存碎片的问题

3.复制算法

它的实质就是把堆分成几个部分,对象面和空闲面,它主要的策略就是把存活对象交换到空闲面,清空对象面,这样空闲面就变成了对象面,对象面就变成了空闲面。

4.分代收集算法

它把堆分成了三个部分,新生代,老生代和永久代。在新生代中,主要进行的是复制算法,新生代里又分成了几个空间,一个elden代,两个survivor区。新对象在elden中生成,当elden中内存不足,就会把存活对象移到survivor0,接着清空elden,当survivor0也存放满了,就把elden和survivor0的存活对象移到survivor1,清空elden和survivor0的对象,让后交换survivor0和1交换。直到surviror1中无法存放来自elden和survivor0的对象,那么就把这些对象移到老生代。

老生代满了之后会触发full GC

持久代对回收没有多大影响

Q:Java中引用有几种类型?在Android中常用于什么情景?

A:

强引用,默认

软引用,内存不足时会回收它

弱引用,GC的时候回收它

虚引用,什么情况下都能被回收

Q:类加载的全过程是怎样的?什么是双亲委派模型?

A:

加载(class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象)

->验证(确保被加载的类的正确性)

->准备(为类的静态变量分配内存,并将其初始化为默认值)

->解析(把类中的符号引用转换为直接引用)符号引用就是一组符号来描述目标,可以是任何字面量。直接引用就是直接指向目标的指针

->初始化(初始化,为类的静态变量赋予正确的初始值)

启动类加载器 lib

扩展类加载器

应用程序类加载器

Q:工作内存和主内存的关系?在Java内存模型有哪些可以保证并发过程的原子性、可见性和有序性的措施?

A:主内存是所有线程共享的。每个线程都有自己的工作内存,工作内存都有一份对主内存变量的拷贝。线程对变量的修改不能再主内存中进行,而是在工作内存中进行人然后刷新到主内存,线程之间无法互相访问对方的工作内存。加锁

Q:JVM、Dalvik、ART的区别?—

A:JVM执行的是.class文件,而Dalvik执行的是,dex文件。

JAM是基于栈的,而Dalvik基于的是寄存器。

安卓5.0后使用的是ART,它与Dalvik最大的区别就是ART能在应用安装的时候就预编译,转化成机器语言,这样以后每次打开应用就是基于机器语言的。字节码转成机器码,占用空间会变大。由于预编译,所以程序每次打开都不用再重复编译了,对CPU的占用资源也就降低了,从用户的体验来说,就是应用更加省电。

Q:Java中堆和栈的区别?—

A:堆里面主要存储的是类的对象和数组。而栈主要是存储方法中产生的基本数据类型和对对象的引用

操作系统

Q:操作系统中进程和线程的区别?

A:进程包括线程,是一个1对多的关系。普通情况下,我们一个应用只有一个进程,进程内有多个线程

Q:死锁的产生和避免?—

A:死锁的原因是在锁里代码阻塞了,比如陷入了无限循环,无法释放锁,其它线程只能眼巴巴地等待这个线程释放锁

数据结构&算法

Q:怎么理解数据结构?

Q:什么是斐波那契数列?

Q:迭代和递归的特点,并比较优缺点

A:递归就是方法调用自己,直到返还结果,优点是代码清晰,用有限的语句来定义对象的无限集合,大问题化为小问题,可以极大的减少代码量,缺点是栈深度过大可能造成堆栈溢出

迭代就是效率高,运行时间只因循环次数增加而增加,缺点是不容易理解,编写复杂问题时困难,代码不如递归简洁

Q:了解哪些查找算法,时间复杂度都是多少?

Q:了解哪些排序算法,并比较一下,以及适用场景

Q:快排的基本思路是什么?最差的时间复杂度是多少?如何优化?

Q:AVL树插入或删除一个节点的过程是怎样的?

Q:什么是红黑树?

Q:100盏灯问题

Q:老鼠和毒药问题,加个条件,必须要求第二天出结果

Q:海量数据问题

Q:(手写算法)二分查找

Q:(手写算法)反转链表

Q:(手写算法)用两个栈实现队列

Q:(手写算法)多线程轮流打印问题

Q:(手写算法)如何判断一个链有环/两条链交叉

Q:(手写算法)快速从一组无序数中找到第k大的数/前k个大的数

Q:(手写算法)最长(不)重复子串

设计模式

Q:谈谈MVC、MVP和MVVM,好在哪里,不好在哪里?

Q:如何理解生产者消费者模型?

Q:是否能从Android中举几个例子说说用到了什么设计模式?

Q:装饰模式和代理模式有哪些区别?

Q:实现单例模式有几种方法?懒汉式中双层锁的目的是什么?两次判空的目的又是什么?—

A:饿汉式,懒汉式、懒汉式(线程安全)、双重校验锁、内部类、枚举(手写实现一遍)。第一次判空是确认没有实例,接着加锁,再判断没有实例。第二个判断主要原因是考虑到如果有两个线程同时通过了第一层检验,在第二层的时候,将会有一个线程进行了实例,另一个线程进行等待,如果没有第二层判空,那么第二个线程也将会再次实例。由于加锁的话效率挺低的,所以一旦有实例,获得实例就不应当加锁,这就是第一层判空的意义。

Q:谈谈了解的设计模式原则?

A:

单一职责原则:根据字面意思就可以得出,职责应当专一,举个简单的例子,MVP里面View就只负责显示界面

开放封闭原则:对于修改时封闭的,对于拓展是开放的。在更改一个类的功能时,应该更考虑通过继承达到要求。

里氏替换:子类替换父类不会产生问题,反之不行。实际应用就是子类与父类应当继承一个更广泛的接口

依赖倒转:通俗解释就是两个模块不应当直接依赖,应该尽量通过接口降低耦合,举个简单的例子,MVP里面的View持有的不是实例化的Present,而是Present接口

最少知识原则:通俗解释就是彼此之间的了解应该尽可能地低,两个模块之间的联系可以通过第三方转发,举个简单的例子,MVP里面View与Model之间不能直接发生联系,而是通过Present

接口隔离:接口应当细分,而不是建立一个庞大的接口。举个简单的例子,MVP里面的契约类

数据库

Q:数据库中的事务了解吗?事务的四大特性?

Q:如何理解数据库的范式?—

A:第一范式:每个字段不可拆分

第二范式:每个字段都要依赖主键

第三范式:每个字段都要直接依赖主键,间接依赖的另立成表

框架

Q:谈一下Retrofit的工作流程

A:创建Retrofit会相应的创建网络请求适配器工厂(默认和自己定义的),数据转换工厂(默认和自己定义的)。在创建网络请求接口的时候,会用代理相应地生成ServiceMethod,这个ServiceMethod包含了方法的所有信息,根据返回的返回值选择正确的网络请求适配工厂,数据转换工厂。最后执行的时候,会生成一个okhttp.call,交给okgttp执行,如果是同步的话就用数据转换工厂生成的数据转换器转换数据,最后返回值。如果是异步的话就同样转换数据,然后用网络适配器工厂生成的网络适配器切换线程。

Q:谈一下Okhttp的工作流程

A:创建请求Call,如果是异步的话就创建线程池处理请求。如果是同步的话就直接通过拦截器发送请求,然后HttpEngine发送请求,如果有缓存的话就取出缓存里的缓存数据返回。如果没有的话就进行网络请求,返回数据。

复用连接池,这个ThreadPool只有5个非核心线程,超时机制1分钟,在插入一个Socket连接的时候,会先清空空闲的连接,这里面的逻辑主要是用到了引用计数器,当计数器为0就可以认为是空闲连接,这里面会取出一个空闲时间最长的,如果这个时间超过滤超时时间,就把它清除。

不会的

Q:bitmap option中选择性加载图片(超长高清大图加载)

A:利用Bitmap.Option里的矩形解析,选择性加载,手指滑动的时候改变矩形的x,y,动态加载。

Q:GC中从根部连接,到底根部是什么

GC ROOT

Q:后台推送机制

Q:一张图片,两个控件加载,内存里有多少个图片副本

hr问题

Q:请简单的自我介绍一下

A:这是个好问题

Q:谈谈项目经历,为什么会做,怎么做的,遇到的难点?

A:这是个好问题

Q:谈谈实习经历,做了什么,收获有哪些?

A:这是个好问题

Q:谈谈学习Android的经历,有哪些学习方法和技巧?

A:这是个好问题

Q:是否会考研?/为何不保研?

A:这是个好问题

Q:成绩怎么样?奖学金情况?

A:这是个好问题

Q:学过哪些课程?那门课印象最深刻/最有意义/学的最好/最不喜欢?为什么?

A:这是个好问题

Q:近x年的职业规划?

A:这是个好问题

Q:为什么想来我们公司?/为何不转正留在xx?

A:这是个好问题

Q:对公司/部门是否有了解?

A:这是个好问题

Q:为何会选择做技术?/对女生做开发的看法?

A:这是个好问题

Q:学习生活中遇到什么挫折,如何解决的?

A:这是个好问题

Q:还投过那些公司,进展如何?如何xx和xx都给你发offer会如何选择?

A:这是个好问题

Q:家是哪里的?是独生子女吗?从小的家庭环境如何?

A:这是个好问题

Q:平常有哪些兴趣爱好?大学参加了哪些校园活动?

A:这是个好问题

Q:有男/女朋友吗?未来有什么规划?

A:这是个好问题

Q:评价一下自己的优缺点?/用x个词形容你自己。/别人都是怎样评价你的?

A:这是个好问题

Q:觉得自己博客写的最好的文章是什么?为什么?

A:这是个好问题

Q:觉得自己的优势是什么?

A:这是个好问题

Q:如何看待加班?

A:这是个好问题

Q:意向工作城市是哪?/是否会考虑在xx发展?

A:这是个好问题

Q:对于薪酬有什么想法?

A:这是个好问题

Q:有什么问题想要问我?

A:这是个好问题

原文  http://coderlengary.github.io/2018/09/19/Answer/
正文到此结束
Loading...