Android 面试主题整理合集(一),android 开发前景
7.invalidate 与 requestLayout 区别
============================
- view 调用 invalidate 将导致当前 view 的重绘,viewGroup 调用 invalidate 会使 viewGroup 的子 view 调用 draw 
- requestLayout 方法只会导致当前 view 的 measure 和 layout,而 draw 不一定被执行。只有当 view 的位置发生改变才会执行 draw 方法 
8.View 和 ViewGroup 区别
==================
- ViewGroup 的 onInterceptTouchEvent 默认返回 false,即不拦截事件,View 没有拦截事件方法,View 默认时消耗事件的 
- ViewGroup 默认不会调用 onDraw 方法,View 默认会调用 onDraw 方法。可以通过 setWillNotDraw(boolean willNotDraw)来指定是否调用 onDraw 方法 
/**
- If this view doesn't do any drawing on its own, set this flag to 
- allow further optimizations. By default, this flag is not set on 
- View, but could be set on some View subclasses such as ViewGroup. 
- Typically, if you override {@link #onDraw(android.graphics.Canvas)} 
- you should clear this flag. 
- @param willNotDraw whether or not this View draw on its own 
*/
public void setWillNotDraw(boolean willNotDraw) {
setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK);
}
9.android 版本新特性
==============
- 5.0 引入 Material Design 主题 
- 6.0 运行时权限 
- 7.0 文件读写权限适配 FileProvider 移除了对 Apache HTTP 客户端的支持,建议使用 HttpURLConnection 代替。继续使用 Apache HTTP API,必须先在 build.gradle 文件中配置: android { useLibrary 'org.apache.http.legacy' } 复制代码 
- 8.0 为所有通知分配渠道 app 内更新下载好的 apk 文件,需要用户开启未知应用安装权限 
- 9.0 使用安全的网络访问,如果使用 http 请求会报错。Android 9.0 网络适配 
- 10.0 存储空间分区存储,沙盒模式 
10.Android 中一张图片占据的内存大小是如何计算
===========================
- 图片来源是 res 内的不同资源目录时,系统会根据设备当前的 dpi 值以及资源目录所对应的 dpi 值,做一次分辨率转换,规则如下:新分辨率 = 原图横向分辨率 * (设备的 dpi / 目录对应的 dpi ) * 原图纵向分辨率 * (设备的 dpi / 目录对应的 dpi ) 
- 其他图片的来源,如磁盘,文件,流等,均按照原图的分辨率来进行计算图片的内存大小 
- 一张图片占用的内存大小的计算公式:分辨率 * 像素点大小;但分辨率不一定是原图的分辨率,需要结合一些场景来讨论,像素点大小就几种情况:ARGB_8888(4B)、RGB_565(2B) 等等 
11.APP 启动速度优化
============
- 用 adb 命令可以检测启动时间,示例如下: 
adb shell am start -W [packageName]/[.MainActivity]
./adb shell am start -W "com.hchstudio.dict"/".MainActivity"
WaitTime 为我们所关注的启动时间
- app 的启动流程,主要需要减少 Application 和启动界面的 onCreate 方法 
- 的 app 首页主题样式加上 android:windowBackground,放一下 app 的背景图片,这样即使 app 启动慢,也会首先加载背景,这样就会给用户造成一种假象,认为是 app 已经启动 
<style name="AppTheme.Launcher">
<item name="android:windowBackground">@color/colorLauncher</item>
</style>
12.内存抖动
=======
内存抖动是由于短时间内有大量对象进出新生区导致的,它伴随着频繁的 GC,gc 会大量占用 ui 线程和 cpu 资源,会导致 app 整体卡顿。
避免发生内存抖动的几点建议:
- 尽量避免在循环体内创建对象,应该把对象创建移到循环体外。 
- 注意自定义 View 的 onDraw()方法会被频繁调用,所以在这里面不应该频繁的创建对象。 
- 当需要大量使用 Bitmap 的时候,试着把它们缓存在数组或容器中实现复用。 
- 对于能够复用的对象 
,同理可以使用对象池将它们缓存起来。
13.Android 中 ClassLoader 的种类 &特点:
=============================
- BootClassLoader(Java 的 BootStrap ClassLoader): 
用于加载 Android Framework 层 class 文件。
- PathClassLoader(Java 的 App ClassLoader): 
只能加载已经安装过的 apk 的 dex 文件
- DexClassLoader(Java 的 Custom ClassLoader): 
可以从一个 jar 包或者未安装的 apk 中加载 dex 文件
- BaseDexClassLoader: 
是 PathClassLoader 和 DexClassLoader 的父类。
14.SharePreference 为什么不能存储较大 value
================================
public String getString(String key, @Nullable String defValue) {
synchronized (this) {
awaitLoadedLocked();
String v = (String)mMap.get(key);
return v != null ? v : defValue;
}
}
private void awaitLoadedLocked() {
while (!mLoaded) {
try {
wait();
} catch (InterruptedException unused) {
}
}
- SharePreference 存值的时候,内部会有一个静态的 map 保存了你所有的 key 和 value 
private ArrayMap<File, SharedPreferencesImpl> getSharedPreferencesCacheLocked() {
if (sSharedPrefsCache == null) {
sSharedPrefsCache = new ArrayMap<>();
}
final String packageName = getPackageName();
ArrayMap<File, SharedPreferencesImpl> packagePrefs = sSharedPrefsCache.get(packageName);
if (packagePrefs == null) {
packagePrefs = new ArrayMap<>();
sSharedPrefsCache.put(packageName, packagePrefs);
}
return packagePrefs;
}
15.实现 View 滑动的几个办法
================
- View 自身提供的 scrollTo()和 scrollBy 方法。但只适合对 View 内容的滑动 
- 使用动画。但滑动后的 View 点击没有效果,所以适用于没有交互的 View 
- 改变布局参数,比如 layoutParams.left。比动画稍微复杂,适合有交互的 View 
Scroller 使用。调用 startScroll 方法,然后 invidate() --> View 会调用 onDraw(),里面会调用 computeScroll(),此方法默认空实现,需要自行实现 --> 重写 computeScroll(),实现滑动,如果没有结束,postInvalidate()重绘
 
 16.事件分发
=======
 
  
  
  
  
  
 - 源码 
// 1. Activity 的 dispatchTouchEvent()方法
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
//交给 PhoneWindow 处理
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
// 2. PhoneWindow 的 superDispatchTouchEvent()方法
public boolean superDispatchTouchEvent(MotionEvent event) {
//交给 DecorView 处理
return mDecor.superDispatchTouchEvent(event);
}
// 3. 由于 DecorView 是 FrameLayout 子类,所以事件会被传递到 DecorView 的子 View 也就是,setContentView 设置的 View 中
- View 的事件分发 
 
  
 17.View 的测量
==========
 
  
 










 
    
评论