面试总结(Android基础)

2020-06-02  本文已影响0人  我叫王凯

Activity的启动模式

Activity的四大启动模式:

Activity中onStart和onResume的区别?onPause和onStop的区别?

Activity有三类:

结论:
onStart执行后,Activity为可见,执行onResume后,Activity为可见可交互。
onPause执行后,Activity为可见不可交互,执行onStop后,Activity为不可见不可交互。

注:可见可交互Activity可以称为前台活跃Activity,可见不可交互的Activity可以成为前台不活跃Activity,不可见不可交互Activity为后台Activity。

屏幕适配

平时如何有使用屏幕适配吗?原理是什么呢?

平时的屏幕适配一般采用的头条的屏幕适配方案。简单来说,以屏幕的一边作为适配,通常是宽。

原理:设备像素px和设备独立像素dp之间的关系是

px = dp * density

假设UI给的设计图屏幕宽度基于360dp,那么设备宽的像素点已知,即px,dp也已知,360dp,所以density = px / dp,之后根据这个修改系统中跟density相关的知识点即可。

Handler消息机制

详细查看gityuan的Android消息机制

Handler机制的作用:

负责跨线程通信,这是因为在主线程不能做耗时操作,而子线程不能更新UI,所以当子线程中进行耗时操作后需要更新UI时,通过Handler将有关UI的操作切换到主线程中执行。

Handler机制的成员:

Handler运行过程:

Handler运行过程

一个线程能否创建多个 Handler,Handler 跟 Looper 之间的对应关系?

说到这个问题,先了解一下ThreadLocal机制。

Looper中还有一个ThreadLocal。ThreadLocal不是线程,它的作用是可以在每个线程中存储数据。
Handler创建的时候会采用当前线程的Looper来构造消息循环系统。

那么Handler内部如何获取当前线程的Looper呢?
这就要使用ThreadLocal。Looper类中使用ThreadLocal来存储Looper对象。

那么为什么需要ThreadLocal来存储Looper呢?
因为Looper的构造函数是私有的,无法创建Looper进行赋值。只能将Looper的引用存在变量中,而且每个线程都有自己对应的Looper,则需要用到ThreadLocal来存储。因为ThreadLocal可以在不同的线程中互不干扰的存储并提供数据,通过ThreadLocal可以轻松获取每个线程的Looper。

而Looper中又有这样一段代码:

private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

从上面代码可以看出,如果获取sThreadLocal.get()不为空,就会抛出异常。代表sThreadLocal.set只会执行一次。由此得出结论:

一个Thread只能有一个Looper,一个MessageQueue,可以有多个Handler。

线程池的相关知识

Android 中的线程池都是直接或间接通过配置 ThreadPoolExecutor 来实现不同 特性的线程池.Android 中最常见的类具有不同特性的线程池分别为 FixThreadPool、CachedhreadPool、SingleThreadPool、ScheduleThreadExecutr。

  1. FixThreadPool:只有核心线程,并且数量固定的,也不会被回收,所有线程都活动时,因为队列没有限制大小,新任务会等待执行。优点:更快的响应外界请求。
  2. SingleThreadPool:只有一个核心线程,确保所有的任务都在同一线程中按序完成。因此不需要处理线程同步的问题。
  3. CachedThreadPool:只有非核心线程,最大线程数非常大,所有线程都活动时会为新任务创建新线程, 否则会利用空闲线程(60s 空闲时间,过了就会被回收,所以线程池中有 0 个线程的可能)处理任务。优点:任何任务都会被立即执行(任务队列 SynchronousQuue 相当于一个空集合); 比较适合执行大量的耗时较少的任务。
  4. ScheduledThreadPool:核心线程数固定,非核心线程(闲着没活干会被立即回收数)没有限制。优点:执行定时任务以及有固定周期的重复任务。

Fragment 加载到 Activity 的 2 种方式

Fragment 加载到 Activity 的方式分为静态加载和动态加载,下面我们看看这两种加载方 式:
静态加载:直接在 Activity 布局文件中指定 Fragment。使用指定属性 name 即可,代码 如下所示:

<fragment
 android:name="com.example.myfragment.MyFragment"
 android:id="@+id/myfragment_1"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"/>

动态加载: 动态加载需要使用到 FragmentManager,这种动态加载的方式在开发中是 非常常见的,示例代码如下:

FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginT ransaction();
 //将FragmentA从容器中移除掉,减少内存的消耗
 fragmentTransaction.remove(fragmentA);
 fragmentTransaction.add(R.id.fragment_layout,new FragmentB());
 fragmentTransaction.commit();

理解Activity,View,Window三者关系

这个问题真的很不好回答。所以这里先来个算是比较恰当的比喻来形容下它们的关系吧。Activity像一个工匠(控制单元),Window像窗户(承载模型),View像窗花(显示视图)LayoutInflater像剪刀,Xml配置像窗花图纸。

1:Activity构造的时候会初始化一个Window,准确的说是PhoneWindow。

2:这个PhoneWindow有一个“ViewRoot”,这个“ViewRoot”是一个View或者说ViewGroup,是最初始的根视图。

3:“ViewRoot”通过addView方法来一个个的添加View。比如TextView,Button等

4:这些View的事件监听,是由WindowManagerService来接受消息,并且回调Activity函数。比如onClickListener,onKeyDown等。

View的事件分发机制

事件分发本质:就是对MotionEvent事件分发的过程。即当一个MotionEvent产生了以后,系统需要将这个点击事件传递到一个具体的View上。
点击事件的传递顺序:Activity(Window) -> ViewGroup -> View
三个主要方法:
dispatchTouchEvent:进行事件的分发(传递)。返回值是 boolean 类型,受当前onTouchEvent和下级view的dispatchTouchEvent影响
onInterceptTouchEvent:对事件进行拦截。该方法只在ViewGroup中有,View(不包含 ViewGroup)是没有的。一旦拦截,则执行ViewGroup的onTouchEvent,在ViewGroup中处理事件,而不接着分发给View。且只调用一次,所以后面的事件都会交给ViewGroup处理。
onTouchEvent:进行事件处理。

View 的绘制过程,自定义View。

View 的绘制过程

关于View的绘制过程,可以简单的分成三个步骤:
1)measure 过程:
作用:测量View的宽、高
流程:performMeasure() --- measure() --- onMeasure() --- 子View的measure()
备注:在onMeasure() 方法中会对所有的子元素进行measure过程
2)layout 过程:
作用:通过确定View四个顶点的位置,从而确定View的位置
流程:performLayout() --- layout() --- onLayout() ---子View的layout过程
备注:在OnLayout()方法中会对所有子元素进行layout过程
3)draw 过程:
作用:将View绘制在屏幕上
流程:performDraw() --- draw() --- onDraw() --- 子View 的 draw 过程

自定义View

自定义View分为以下几种:

类型 定义
自定义组合控件 多个控件组合成为一个新的控件,方便多处复用
继承系统View控件 继承自TextView等系统控件,在系统控件的基础功能上进行扩展
继承View 不复用系统控件逻辑,继承View进行功能定义
继承系统ViewGroup 继承自LinearLayout等系统控件,在系统控件的基础功能上进行扩展
继承ViewViewGroup 不复用系统控件逻辑,继承ViewGroup进行功能定义

详情参考Android自定义View全解

Android有哪些序列化方式?

为了解决Android中内存序列化速度过慢的问题,Android使用了Parcelable

对比 Serializable Parcelable
易用性 简单 需要实现特定方法
效率
场景 IO、网络和数据库 内存中
上一篇下一篇

猜你喜欢

热点阅读