面试复习:
來源:
https://blog.csdn.net/qq_30379689/article/details/73698192#activity%E9%9D%A2%E8%AF%95%E9%A2%98
https://www.jianshu.com/p/6bace0b3761a
https://hit-alibaba.github.io/interview/basic/algo/Greedy.html
https://www.jianshu.com/p/a0db5e588506
需修:
7-4,12-3,
目錄:
1. Activity
2.Service
3.Broadcast Receiver
4.Content Provider
5.Fragment
6.Binder
7.Handler
8. AsyncTask
9. HandlerThread
10. 视图工作机制
11.事件分发机制
12. ListView
13.Android项目构建面试题
14.ANR面试题
15. OOM (out of memory)
16. kotlin
17. 注解
-------------------------------------
1.Activity
1-1Activity主要的四种状态:
Running(运行):在屏幕前台(位于当前任务堆栈的顶部)
* onCreate() ->onStart() -> onResume()。
Paused(暂停):失去焦点但仍然对用户可见(覆盖Activity可能是透明或未完全遮挡)
*运行状态 到 暂停状态:onResume() -> onPuased()。
*暂停状态 到 运行状态: onPuased()->onResume()。
Stopped(停止):完全被另一个Activity覆盖
*暂停状态 到 停止状态 触发的函数及顺序为:onPuased() -> onStop()。
*停止状态 恢复至 运行状态 所触发的函数及顺序为:onStop() -> onRestart() -> onStart() -> onResume()。
Destroyed(销毁):退出,完全销毁.
*停止状态到死亡状态分为两种情况:(1)由用户操作导致,则执行:onStop() -> onDestroy()。(2)由系统自动强制执行,则该Activity被强行结束。
1-2 Activity生命周期
- onCreate()
- onRestart()(stop恢復時)
- onStart()
- onResume()
- onPause()
- onStop()
- onDestroy()
onStart()是当Activity正在变为可见状态时才会被调用。一般地在此期间可以注册一个广播等等。
onPuased()是当一个Activity 失去系统焦点 后将会被调用.
onStop()是当一个Activity变为不可见时将会被调用
onDestroy()是当一个Activity正在被系统finished期间被调用的。
1-3.Activity切换横屏时生命周期
- onSaveInstanceState() (沒?)
- onPause()
- onStop()
- onDestroy()
- onCreate()
- onStart()
- onRestoreInstanceState()
- onResume()
把该Activity添加
android:configChanges="orientation",
1-4. 进程的优先级
沒用過,
oom_adj是linux内核分配给每个系统进程的一个值.
1-5. Activity启动模式 (Intent)
- standard
- singletop
- singletask
- singleinstance
android:name=".SingleTopActivity"
android:label="@string/singletop"
android:launchMode="singleTop" >
</activity>
1-6. scheme跳转协议
沒用過
1-7.Context、Activity、Application之间有什么区别
- ContextImpl:實作 Context
- ContextWrapper:包裝、封裝,且初始化過程會創建ContextImpl實作Context
- ContextThemeWrapper:Activity 需要主題
- Service, Application:不需要主題,因為不需要介面,完全在背景處理

- 看的見的:Dialog,Activity等,就必須要用Activity的Context
- 看不見的:調用getString或getResource方法獲取res文件夾下的資源時,所有的Context對像都可以使用
https://spicyboyd.blogspot.com/2018/04/appcontext.html
取Context 方法
*View.getContext()
=>返回當前View對象的Context對象
*this 或 Activity.this
=>返回當前的Activity
*Activity.getApplicationContext()
=>app 的context
*ContextWrapper.getBaseContext()
=>獲取一個ContextWrapper進行裝飾之前的Context
總結:

虽然Activity和Application都是Context的子类,但是他们维护的生命周期不一样.
前者维护一个Acitivity的生命周期,所以其对应的Context也只能访问该activity内的各种资源。
后者则是维护一个Application的生命周期(整個app).
1-8.Activity启动过程
*startActivity(intent);
*startActivityForResult()。由于startActivityForResult()是有返回结果的.
setResult(RESULT_OK, gobackIntent).// class B
startActivityForResult(intent, EDIT);//class A
//class A
protected void onActivityResult(int requestCode, int resultCode, Intent data){.... }
-------------以下沒用過-----
*scheduleLaunchActivity
*handleLaunchActivity
Else:
四大元件:
Activity
Broadcast Receiver
Service
Content Provider
2.Service
Service是四大组件之一,可以在 后台执行 长时间 运行操作 而 没有用户界面 的应用组件.
1-2、Service和Thread的区别
Service 运行在 独立进程 的主线程中,不可以执行耗时操作。
Thread是 程序执行的最小单元,分配CPU的基本单位,开启 子线程执行 耗时操作.
1-3.Service启动方式
- startService (以下生命週期)
- onCreate()
- onStartCommand()
- onDestroy()
- bindService(以下生命週期)
- onCreate()
- onBind()
- onUnbind()
- onDestroy()

1-4. example
後台播放音樂、定時檢查更新資料. or 接收boardcastReceiver
推波?
AndroidManifest.xml
< service android:name = "com.example.serviceTest.MyService"></ service >
3. Broadcast Receiver
Broadcast是四大组件之一,广泛运用在 应用程序之间 传输信息的机制,通过发送Intent来传送我们的数据.
3-2.Broadcast Receiver的使用场景
- 同一App具有多个进程的不同组件之间的消息通信
- 不同App之间的组件之间的消息通信
3-3Broadcast Receiver的种类
- 普通广播
- 有序广播
- 本地广播
- Sticky广播
- 静态注册:注册后一直运行,尽管Activity、进程、App被杀死还是可以接收到广播
- 动态注册:跟随Activity的生命周期
example:
BroadcastReceiver mWifiScanReceiver = new BroadcastReceiver()
{ @Overridepublic void onReceive(Context c, Intent intent) { if (intent.getAction().equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { List<ScanResult> mScanResults = mWifi.getScanResults();String ConnectingWifi = mWifi.getConnectionInfo().getSSID(); for(int i = 0; i<mScanResults.size(); i++) { if(!("\""+mScanResults.get(i).SSID+"\"").equals(ConnectingWifi)) WifiList.add(mScanResults.get(i).SSID); } spinnerArrayAdapter.notifyDataSetChanged(); } } };
4.Content Provider
內容提供者,通過Binder向其他元件以及其他應用提供資料.
AndroidManifest.xml
<provider
android:name=".MyContentProvider"
android:authorities="com.xxxx.xxx.MyContentProvider" //唯一標識,通過它外部應用訪問MyContentProvider
android:exported="true" // 屬性用於指示該服務是否能夠被其他應用程式元件呼叫或跟它互動。如果設定為true,則能夠被呼叫或互動,否則不能
android:multiprocess="true" //為true時:多例項 false:單例項
/>
*contentProvider 實作public class MyContentProvider extents ContentProvider{
/*
* 建立時被呼叫
*/
@Override
public boolean onCreate(){
return false;
}
/*
* 根據Uri查詢符合selection條件的全部記錄,projection是一個列名列表,選擇出指定的資料列,有點sql的select的意思
*/
@Override
public Cursor query(Uri uri,String[] project,String selection,String[] selectionArgs,String sortOrder){
//一般使用SQLiteDatabase進行資料的增刪查改
return null;
}
/*
* 返回Uri查詢出的selection條件的資料的MIME型別
*/
@Override
public String getType(Uri uri){
//當對應多條記錄時 以vnd.android.cursor.dir/開頭
//當對應單條記錄時 以vnd.android.cursor.item/開頭
return null;
}
/*
* 根據Uri插入對應的value的資料
*/
@Override
public Uri insert(Uri uri,ContentValues values){
return null;
}
/*
* 根據Uri刪除selection匹配的記錄
*/
@Override
public int delete(Uri uri,String selection,String[] selectionArgs){
return 0;
}
/*
* 根據Uri修改selection匹配的記錄
*/
@Override
public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs){
return 0;
}
}
contentProvider的作用是用來暴露資料,而ContentResolver就是用來操作資料.
//將內容字串解析成Uri物件
Uri uri = Uri.parse("content://com.xxx.xxx.myContentProvider/hello");
Cursor cursor = getContentResolver().query(uri,project,selection,selectionArgs,sortOrder);
https://www.itread01.com/content/1544722235.html
****code中沒用
5.Fragment
定义可知:Fragment比Activity更节省内存,且有自己的生命周期,而且必须依附于Activity.
5-1、Fragment为什么被称为第五大组件
Fragment比Activity更节省内存,其切换模式也更加舒适.
5-2、Activity创建Fragment的方式
6.Binder
6-1.Linux内核的基本知识
*系统调用:Linux内核对应用有访问权限,用户只能在应用层通过系统调用,调用内核的某些程序
*binder驱动:它负责各个用户的进程,通过binder通信内核来进行交互的模块
6-2.为什么使用Binder
- 性能上,相比传统的Socket更加高效
- 安全性高,支持协议双方互相校验
my code not use. 底層?
---------------以下為詳細----
http://gityuan.com/2016/09/04/binder-start-service/
Android内核是基于Linux系统, 而Linux现存多种进程间IPC方式: 管道, 消息队列, 共享内存, 套接字.
从我个人的理解角度, 曾尝试着在知乎回答同样一个问题 为什么Android要采用Binder作为IPC机制?.
類似TCP 五層架構,这样分层设计的思想, 让每一个子问题都设计成一个独立的协议,
Binder架构也是采用分层架构设计, 每一层都有其不同的功能:
- Java应用层: 对于上层应用通过调用 AMP.startService, 完全可以不用关心底层,经过层层调用,最终必然会调用到AMS.startService.
- Java IPC层: Binder通信是采用C/S架构, Android系统的 基础架构 便已设计好Binder在Java framework层的Binder客户类BinderProxy和服务类Binder;
- Native IPC层: 对于Native层,如果需要直接使用Binder(比如media相关), 则可以直接使用BpBinder和BBinder(当然这里还有JavaBBinder)即可, 对于上一层Java IPC的通信也是基于这个层面.
- Kernel物理层: 这里是Binder Driver, 前面3层都跑在用户空间,对于用户空间的内存资源是不共享的,每个Android的进程只能运行在自己进程所拥有的虚拟地址空间, 而内核空间却是可共享的. 真正通信的核心环节还是在Binder Driver.
以startService流程分析为例子 来说说Binder所其作用. 首先在 发起方进程调用AMP.startService,经过binder驱动,最终调用系统进程AMS.startService,如下图:
AMP和AMN都是实现了IActivityManager接口,AMS继承于AMN. 其中AMP作为Binder的客户端,运行在各个app所在进程, AMN(或AMS)运行在系统进程system_server.
7.Handler
7-1、Handler是什么
Handler通过发送 和 处理Message 和Runnable对象 来 关联相对应 线程的MessageQueue
7-2、Handler使用方法
- post(runnable)
- sendMessage(message)
7-3、Handler工作原理
7-4、Handler引起的内存泄漏
- 原因:非静态内部类 持有 外部类 的匿名引用,导致Activity无法释放
- 解决:
- Handler内部持有外部Activity的弱引用
- Handler改为静态内部类
- Handler.removeCallback()
private final Handler mLeakyHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// ...
}
};
Handler class 具有隱式引用.該引用將一直持續到消息被處理為止,從而防止了 活動上下文(context) 被垃圾回收並洩漏了所有應用程序資源。
解決:
要解決此問題,請
Handler在新文件中將其 子類化,或改用靜態內部類 private static class MyHandler extends Handler {
private final WeakReference<SampleActivity> mActivity;
public MyHandler(SampleActivity activity) {
mActivity = new WeakReference<SampleActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
SampleActivity activity = mActivity.get();
if (activity != null) {
// ...
}
}
}
8. AsyncTask
private class GetImage extends AsyncTask<String , Integer , Bitmap>{
@Override
protected void onPreExecute() {
//執行前 設定可以在這邊設定
super.onPreExecute();
}
@Override
protected Bitmap doInBackground(String... params) {
//執行中 在背景做事情
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
//執行中 可以在這邊告知使用者進度
super.onProgressUpdate(values);
}
@Override
protected void onPostExecute(Bitmap bitmap) {
//執行後 完成背景任務
super.onPostExecute(bitmap);
}
}
9. HandlerThread
2、HanlderThread的特点、
*HandlerThread本质上是一个线程,继承自Thread
*HandlerThread有自己的Looper对象,可以进行Looper循环,可以创建Handler
*HandlerThread可以在Handler的handlerMessage中执行异步方法
*HandlerThread优点是异步不会堵塞,减少对性能的消耗
*HandlerThread缺点是不能同时继续进行多任务处理,需要等待进行处理,处理效率较低
*HandlerThread与线程池不同,HandlerThread是一个串行队列,背后只有一个线程.
10. 视图工作机制
Android进阶——Android视图工作机制之measure、layout、draw
10-1.Android视图工作机制按顺序分为以下三步:
- measure:确定View的宽高
- layout:确定View的位置
- draw:绘制出View的形状
相关概念:
- View(照片框):自定义View
- measure(尺子):测量View大小
- MeasureSpec(尺子刻度):测量View大小的测量单位
- layout(照片框的位置):View的具体位置
- draw(笔):绘制View
例如: 画图步骤:
- 首先画一个100 x 100的照片框,需要尺子测量出宽高的长度(measure过程)
- 然后确定照片框在屏幕中的位置(layout过程)
- 最后借助尺子用手画出我们的照片框(draw过程)
自定义View第一步是 测量, 测量 需要 测量规格(或测量标准)才能知道View的宽高,所以在 测量之前需要认识MeasureSpec类. MeasureSpec的表示形式是32位的int值
- 高2位(前面2位):表示测量模式,即SpecMode
- 低30位(后面30位):表示在测量模式下的测量规格大小,即SpecSize
一、结论:子View的MeasureSpec 由 "父容器的MeasureSpec" 和 "自身的LayoutParams" 来共同决定的
- 首先要知道LayoutParams有三种情况:MATCH_PARENT、WARP_CONTENT、100dp(精确大小).
- 只要子View的MeasureSpec被确定,那么就可以在measure过程中,测量出子View的宽高
其實決定權在 子view 的layoutParams
三.measure过程
一、ViewGroup的measure过程ViewGroup源码中, 提供了一个 measureChildren 的方法 来遍 历调用子 View的measure方法.
从源码中分析,
getChildMeasureSpec()逻辑其实就是总结的内容.//如果父View为具体的大小,比如100dp
case MeasureSpec.EXACTLY:
//如果子View的宽高有具体值,比如50dp,就直接用50dp
if (childDimension >= 0) {
resultSize = childDimension; //50dp
resultMode = MeasureSpec.EXACTLY; //精确模式
//如果子View的宽高是MATCH_PARENT,就用子View真实可以容纳最大的大小
} else if (childDimension == LayoutParams.MATCH_PARENT) {
resultSize = size; //子View真实可以容纳最大的大小
resultMode = MeasureSpec.EXACTLY; //精确模式
//如果子View的宽高是WRAP_CONTENT,就用子View真实可以容纳最大的大小,但是不能超过父View的大小
} else if (childDimension == LayoutParams.WRAP_CONTENT) {
resultSize = size; //子View真实可以容纳最大的大小
resultMode = MeasureSpec.AT_MOST; //最大值模式:不能超过父View的大小
}
break;
10-3. Android视图工作机制之layout过程
1. setFrame()onLayout()方法其实就是一个空方法, 自定义View时重写onLayout()方法,其实就是让我们重新设置View的位置.
setFrame()去挖掘它是如何判断View已经发生位置改变的.前视图的大小或者位置与上次相比发生了变化, 执行两次
invalidate().2. invalidate()
方法在 UI 線程中調用,重繪當前 UI。
其他:
postInvalidate() 方法在非 UI 線程中調用,通知 UI 線程重繪。
10-4. Android视图工作机制之draw过程
1.绘制当前视图的背景:drawBackground(canvas)
2.保存当前画布的堆栈状态,并且在在当前画布上创建额外的图层,以便接下来可以用来绘制当前视图在滑动时的边框渐变效果
3.绘制当前视图的内容:if (!dirtyOpaque) onDraw(canvas)
4.绘制当前视图的子视图的内容:dispatchDraw(canvas)
5.绘制当前视图在滑动时的边框渐变效果
6.绘制当前视图的滚动条:onDrawForeground(canvas)
10-5.Android视图工作机制中的重绘
一. invalidate()和requestLayout(),常用于View重绘和更新,其主要区别如下
- invalidate方法只会执行onDraw方法
- requestLayout方法只会执行onMeasure方法和onLayout方法,并不会执行onDraw方法。
只需调用invalidate方法;
*View宽高、位置发生改变 且显示 内容不变,只需调用requestLayout方法;
*两者均发生改变,则需调用两者,按照View的绘制流程,推荐先调用requestLayout方法再调用invalidate方法.
二、invalidate()和postInvalidate()
- invalidate方法用于UI线程中重新绘制视图
- postInvalidate方法用于非UI线程中重新绘制视图,省去使用handler
11.事件分发机制
Android事件分发机制之dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent
12. ListView
ListView是能将一个 数据集合以动态滚动 的方式展示到用户界面上的View.
12-3. ListView的优化 ??
- 重用convertView
- 使用ViewHolder
- 图片三级缓存
- 监听滑动事件
- 少用透明View
- 开启硬件加速
13.Android项目构建面试题
*proguard是什么?
ProGuard工具是用于压缩、优化和混淆我们的代码,其主作用是移除或混淆代码中无用类、字段、方法和属性. 我們程式中沒使用(有lib使用).
*proguard技术功能
- 压缩
- 优化
- 混淆
- 预检测
14.ANR
UI thread & worker thread.通常如果再UI thread 上做過多計算容易發生 , (官網是5s; 有時不到or 更久)
解決方法:
AsyncTask
Thread
Handler
15. OOM (out of memory)
通常為bitmap 沒 recycle 造成( 新版幾乎有自己回收機制,不怎發生)



沒有留言:
張貼留言