一.四大组件面试题:
四大组件都需要在AndroidManifest.xml文件中进行注册
1. Activity
1.1 Activity的启动流程和生命周期
onCreate–>(onRestart)–>onStart–>onResume–>onPause–>onStop–>onDestory
1.2 AppcompatActivity相对于Activity的主要的两点变化
(1)主界面带有toolbar的标题栏;
(2)theme主题只能用android:theme=”@style/AppTheme (appTheme主题或者其子类),而不能用android:style。 否则会提示错误: Caused by: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
1.3 onSaveInstance onRestoreInstance何时调用
当Activity发生意外,Activity会被销毁,其onPause,OnStop,onDestory函数均会被调用,系统会调用onSaveInstanceState来保存当前Activity状态。当Activity被重新创建后,系统会调用onRestoreInstanceState,并且把Actiivty销毁时onSaveInstanceState方法所保存的Bundle对象作为参数传递给onRestoreInstanceState和onCreate方法。
1.4 Activty的销毁是什么概念,ondestroy调用之后对象是否还存在
Activity.finish() :系统只是将最上面的Activity移出了栈,并没有及时的调用onDestory() 方法,其占用的资源也没有被及时释放。因为移出了栈,所以当你点击手机上面的“back”按键的时候,也不会找到这个Activity。
Activity.onDestory() : 系统销毁了这个Activity的实例在内存中占据的空间。对象被销毁,不存在了
System.exit(0) : 退出整个应用程序,是针对整个Application的。将整个进程直接KO掉。
1.5 一个Activity被非全屏窗口覆盖会走什么回调?被透明的activy覆盖会走什么回调?
Activity 被非全屏窗口覆盖,会失去焦点,处于暂停状态回调onPause()方法。在onPause()方法做一些数据存储,停止动火,暂停播放音视频等操作,不能太耗时,否则影响新 Activity显示。
当 Activity 被另一个透明或者 Dialog 样式的 Activity 覆盖时的状态,会执行onPause(),由于它依然与窗口管理器保持连接,系统继续维护其内部状态,所以它仍然可见,并不会执行onStop。
1.6 Activity的启动模式和种类,ActivityManager如何管理activity
standard:标准模式,每次启动都会重建一个新实例。用ApplicationContext启动这个模式的 Activity 会报错,因为非 Activity 类型的 Context并没有任务栈。解决这个问题的方法是指定一个标志位:FLAG_ACTIVITY_NEW_TASK,这样会创建一个新任务栈给这个 Activity。
singleTop:栈顶复用模式,如果 Activity 已经位于栈顶,此Activity 不会重建,会回调 onNewIntent方法,不调用 onCreate,onStart。(推送通知栏)
singleTask:栈内复用模式,只要一个栈中存在,此 Activity 就不会重建,和 singleTop一样会回调 onNewIntent方法。此模式具有 clearTop效果,使在其上面的 Activity全部出栈。(程序模块逻辑入口,WebView页面、扫一扫页面、电商中:购物界面,确认订单界面,付款界面)
singleInstance:单例模式,除了具有 singleTask 的所有特性,还独自占用一个任务栈。此种模式的Activity只能单独位于一个任务栈中。(系统Launcher、锁屏键、来电显示,闹铃)
动态设置启动模式:在startActivity(intent)里的intent里添加flags标记,
Intent intent = new Intent(this, B.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
2. BroadCastReceiver 广播
3. Android Service 服务
3.1 运行环境
Service和其他组件一样,都是运行在主线程中,因此不能用它来做耗时的请求或者动作。你可以在服务中开一个线程,在线程中做耗时动作。
3.2 IntentService
IntentService是Service类的子类,用来处理异步请求。客户端通过startService(Intent)方法传递请求给IntentService,在 IntentService 内有一个工作线程(HandlerThread)来处理耗时操作,启动 IntentService 的方式和启动传统 Service 一样,同时,当任务执行完后,IntentService 会自动停止,而不需要我们去手动控制。另外,可以启动 IntentService 多次,而每一个耗时操作会以工作队列的方式在IntentService 的 onHandleIntent 回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个
IntentService通过worker thread处理每个Intent对象,执行完所有工作后自动停止Service。
3.3 生命周期:
(1)单独使用startService():
onCreate()->onStartCommand()->Service running->onDestroy()->Service shut down
(2)单独使用bindService():
onCreate()->onBind()->Clients are bound to service->onUnbind()->onDestroy()->Service shut down
3.4 前台Service
例子:音乐播放。将一个服务设置为前台服务,只需要在绑定时调用startForeground
将自己设置为前台服务即可
@Override
public IBinder onBind(Intent intent) {
//设置为前台服务
Notification.Builder builder = new Notification.Builder(this);
builder.setContentTitle("播放音乐中..").setContentText("Diamonds").setWhen(System.currentTimeMillis()).setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
Notification notifation = builder.getNotification();
startForeground(2, notifation);
return mBinder;
}
@Override
public void onDestroy() {
super.onDestroy();
if (mediaPlayer != null)
mediaPlayer.release();
stopForeground(true);
}
3.5 对同一个service进行start和bind操作,生命周期和执行顺序
(1)startServic:调用onCreate()->onStartCommand()
(2)bindService:调用onBind()
(3)stopService:没有调用onDestory() Service仍然在运行!
(4)unbindService:调用onUnbind()->onDestory() 此时Service关闭!
若被停止的服务依然有ServiceConnection 与其绑定,则服务不能销毁,直至我们把所有ServiceConnection 解绑
4. ContentProvider
4.1 实现原理
通过Binder向其它应用提供数据。当ContentProvider所在的进程启动时,ContentProvider会同时启动并被发布到AMS中,需要特别注意的是ContentProvider的onCreate方法要早于Application的onCreate方法执行。
4.2 工作原理
当调用ContentProvider的insert、delete、update、query方法中的任何一个时,如果ContentProvider所在的进程没有启动的话,那么就会触发ContentProvider的创建,并伴随着ContentProvider所在进程的启动。
进程间通信的方式,其实它原理核心就是Binder。
Cursor cursor = ContentProvider.getContentResolver.query(final Uri uri,String[] projection, String selection, String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal)
- uri,指定查询某一个程序下的某一张表
- Uri uri = new Uri.parse("content://com.example.app.provider/table1");
- projection,指定查询的列名
- selection,指定查询条件,相当于sql语句中where后面的条件
- selectionArgs,给selection中的占位符提供具体的值
- orderBy,指定查询结果排序方式
- cancellationSignal,取消正在进行操作的信号量
之后遍历curser,一条条读取出来,
参与UploadToDrive和Share功能进行描述。
5. 通信
5.1 Activity 和 Service 之间的通信
(1)直接通过Intent进行传值,性能不高。intent会在onStartComment时候得到。是Activity传给Service
(2)(适用于bindservice)通过binder, service类里onbind 返回一个当前的service,然后Activity 启动 ServiceConnection,必须实现两个方法onServiceConnection(ComponentName,IBinder) 和 onServiceDisconnection。前者的IBinder就是service 里面onBind 的返回值,所以通过这个可以进行通信,二维码服务就是这样做的,这个相当于服务通知Activity消息。但是这个需要Activity每次去拿消息。
(3)(适用于bindservice)加接口,service 注册接口回调方法供外部使用,service中进度发生变化就调用接口里的抽象方法,由于Activity实现了这个接口(在onServiceConnected里面实现),所以发生变化就会改变。然后通过Handler告诉主线程发生了变化。这个做法是Service中进度发生变化主动通知Activity。
(4)通过broadcast(广播)
5.2 Android进程间的通信
(1)Activity可以跨进程调用其他应用程序的Activity;
(2)Broadcast可以向android系统中所有应用程序发送广播,
而需要跨进程通讯的应用程序可以监听这些广播;
(3)ContentProvider可以跨进程访问其他应用程序中的数据(以Cursor对象形式返回),
当然,也可以对其他应用程序的数据进行增、删、改操作;
(4)Service和Content Provider类似,也可以访问其他应用程序中的数据, 但不同的是,ContentProvider返回的是Cursor对象, 而Service返回的是Java对象,这种可以跨进程通讯的服务叫AIDL服务。
5.3 AIDL
两个进程无法直接进行通信,通过Android系统底层间接通信。
5.4 Binder机制
涉及到多进程间的通信底层都是依赖于Binder 机制。联系AIDL
使用Binder的原因
1.性能方面
(1)Binder相对出传统的Socket方式,更加高效。Binder数据拷贝只需要一次,而管道、消息队列、Socket都需要2次
2.安全方面
Binder机制从协议本身就支持对通信双方做身份校检,因而大大提升了安全性。
二. 消息处理
1. Intent方法 是否安全, 线程如何中断
提前验证是否有APP可以接受一个Intent,这样可以在发送Intent前,避免发送的Intent没有能够接收的APP,导致FC。
2. Android提供哪些异步相关的机制
两种常用的异步机制Thread+Handler与Async Task(联系UploadToDrive/WorkTask)机制;
2.1 二者的差异在什么地方,AsyncTask的优缺点是什么
(1)AsyncTask 提供了像onPreExecute, onProgressUpdate这类的快速调用方法,可以被UI线程方便的调用,Thread没有。
(2).AsyncTask 不能重复运行, 一旦执行过了,你需要下次需要时重新创建调用。 thread 可以创建成在队列中获取workitem持续调用的模式,不停地执行。
(3)AsyncTasks的执行优先级是3.0, 默认的执行模式是一次一个任务;thread的执行则与其它线程无关。
(4)AsyncTask 写起来较快, Thread则需要多做一些工作。
(5)AsyncTask 的线程池大小是
CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
3. AsyncTask,即异步任务
联系:UploadToDrive(GetUriFileTask)
耗时操作,只能放在子线程进行异步处理
.构建AsyncTask子类的泛型参数
AsyncTask<Params,Progress,Result>是一个抽象类,通常用于被继承.继承AsyncTask需要指定如下三个泛型参数:
Params:启动任务时输入的参数类型.
Progress:后台任务执行中返回进度值的类型.
Result:后台任务执行完成后返回结果的类型.
构建AsyncTask子类的回调方法
AsyncTask主要有如下几个方法:
onPreExecute:执行后台耗时操作前被调用,通常用于进行初始化操作.
doInBackground:必须重写,异步执行后台线程要完成的任务,耗时操作将在此方法中完成.
onPostExecute:当doInBackground方法完成后,系统将自动调用此方法,并将doInBackground方法返回的值传入此方法.通过此方法进行UI的更新.
onProgressUpdate:当在doInBackground方法中调用publishProgress方法更新任务执行进度后,将调用此方法.通过此方法我们可以知晓任务的完成进度.
Activity的context和 application的context的不同点在于,生命周期不同,this.getApplicationContext()取的是这个应用程序的Context,它的生命周期伴随应用程序的存在而存在;而Activity.this取的是当前Activity的Context,它的生命周期则只能存活于当前Activity,这两者的生命周期是不同的
4. Handler传递消息原理,如何引起内存泄露
主线程发送消息给子线程, 在主线程中实例化一个Handler,然后让他与子线程相关联(只要它与子线程的Looper相关联即可),这样子它处理的消息就是该子线程中的消息队列,而处理的逻辑都是在该子线程中执行的,不会占用主线程的时间。
当主线程中有耗时的操作时,需要在子线程中完成,通常我们就把这个逻辑放在HandlerThread的对象中执行(该对象就是一个子线程),然后在需要开始执行逻辑的地方发送一个Message来通知一下就可以了。
小结:
Handler与哪个线程的Looper相关联,那么它的消息处理逻辑就在与之相关的线程中执行,相应的消息的走向也就在相关联的MessageQueue中。(最常见的就是Handler与主线程关联,那么接收Looper回传的消息后的逻辑就会在主线程中执行)
当主线程中需要与子线程进行通信时(比如将耗时操作放在子线程中),建议使用HandlerThread。同时要注意,千万不要去重写它的run方法。
https://www.cnblogs.com/dendai-05/p/6945159.html
假设如果在一个Activity中,有多个线程去更新UI,并且都没有加锁机制,马么会产生生么样的问题?——更新界面混乱;
如果对更新UI 的操作都加锁处理的话会产生什么样子的问题?——性能下降
不用关心多线程的问题,更新UI的操作,都是在主线程的消息队列当中轮询处理的。
自己做的: driveRenameWorker和driveFavoriteWork 的task.run 改变为 taskmanager.executeTask(***Task),
run方法是直接返回最终结果,executeTask方法是实时的反馈进程的状态结果,方便Fragment对不同的状态进行不同的UI处理
5. HandlerThread、IntentService理解
三. 性能优化及问题处理
1 Android性能优化方式和内存优化方式
1.1 布局优化:
①(优先LinearLayout),删除布局中无用的控件和层次,其次有选择地使用性能比较低的ViewGroup。
②采用标签,标签,ViewStub,Include(例:布局重用等),ViewStub(例:逻辑不同加载不通界面等),Merge。
③避免过度绘制:屏幕上的某个像素在同一帧的时间内被绘制了多次
1.2 绘制优化:
①onDraw中不要创建新的局部对象。
②onDraw方法中不要做耗时的任务
1.3 内存泄露优化:
单例造成的内存泄漏
非静态内部类创建静态实例造成的内存泄漏
Handler造成的内存泄漏
线程造成的内存泄漏
资源未关闭造成的内存泄漏
1.4 响应速度优化:
避免在主线程中做耗时操作
1.5 ListView/RecycleView及Bitmap优化:
①使用ViewHolder模式来提高效率。
②异步加载:耗时的操作放在异步线程中。
③ListView/RecycleView的滑动时停止加载和分页加载
1.6 线程优化:
采用线程池,避免程序中存在大量的Thread。
1.7 其他性能优化建议:
①避免过度的创建对象
②不要过度使用枚举,枚举占用的内存空间要比整型大
③常量请使用static final来修饰
④使用一些Android特有的数据结构,比如SparseArray和Pair等
⑤适当采用软引用和弱引用
⑥采用内存缓存和磁盘缓存:内存缓存memory cash extend lru cash体现在Drive中是Thumbnail缩略图片,磁盘缓存data/data在Drive中体现在点击fileDetail查看图片,就会保存在data/data中
⑦尽量采用静态内部类,这样可以避免潜在的由于内部类而导致的内存泄漏。
2. ListView 怎样优化,优化ListView的绘制效率,降低view的联动层级
基本上用recycler进行代替优化,原理是recyclerView会在滑动的时候回收越界屏幕的内容,再次滑动时由于使用内存优化,然后不会很耗时的得到。而ListView不会回收
23. 自定义view
参考Drive的勇哥写的圆角自定义view,原理都是继承自基础的view,然后重写里面的onDraw方法
3. RecyclerView优化
4. 怎么分析丢帧失帧问题点
5. ANR 问题点的分析
activity view 5S,广播 10S,服务20S
6. 引起内存泄露的方式
7. 内存溢出(oom)和内存泄漏(leak)区别和关联,以及怎么优化
7.1 内存溢出 out of memory:(数组开的不够大)
是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;
导致:
(1)资源对象没关闭
①Cursor游标对象没有关闭;
②调用registerReceiver后未调用unregisterReceiver();(广播)
③未关闭InputStream/OutputStream;(未关闭数据流)
④Bitmap使用后未调用recycle()
(2)作用域不一样,导致对象不能被垃圾回收器回收,比如:
①非静态内部类会隐式地持有外部类的引用,
②Context泄露——概括一下,避免Context相关的内存泄露,记住以下事情:
i不要保留对Context-Activity长时间的引用(对Activity的引用的时候,必须确保拥有和Activity一样的生命周期)
ii尝试使用Context-Application来替代Context-Activity
iii如果你不想控制内部类的生命周期,应避免在Activity中使用非静态的内部类,而应该使用静态的内部类,并在其中创建一个对Activity的弱引用。
③Thread 引用其他对象也容易出现对象泄露。
④onReceive方法里执行了太多的操作
(3)内存压力过大—最直接:
①图片资源加载过多,超过内存使用空间,例如Bitmap 的使用,bitmap分辨率越高,所占用的内存就越大,这个是以2为指数级增长的;参考当时超哥的16M照片太大,导致内存溢出,主要是由于这个图片在生成bitmap的时候内存过大,解决方式是在decode之前把图片做小
②重复创建view,listview应该使用convertview和viewholder,ListView相关的知识点有两个:1)ListView的实现;2)ListView的效率优化,其中第二点对于开发者在使用ListView时是需要重点关注的,《第一行代码》中有相关介绍。
7.2 避免内存溢出(OOM)的常用方法总结
(1)资源文件需要选择合适的文件夹进行存放;资源文件放在适合的xxdpi文件夹下
(2)优化布局层次,越扁平化的视图布局,占用的内存就越少,效率越高;
(3)减小Bitmap对象的内存占用;
(4)使用更小的图片,是否存在可以压缩的空间,是否可以使用一张更小的图片;
(5)复用系统自带的资源,比如字符串/颜色/图片/动画/样式以及简单布局等等,这些资源都可以在应用程序中直接引用;
(6)注意在ListView/GridView等出现大量重复子组件的视图里面对ConvertView的复用;
(7)类似onDraw等频繁调用的方法,一定需要注意避免在这里做创建对象的操作,因为他会迅速增加内存的使用,而且很容易引起频繁的gc,甚至是内存抖动;
(8)在有些时候,代码中会需要使用到大量的字符串拼接的操作,这种时候有必要考虑使用StringBuilder来替代频繁的“+”;
(9)考虑使用Application Context而不是Activity Context
7.3 内存泄露 memory leak:
(没有关闭流,没有remove线程池,没有回收资源)
是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
注:一个程序中,已经不需要使用某个对象,但是因为仍然有引用指向它,垃圾回收器就无法回收它,当该对象占用的内存无法被回收时,就容易造成内存泄露。多个内存泄漏最终会导致内存溢出,即OOM。memory
leak会最终会导致out of memory!
handler引起的内存泄露是,当activity finish掉之后,消息仍然会在主线程存在8S,因为消息引用了主线程的handler,所以应该销毁的activity并不会销毁,
解决方法是使用弱引用 ,和handler使用静态内部类,runnable写成静态内部类,在ondestory中移除所有的callback和message
匿名AsyncTask 引起的泄露是由于它本身会持有外部的类对象,也就是activity,所以当activity销毁后,这个线程继续持有这个activity的引用,所以activity不会被销毁,直到线程执行完成。解决方法是自定义静态的AsyncTask类,还有保持AsyncTask与activity的生命周期同步,在antivitg 结束时,把AsyncTask销毁掉。
其他:
-
写一个notification的实例
-
堆存放new(有回收机制),栈存放变量,静态区存放static
-
Android中数据存储方式有哪些,使用场合是什么?
1 使用SharedPreferences存储数据:保存少量的数据,且这些数据的格式非常简单:字符串型、基本类型的值。
SharedPreferences有两种提交方式:
(1)editor.commit();
(2) editor.apply();
区别:(1)commit()返回boolean值验证是否提交成功 ;apply()第二种没有返回值
(2)commit()同步提交硬盘,容易造成线程堵塞;apply()先提交到内存,然后异步提交到磁盘
2 文件存储数据: Context提供了两个方法来打开数据文件里的文件IO流 FileInputStream openFileInput(String name); FileOutputStream(String name , int mode),这两个方法第一个参数 用于指定文件名,第二个参数指定打开文件的模式。
3 SQLite数据库存储数据:SQLite是轻量级嵌入式数据库
4 使用ContentProvider存储数据
5 网络存储数据 -
View的绘制流程,具体到方法如何实现
measure(int ,int) :测量View的大小
layout(int ,int ,int ,int) :设置子View的位置
draw(Canvas) :绘制View内容到Canvas画布上 -
动画
触摸反馈动画(Ripple Effect),(联系波浪效果,drawable文件夹中定义ripple节点).
参考recent–upload–download -
EventBus的实现原理
8.OKHttp
9.Fresco的使用
10.Android input事件的分发 -
如何实现下拉刷新
参考Drive中的 reload,在initView中的onRefresh判断调用reload
12.用户态和内核态的区别
13.软引用和弱引用的区别
- 面试
12.22 天津面试经历
- 动画
- app优化
- 有没有独立开发app的经验
- handler机制
12.27 北京面试经历:
9. jdk1.7和jdk1.8区别
1.8中Switch语句支持string类型
Try-with-resource语句
hashmap在1.8之后的冲突达到8之后,采用红黑树结构
-
如果在静态方法中开启一个线程,等到静态方法运行结束后,这个线程会不会销毁?
-
用什么解析xml
1、DOM解析;2、SAX解析;3、JDOM解析;4、DOM4J解析。
其中前两种属于基础方法,是官方提供的平台无关的解析方式;后两种属于扩展方法,它们是在基础的方法上扩展出来的,只适用于java平台。 -
如何分享
12.28 面试经历
1.ANR问题的产生和如何解决,包括看什么log,
其他人面试经历:
1.oncreate中,开启三个线程,1.普通handler,2.UImain runnable 3. view runnable
-
hashmap, arraylist,linklist 他们的查找 和 修改数据 的时间复杂度分别是多少?
-
讲解一下GC垃圾回收机制
-
ANR问题,如果我在一个thread线程里面开启一个服务,会导致ANR问题吗?
-
内存泄漏以及如何处理它?
-
Activity的启动流程
-
activity的启动模式, 默认情况下,按一下开启activtyA->B->C->D>C,当按返回键,显示的页面是哪一个?如果我想直接返回到B,如何设置?
-
事件分发机制,问的比较深入
-
view的绘制过程(主要的三个方法),如何绘制一个空心圆?
-
service有哪几种以及各自的大致使用
startservice 和 bindservice -
广播的使用以及种类?
发出:有序(可拦截可修改),无序(不可拦截,不可修改),本地(app内部传播localbroadcastManager.sendBroadcast)
接受:动态(新建一个类,继承BroadcastReceiver),静态(在AndroidManifest中注册) -
线程与进程的区别?
-
线程池
ThreadPoolExecutor,
什么时候使用线程池?
单个任务处理时间比较短
需要处理的任务数量很大
联系到Drive上就是每个Worker对应一个DriveTaskManager ,使用饿汉的单例模式来进行获取,做多五个线程。 -
跨进程通信的方式?
-
AIDL
-
Handler消息机制的原理
-
thread和runnable的区别
Thread,则不适合资源共享。
Runable,则很容易的实现资源共享。 -
开启线程的三种方式
所有的线程对象都必须是Thread类或其子类的实例。
继承Thread ,重写run,并且使用.start()方法
实现runnable ,重写run,并且使用.start()方法
使用Callable和Future创建线程 -
Activity 中用一个button开启自身的Activity,生命周期有什么变化
-
Service如果频繁启动一个Service,生命周期是怎样
-
Service 和Activity之间如何传递数据,如何实时监听Service数据变化
-
synchronized相关,两个函数都加synchronized,是否互相影响
-
ListView RecyclerView 如何加载不一样的item布局,哪个函数式绑定布局,哪个函数式绑定数据
-
怎么处理Crash问题
-
动画,自定义动画
-
怎么确定looper是哪个线程的
-
点击物理屏幕到响应的流程
-
binder底层实现
-
文件的权限使用
-
前台服务和后端服务的区别
-
Activity启动模式的用途
-
Binder的原理和底层实现
-
抽象类和接口的区别
接口:默认 方法属性public abstract,变量public static final,
抽象类:都可以(除了private)
类可以不实现抽象类和接口中的所有方法,但是这样的话,类必须声明是抽象的
都不可以被实例化
小米安全团队:
一轮:(2h)
-
算法:手写链表反转
描述思路
N1->N2->N3->N4public static Node reverse2(Node head) { if (head == null) return head; Node pre = head;// 上一结点 Node cur = head.getNext();// 当前结点 Node tmp;// 临时结点,用于保存当前结点的指针域(即下一结点) while (cur != null) {// 当前结点为null,说明位于尾结点 tmp = cur.getNext(); cur.setNext(pre);// 反转指针域的指向 // 指针往下移动 pre = cur; cur = tmp; // 最后将原链表的头节点的指针域置为null,还回新链表的头结点,即原链表的尾结点 head.setNext(null); return pre; }
-
Activity生命周期+Fragment生命周期
打开ActivityA并加载FragmentA(包含一个Button用来启动ActivityB),描述生命周期
打开ActivityB并加载FragmentB,描述生命周期。
返回到手机主界面,描述生命周期。
简述四种启动模式 -
Handler:描述handler工作机制
3.1. 为什么Looper和MessageQueue只有一个:Looper有两个关键的放perpare(),loop()方法,在prepare方法会创建一个Looper对象,然后保存在ThreadLocal中,该方法只能被调用一次,否则会抛出异常,这样保证了一个线程只有一个looper,Looper构造器中创建MessageQueue对象。所以只有一个looper和MessageQueue
3.2. 什么是ThreadLocal,源码怎么保证上述两个变量只有一个。
ThreadLocal:Thread–>ThreadLocal–>ThreadlocalMap(key , value)- Thread类中有一个成员变量属于ThreadLocalMap类(一个定义在ThreadLocal类中的内部类),它是一个Map,他的key是ThreadLocal实例对象。
- 当为ThreadLocal类的对象set值时,首先获得当前线程的ThreadLocalMap类属性,然后以ThreadLocal类的对象为key,设定value。get值时则类似。
- ThreadLocal变量的活动范围为某线程,是该线程“专有的,独自霸占”的,对该变量的所有操作均由该线程完成!也就是说,ThreadLocal 不是用来解决共享对象的多线程访问的竞争问题的,因为ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的。当线程终止后,这些值会作为垃圾回收。
- 由ThreadLocal的工作原理决定了:每个线程独自拥有一个变量,并非是共享的
- ThreadLocal的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用。作用:提供一个线程内公共变量(比如本次请求的用户信息),减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度,或者为线程提供一个私有的变量副本,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException(“Only one Looper may be created per thread”);
}
sThreadLocal.set(new Looper(true));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mRun = true;
mThread = Thread.currentThread();
}3.3 Looper一直在循环MessageQueue,没有消息时为什么不会造成主线程ANR?
因为Android 的是由事件驱动的,looper.loop() 不断地接收事件、处理事件,每一个点击触摸或者说Activity的生命周期都是运行在 Looper.loop() 的控制之下,如果它停止了,应用也就停止了。只能是某一个消息或者说对消息的处理阻塞了 Looper.loop(),而不是 Looper.loop() 阻塞它。用汽车举例,发动机就是looper,他在不断地运行,只能说有人阻止了他的运行,而不是他阻止别的行为进行。3.4 子线程中如何创建handler,为什么要加Looper.prepare。为什么主线程不用?
主线程的在ActivityThread中的main方法中已经Looper.prepareMainLooper和.loop了
3.5 造成内存泄漏的原因?解决。
handler 要用static 修饰, 隐性匿名类Handler变成static的内部类,由于static的内部类,使用的使用不需要外部类的实例,所以static的内部类和外部类是没有联系的,从而不持有外部类的引用,通过这种方法,我们可以避免内存泄露情况的发生。
handler 里面的外部引用要用弱引用
弱引用的写法:WeakReference <Image> imageWeak; imageWeak = new WeakReference <>(传来的Image);
-
进程间通信的方式有哪些?
-
简述Binder机制,binder机制的优点,binder机制的实现流程。什么是UID/PID?
-
AIDL原理,如何自己实现AIDL?
-
OKHttp在使用中遇到的坑。为什么选择OkHttp?
-
ListView优化方案,多种。RecylerView对比ListView的优点。
ViewHolder模式提高效率, -
简述HashMap的原理
-
简述BootLoader启动流程,简述secureBoot校验过程,对TrustZone框架的理解。
-
Android 4.4 到5.0 什么区别
-
输入字符串,判断是否是IP地址
-
各种数据存储的安全性
-
View,activity ,window
-
ArrayList,LinkedList; ArrayMap,HashMap,HashTable,
二轮:(40min)
+算法
-
自定义View相关
-
CANCLE事件应用场景
-
List和Map是否线程安全,别的集合哪些是线程安全的,如果非用这两种,如何做到线程安全。
实现线程安全,加锁,//List 加锁 假如你创建的代码如下:
List<Map<String,Object>> data=new ArrayList<Map<String,Object>>();//那么为了解决这个线程安全问题你可以这么使用Collections.synchronizedList(),如:
List<Map<String,Object>> data=Collections.synchronizedList(new ArrayList<Map<String,Object>>());//Map 加锁
synchronized(anObject){
value = map.get(key);
} -
什么是内存泄漏,handler造成的原因以及解决办法,什么是弱引用,软引用
-
进行线程同步的方式有哪些?
为何要使用同步?
java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查),
将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用,
从而保证了该变量的唯一性和准确性。- 同步方法
即有synchronized关键字修饰的方法。 - 同步代码块
即有synchronized关键字修饰的语句块。 - 使用特殊域变量(volatile)实现线程同步
private volatile int account = 100;
- 同步方法
三轮:(1h)
- 算法
- 描述项目
- 单例模式 双重校验锁
- ListView优化
- 在底层都做了哪些工作
- Flowlayout怎么实现的
- 有没有实现过自定义控件
- 有没有解决过滑动冲突
ScrollView中嵌套了ListView
1.使用LinearLayout取代ListView
2.自定义可适应ScrollView的ListView,通过重写其onMeasure方法 - 平时怎么解决项目中的难题。
四轮:(30min)
1.聊天
2.底层遇到的安全机制
小米商城:
笔试+面试 挂
1.一个线程中Handler和MessageQueue的数量分别是
2.View优化
3.Java Exception
4.93&-10
5.考察 子类和父类 以及内部类 静态内部类 构造方法的调用先后顺序(new 一个子类)
6.Activity的四种启动模式 应用场景
7.内存泄漏的方式 解决 考察了代码
8.手写android中包含Context的单例模式
9.二叉树遍历(不写代码) 前序+中序 给出前序和中序 如何得到树
10.手写双重校验锁的单例模式 解释原理 什么情况下会单例失败
没有用volatile
现在我们分析一下为什么要在变量singleton之间加上volatile关键字。要理解这个问题,先要了解对象的构造过程,实例化一个对象其实可以分为三个步骤:
(1)分配内存空间。
(2)初始化对象。
(3)将内存空间的地址赋值给对应的引用。
但是由于操作系统可以对指令进行重排序,所以上面的过程也可能会变成如下过程:
(1)分配内存空间。
(2)将内存空间的地址赋值给对应的引用。
(3)初始化对象
11.JVM的内存机制
12.多线程的几种状态 sleep和wait 阻塞状态和可执行状态 notify会不会立即释放锁
13.给一段代码 找出内存泄漏的地方
14.什么是ANR 造成ANR的方式 Looper.loop为什么不会造成ANR
15.算法,给出一串数字,输出连续数列的最大长度 1 2 3 4 6 8 100 200 返回4
16.MessageQueue是阻塞队列吗?你知道有哪些阻塞队列吗?
1.23 小米面试
-
onDestory里面都进行了什么回收操作
-
Looper怎么确定的把消息发给哪一个handler
-
动态广播怎么设置,有序广播怎么拦截不再下发
-
除了四大组件的跨进程通信,还有吗?
-
为什么要用AsyncTask,AsyncTask的优点
-
除了普通 service和IntentService,你还知道什么Service,不包括自定义的。
-
Android N,O,P上面service是不同的,有什么不同
-
xml和json的区别
-
Activity的启动流程,Activity1启动Activity2 调用startActivity(Activity2),他是怎么走的
-
hashmap是具体是怎么实现的
-
hashtable为什么线程安全,我回答的是加锁了,他又问怎么加的锁
-
视图,A嵌套B,B嵌套C,B,C都可滑动,滑动最里面的C,划到边界,B,C怎么动
-
做过什么优化
-
Binder
-
算法题:输入是一个字符串,大小写错乱,空格错乱
例如“tHis iS my FRIEND JaCk ”
要求输出规则,基数字符的首字母大写,剩下全部小写,各个字符之间只能有一个空格,首尾没有空格。时间复杂度要求O1(他也说了空间复杂度,我忘记了。总感觉时间复杂度O1实现不了)
例如“This is My friend Jack” -
本地广播和全局广播有什么区别
-
IntentService,作用是什么
-
AIDL 解决了什么问题
-
Activity Window View 三者差别,
-
fragment生命周期,有什么特点
-
描述一次网络请求流程
-
Handler HandlerThread Thread 差别
-
低版本SDK 实现高版本api
-
launch mode 应用场景
-
touch事件传递机制
-
view绘制流程
-
什么情况导致内存泄露
-
ADR定位和修正
-
什么情况导致OOM
-
如何保证一个后台服务不被杀死,比较省电的方式是什么
-
RequestLayout,onLayout,onDraw,DrawChild区别和联系
-
Invalidate和postInvalidate区别和使用
-
Android 动画实现原理
-
Android为每个应用程序分配的内存大小是多少
-
View刷新机制
-
LinearLayout和RelativeLayout对比
-
优化自定义view
-
volley
-
Android属性动特性
-
Handler机制及底层实现
-
Binder机制及底层实现
-
异步
-
网络,网络架构
-
json解析
-
架构:MVC,MVP,MVVM
字节跳动面试
volatile 关键字
开启三个线程,输出1A,2B,3C,1D,2E…
反转链表
时间复杂度
谷歌图片加载,缓存
String StringBuffer,StringBuilder
View的生命周期,回调方法
单例模式,有几种,懒汉饿汉已经回答了
另一个面试
sharedpreferenced 提交方式与区别
pause 和 stop的区别:只pause 失去焦点,activity仍热继续,有滑动仍然会滑动;stop是暂停,activity暂停状态
断点续传的实现原理
android源码中,那些用到了观察者模式
RecyclerView和ListView的区别,为什么要用RecyclerView
教育机构面试:
OKHttp,网络图片下载,缓存,图片压缩方法,适配方法,缓存方法
MVP架构
Handler,消息怎么发送到handleMessage的,子线程创建handler
hashmap
自定义View
service两种方式的区别
startservice开启后跟调用者无关,bindservice随着绑定着共存亡
IntentService 特点
广播的实现
本地广播和全局广播的实现区别
处理滑动异常:
ScrollView嵌套ListView显式问题:
处理方法
1.通过Activity计算item的高度,重新布局
2.自定义listView,重写onMeasure方法
滑动问题:
原因:listview显式不全,
注意点1.一次完全触摸事件全部在listView覆盖范围,
2.设置父控件不拦截,getParent().requestDisallInterceptRouchEvent(true)
该方法是子控件命令父控件是否拦截的
处理方法:
1.设置setOnTouchListener(),监听到ACTION_UP事件时请求父控件不拦截
2.自定义ListView,重写分发拦截