Activity、 Window、 View 三者如何协同显示界面的。—考点:显示的过程(view 绘 制流程)源码的熟悉度。
Activity 剪窗花的人(控制的);Window 窗户(承载的一个模型);View 窗花(要显示 的视图 View);LayoutInflater 剪刀—将布局(图纸)剪成窗花。 (Alt+方向箭头)
fragment 的特点?(你用 fragment 有没有领略到一些乐趣,或者有没有踩过什么坑?)
fragment 的设计主要是把 Activity 界面包括其逻辑打碎成很多个独立的模块,这样便 于模块的重用和更灵活地组装呈现多样的界面。
1) Fragment 可以作为 Activity 界面的一个部分组成;
2) 可以在一个 Activity 里面出现多个 Fragment,并且一个 fragment 可以在多个 Activity 中使用;
3) 在 Activity 运行中,可以动态地添加、删除、替换 Fragment。
4) Fragment 有自己的生命周期的,可以响应输入事件。
踩过的坑:
重叠;
注解 newAPI(兼容包解决);
Setarguement()初始化数据;
不 能在 onsave…()方法后,commit;
入栈出栈问题; --事务。
像 Activity 跳转 一样的效果,同时返回的时候还能回到之前的页面(fragment)并且状态都还在。 replace(f1,f2)严重影响生命周期:add()+show+hide
两种情况:
1) 一般很多高版本的新的 API 都会在兼容包里面找到替代的实现。比如 fragment。 Notification , 在 v4 兼 容 包 里 面 有 NotificationCompat 类 。 5.0+ 出 现 的 backgroundTint,minSdk 小于 5.0 的话会包检测错误,v4 兼容包 DrawableCompat 类。
2) 没有替代实现就自己手动实现。比如:控件的水波纹效果—第三方实现。 或者直接在低版本去除这个效果。
3) 补充:如果设置了 minSDK 但是代码里面使用了高版本的 API,会出现检测错误。需 要在代码里面使用声明编译检测策略,比如:@SuppressLint 和@TargetApi 注解提 示编译器编译的规则。@SuppressLint 是忽略检测;@TargetApi=23,会根据你函数 里面使用的 API,严格地匹配 SDK 版本,给出相应的编译错误提示。
4) 为了避免位置的错误,最好不要使用废弃 api。(一般情况下不会有兼容性问题,后 面可能会随时删除这个 API 方法;性能方面的问题。)
栈:先进后出
标准模式
SingleTop:使用场景:浏览器的书签;通讯消息聊天界面。
SingleTask:使用场景:某个 Activity 当做主界面的时候。
SingleInstance:使用场景:比如浏览器 BrowserActivity 很耗内存,很多 app 都会要调用 它,这样就可以把该 Activity 设置成单例模式。比如:闹钟闹铃。
Measure:测量,测量自己。如果是 ViewGroup 就需要测量里面的所有 childview.
测 量 的 结 果 怎 么 办 ? setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState), heightSizeAndState);设置自己的大小。
Layout: 摆放,把自己摆放在哪个位置。如果是 ViewGroup 就需要发放里面的所有 childview.
怎么去具体摆放呢?
Draw:绘制
/*
Draw traversal performs several drawing steps which must be executed
in the appropriate order:
1)什么是内存泄漏:最好解释清楚 GC 垃圾回收机制以及概念 GC Root。
2)为什么会有内存泄漏:因为内存泄漏是属于人为的失误造成的。而且面向对象开发 关系复杂、多线程的关系,很容易出现引用层级关系很深以及很混乱。
3)什么情况容易导致内存泄漏;
4)如何解决内存泄漏;
可以通过查看/data/anr/traces.txt 查看 ANR 信息。
根本原因是:主线程被卡了,导致应用在 5 秒时间未响应用户的输入事件。
很多种 ANR 错误出现的场景:
1) 主线程当中执行 IO/网络操作,容易阻塞。
2) 主线程当中执行了耗时的计算。----自定义控件的时候 onDraw 方法里面经常这么 做。(同时聊一聊自定义控件的性能优化:在 onDraw 里面创建对象容易导致内存抖动 —绘制动作会大量不断调用,产生大量垃圾对象导致 GC 很频繁就造成了内存抖动。)内存抖动就容易造成 UI 出现掉帧卡顿的问题。
3) BroadCastReceiver 没有在 10 秒内完成处理。
4) BroadCastReceiver 的 onReceived 代码中也要尽量减少耗时的操作,建议使用 IntentService 处理。
5) Service 执行了耗时的操作,因为 service 也是在主线程当中执行的,所以耗时操 作应该在 service 里面开启子线程来做。
6) 使用 AsyncTask 处理耗时的 IO 等操作。
7) 使 用 Thread 或 者 HandlerThread 时 , 使用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND) 或 者 java.lang.Thread.setPriority (int priority)设置优先级为后台优先级,这 样可以让其他的多线程并发消耗 CPU 的时间会减少,有利于主线程的处理。
8) Activity 的 onCreate 和 onResume 回调中尽量耗时的操作。
OOM 产生的原因:内存不足,android 系统为每一个应用程序都设置了一个硬性的条件: DalvikHeapSize 最大阀值 64M/48M/24M.如果你的应用程序内存占用接近这个阀值,此时如 果再尝试内存分配的时候就会造成 OOM。
1)内存泄露多了就容易导致 OOM
2)大图的处理。压缩图片。平时开发就要注意对象的频繁创建和回收。
3)可以适当的检测:ActivityManager.getMemoryClass()可以用来查询当前应用的 HeapSize 阀值。可以通过命名 adb shellgetProp | grep dalvik.vm.heapxxxlimit 查看。
如何避免内存泄露:
1) 减小对象的内存占用:
a) 使用更加轻量级的数据结构: 考虑适当的情况下替代 HashMap 等传统数据结构而使用安卓专门为手机研发 的 数 据 结 构 类 ArrayMap/SparseArray 。 SparseLongMap/SparseIntMap/SparseBoolMap 更加高效。 HashMap.put(string,Object);Object o = map.get(string);会导致一些没必 要的自动装箱和拆箱。
b) 适当的避免在 android 中使用 Enum 枚举,替代使用普通的 static 常量。(一 般还是提倡多用枚举—软件的架构设计方面;如果碰到这个枚举需要大量使 用的时候就应该更加倾向于解决性能问题。)。
c) 较少 Bitmap 对象的内存占用。 使用 inSampleSize:计算图片压缩比例进行图片压缩,可以避免大图加载造成 OOM; decodeformat : 图 片 的 解 码 格 式 选 择 , ARGB_8888/RGB_565/ARGB_4444/ALPHA_8,还可以使用 WebP。
d) 使用更小的图片 资源图片里面,是否存在还可以继续压缩的空间。
2) 内存对象的重复利用: 使用对象池技术,两种:
1.自己写;
2.利用系统既有的对象池机制。比如 LRU(Last Recently Use)算法。
a) Li
《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享
stView/GridView 源 码 可 以 看 到 重 用 的 情 况 ConvertView 的 复 用 。RecyclerView 中 Recycler 源码。
b) Bitmap 的复用 Listview 等要显示大量图片。需要使用 LRU 缓存机制来复用图片。
c) 避免在 onDraw 方法里面执行对象的创建,要复用。避免内存抖动。
d) 常见的 java 基础问题—StringBuilder 等
3) 避免对象的内存泄露;
4) 使用一些内存的优化策略: 看文档
1)通过 Binder
2)通过广播
把几个关键版本的特性记住:3.0/4.0、4.4、5.0、6.0/7.0……
RequestLayout()方法:会导致调用 Measure()方法和 layout()。将会根据标志位判断是否 需要 onDraw();
onLayout():摆放 viewGroup 里面的子控件
onDraw():绘制视图本身;(ViewGroup 还需要绘制里面的所有子控件)
drawChild(): 重 新 回 调 每 一 个 子 视 图 的 draw 方 法 。 child.draw(canvas, this, drawingTime);
invalidate():在主线程当中刷新;
postInvalidate():在子线程当中刷新;其实最终调用的就是 invalidate,原理依然 是通过工作线程向主线程发送消息这一机制。
public void postInvalidate() {
postInvalidateDelayed(0);
}
public void postInvalidateDelayed(long delayMilliseconds) {
// We try only with the AttachInfo because there’s no point in invalidating
// if we are not attached to our window
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds);
}
}
public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
mHandler.sendMessageDelayed(msg, delayMilliseconds);
}
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_INVALIDATE: ((View) msg.obj).invalidate();
}
break;
传统的动画框架:View.startAnimation();
弊端:移动后不能点击。原因?跟实现机制有关系。
所有的透明度、旋转、平移、缩放动画,都是在 view 不断刷新调用 draw 的情况下实现的。
调用的 canvas.translate(xxx),canvas.scaleX(xxx)…. Xxx:matrix 像素矩阵来控制动画 的数据。记得看源码,结合多只缩放的 demo 看源码。
看具体的手机平台,常见的有:64M/32M 等。
性能对比:LinearLayout 的性能要比 RelativeLayout 好。
因为 RelativeLayout 会测量两次。而默认情况下(没有设置 weight)LinearLayout 只会测 量一次。
为什么 RelativeLayout 会测量两次?首先 RelativeLayout 中的子 view 排列方式是基于彼 此依赖的关系,而这个依赖可能和布局中 view 的顺序无关,在确定每一个子 view 的位置的 时候,就需要先给每一个子 view 排一下序。又因为 RelativeLayout 允许横向和纵向相互依 赖,所以需要横向纵向分别进行一次排序测量。