Android面试题笔记

Android面试题记录

Android面试题笔记

面试题的笔记与自己的看法

数据结构

  1. 数组

    • 是由同一种数据类型组成

    • 存储在连续的内存中

    • 可以使用索引来查找数组中的元素地址

    • 通常有一维数组(也是最常用的,也是最简单的数据结构),多维数组

    • 时间复杂度:

      算法 平均复杂度
      空间 O(n)
      查找 O(n)
      插入 O(n)
      删除 O(n)
  1. 链表

    • 链表整体看起来是个树型,而不是数组

    • 每一个节点都包括一个数组和一个指针

    • 节点中的数据类型可以为任意类型

    • 指针就是指向下一节点的引用

    • 每个链表都包含一个头节点和一个尾节点

    • 头节点就是链表中的第一个节点。尾节点就是链表中最后一个节点

    • 头节点和尾节点并不相连,尾节点的指针下一个是结尾(也就是指向空),并不是一个循环数据结构

    • 时间复杂度:

      算法 平均复杂度
      空间 O(n)
      查找 O(n)
      插入 O(1)
      删除 O(1)
  2. 双向链表

    • 一个双向链表首先是一个链表

    • 一个双向链表中有一个前驱指针和一个后继指针

    • 前驱指针是指向前驱结点(也就是前一个节点)

    • 后继指针是指向后继结点(也就是后一个结点)

    • 在双向链表中也有一个头结点,头结点是指向第一个节点,最后一个结点指向空

    • 如果最后一个结点指向第一个结点,那么这就变成了双向循环链表

    • 双向循环链表可以很容易从每个结点查找到它的前驱节点和后继节点

    • 时间复杂度:

      算法 平均复杂度
      空间 O(n)
      查找 O(n)
      插入 O(1)
      删除 O(1)
    • 是一个有着【后进先出】特性的数据结构

    • 也就是最后进栈的元素也是第一个出栈的元素

    • 想要得到栈中第一个元素(也就是最下面的元素),就必须要把后面(上面)所有的元素都先出栈,才可以取出第一个元素

    • 向栈中添加一个元素的操作被称作Push(入栈)

    • 从栈中取出一个元素的操作被称为Pop(出栈)

    • 查看且不删除栈中最后一个入栈的元素(也就是最上方的元素)的操作被称为Top

    • 时间复杂度:

      算法 平均复杂度
      空间 O(n)
      查找 O(n)
      入栈(Push) O(1)
      出栈(Pop) O(1)
      查看栈顶(Top) O(1)
  3. 队列

  4. 贪婪算法

    • 贪婪算法也就是在求解一个问题的时候,做出当前最好的解决,而不是全局最好的解决
    • 这种算法的实现都是在某一方面上局部最优解
    • 贪婪算法也是不可回退的
    • 贪婪算法在最优子结构问题中尤为有效,最优子结构也就是局部最优能决定全局最优(问题能分成多个小问题,每个小问题的最优解决能递推到最终问题的最优解)
    • 当一个问题可以通过贪婪算法解决时,那么贪婪算法一般是解决这个问题的最好解决办法

Java核心

  1. 基本数据类型

    • byte(数据类型为8位,有符号,以而进程补码的整数,默认值是”0”)

    • short(数据类型位16位,有符号,以二进程补码的整数,默认值是”0”)

    • int(数据类型为32位,有符号,以二进程补码表示的整数,默认值是”0”)

    • long(数据类型为64位,有符号,以二进程补码的整数,默认值是”0L”(L是不区分大小写,为了书写规范,最好写成大写))

    • float(数据类型为单精度,32位的浮点数,默认值是”0f”)

    • double(数据类型为双精度,64位的浮点数,默认值是”0d”)

    • boolean(数据类型为表示一位的信息,默认值只有两种”true”,”false”)

    • char(数据类型为一个单一的16位Unicode字符,可以存储任意字符)

      Unicode是全球统一的字符编码

  2. 抽象类的概念

    • 在面向对象的概念中,所有的对象都是用类来描述,但是并不是所有的类都是来描述对象的,当一个类没有足够多的信息来描绘一个对象时,这个类就是一个抽象类
  3. 抽象的概念

  4. 继承

    • 继承可以使子类别具有父类别的各种属性和方法,而不需要去在重复编写相同代码。子类在继承父类的同时,也可以去重新定义某些属性,并重写某些方法,来覆盖父类别的原有属性和方法,使获取和父类别不同的功能。当遇到需要多重继承的时候,可以使用实现接口来实现多继承相似的效果
  5. 封装

    • 从字面意思上来讲就是包装的意思,是指利用抽象数据类型,将数据和有关数据操作都封装起来,使它变成一个不可分割的独立体。用户不知道对象内部的细节,但是可以通过该对象提供的接口来进行访问对象。好处是:减少耦合性,方便未来修改
  6. 多态

    • 多态就是指一个行为有多个不同的表现形式或形态的能力。多态就是一个接口,使用不同的实例而执行不同的操作(比如说定义了一个接口,它有两个不同的实例对象,使用不同的实例化就可以使用不同的效果)
  7. 面向对象的三个基本元素和五个原则

    1. 元素
      • 继承
      • 多态
      • 封装
    2. 原则
      • 单一职责
      • 开闭原则
      • 里氏替换
      • 依赖倒置
      • 接口隔离
  8. 什么是线程,什么是进程?

    1. 进程
      • 进程就是程序一次运行的过程,是系统运行程序的基本单位,因此进程是动态的。在java中,当我们运行main函数,其实也就是开启了一个JVM进程
    2. 线程
      • 线程于进程类似,是一个比进程更小的执行单位,一个进程在执行过程中可以开启多个线程。当运行main函数时,main函数所在的线程就是进程中的一个线程,也就是主线程
  9. JDK & JVM & JRE分别是什么以及它们的区别?

    1. JDK

      • JDK是整个JAVA开发的核心,是面向开发者使用的SDK,它提供了JAVA的开发环境和运行环境
    2. JRE

      • JRE就是运行时环境(它主要包含两个部分,JVM的标准实现,JAVA的一些基本类库)
    3. JVM

      • JVM是JAVA虚拟机,也就是因为它,所以JAVA才拥有跨平台性
    4. 区别

      • 它们三者的关系为:JDK包含JRE包含JVM

        image-20210216113540235

  10. 什么是面向过程 & 什么是面向对象 & 区别?

    1. 面向对象

      • 面向对象是一种对现实世界理解和抽象的方法
    2. 面向过程

  • 是一种 以过程为中心 的编程思想。这些都是以什么正在发生为主要目标进行编程,不同于面向对象的是谁在受影响。每个过程有一个阶段性的目标,依次完成这些过程,才能得到结果
  1. 给我说说Java面向对象的特征

    1. 特点
      • 对象具有属性和行为
      • 对象具有变化和形态
      • 对象具有唯一性
      • 对象都是某个类别的实例
      • 一切皆为对象,真实世界中的所有事物都可以视为对象
    2. 三大基本特征
      • 继承
      • 多态
      • 封装
  2. 什么是重载 & 什么是重写 & 区别

    1. 重载

      • 重载就是指在同一个类中,方法名相同,而参数不同,返回类型可以相同,也可以不相同
    2. 重写

      • 重写是指在方法名相同时,参数也相同,返回类型也相同,但方法内部实现操作不同(一般表示子类与父类之间的关系)
    3. 区别

      区别点 重载方法 重写方法
      参数列表 必须修改 一定不能修改
      返回类型 必须修改 一定不能修改
      访问修饰符 不能比父类更严格 一定不能修改
      方法名 一致 一致
      异常 可以修改 可以减少或删除,一定不能抛出新的或者更
      访问 可以修改 一定不能做更严格的限制(可以降低限制)
  3. 谈谈你对this和super的认识

    1. this
      • this就是指当前方法的调用者(也就是指当前使用的对象)
    2. super
      • super只是编译期中的一个指示符(也就是被看作是调用父类中被重写的方法,但实际上调用者还是子类对象)
  4. 接口和抽象类的区别

    1. 接口
      • 接口是公开的,不能有私有的变量和方法,接口中的所有方法都没有方法体,通过关键字interface实现。接口也可以被看做抽象类的变体,接口中所有的方法都是抽象的,可以通过接口来实现多重继承
    2. 抽象类
      • 抽象类可以拥有私有的方法和变量,通过abstract来声明一个类是一个抽象类,被声明为抽象方法不能包含方法体。抽象类的子类为父类中所有抽象方法的具体实现,否则也是抽象类
    3. 相同点
      • 都不能被实例化
      • 接口的实现类或者抽象类的子类都只有实现了接口或者抽象类中的方法后才能实例化
    4. 不同点
      • 接口只能定义,不能有方法的实现。抽象类可以定义也可以实现方法
      • 实现接口的关键字为implements,继承抽象类的关键字为extends。一个类可以实现多个接口,但只能继承一个抽象类
      • 接口强调特定功能的实现,抽象类强调所属关系
  5. 给我说说权限修饰符特性

    1. public 公开的
    2. private 类内部使用,外部没有访问权
    3. protected 继承权限,子类继承父类后,子类有权限访问父类,在不同的包下都可以访问
    4. default 默认访问权限,在同个包下都可以访问
  6. 给我谈谈Java中的内部类

    在Java中允许在类的内部在创建一个类,这个定义在类内部的类就被称作内部类,包含内部类的类就被称作外部类。内部类可以方便的访问外部类私有属性和方法

    1. 静态内部类

      • 定义方式为 static class。静态内部类可以直接访问外部类的静态属性和方法,但是不可以访问外部类的实例属性和方法

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        public class StaticOutter {
        private static Integer outterNum = 1;

        private static void outStatic(){
        System.out.println("run out static");
        }

        public static class StaticInner{

        public void testStaticInner(){
        System.out.println("调用外部类的静态方法");
        outStatic();
        System.out.println("调用外部类的静态属性");
        System.out.println(outterNum);
        }

        }

        }
    2. 成员内部类

      • 定义方式为 class。成员内部类除了可以访问外部类的静态属性和方法,还可以访问实例属性和方法,但不可以定义静态变量和静态方法。这里可以吧成员内部类看作一个比较特殊的实例方法

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        public class Outter {
        private Integer outterNum = 1;

        private void outterMethod(){
        System.out.println("运行外部方法......");
        }

        public class Inner{

        public void innerMethod(){
        System.out.println("outterNum:"+outterNum);
        System.out.println("运行outter的方法");
        outterMethod();
        }

        }
        }
    3. 方法内部类

      • 定义方式为 class。方法内部类就是在一个方法中定义的一个类,方法内部类只能在定义的方法中使用。方法内部类可以直接调用定义方法的参数和方法内部的属性,也可以调用外部类中的静态属性和方法

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        public class MethodOutter {
        private Integer outter = 10;

        public void testMethod(Integer param){
        String local = "hello";
        class MethodInner{
        public void innerMethod(){
        System.out.println("MethodOutter outter:"+outter);
        System.out.println("param:"+param);
        System.out.println("local:"+local);
        }

        }
        MethodInner inner = new MethodInner();
        inner.innerMethod();
        }

        public static void main(String[] args) {
        MethodOutter out = new MethodOutter();
        out.testMethod(1);
        }
        }

    4. 匿名内部类

      • 匿名内部类只能使用一次,它没有名字,没有构造方法,但它可以根据参数调用父类的构造方法。和方法内部类一样,匿名内部类可以访问外部类的属性和方法,也可以访问局部变量和参数

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        public interface TestInteface {
        public void show(String param);
        }

        public class AnonymousTest {
        public void test(){
        new TestInteface() {
        @Override
        public void show(String param) {
        System.out.println(param);
        }
        };
        }
        }
  7. 什么是拆箱 & 装箱,能给我举栗子吗?

    1. Java中基础数据类型与它们的包装类进行运算时,编译器会自动帮我们进行转换,转换过程对程序员是透明的,这就是装箱和拆箱,装箱和拆箱可以让我们的代码更简洁易懂

    2. 在那些情况下会进行操作

      • 进行‘=’赋值操作(装箱或拆箱)
      • 进行’ + , - , * , / ‘混合运算(拆箱)
      • 进行’ > , < , ==’比较运算(拆箱)
      • 进行’equals’进行比较(装箱)
    3. 例子

      1
      2
      3
      4
      5
      public void testAutoBox() {
      List<Float> list = new ArrayList<>();
      list.add(1.0f);
      float firstElement = list.get(0);
      }

      在第二行中,创建了一个存放Float类型的List,然后往里添加1.0f(float基础类型),在将结果返回给float(这里List取出的结果是为Float)

      所以结果很明显了,以float和Float为例,装箱就是调用Float的valueOf方法new一个Float并赋值,拆箱就是调用Float对象的floatValue方法并赋值返回给float。其他基础类型都是大同小异的,具体可以查看源码。

  8. static关键字的作用?

    在Java中主要有3种使用情况

    1. static成员变量

      (Java类提供了两种类型的变量:用static关键字修饰的静态变量和不用static关键字修饰的实例变量)

      • 静态变量属于类,在内存中只有一个复制,只要静态变量所在的类被加载,这个静态变量就会被分配空间,因此就可以被使用了。对静态变量的引用有两种方式,分别是“类.静态变量”和”对象.静态变量”
      • 实例变量属于对象,只有对象被创建后,实例变量才会被分配内存空间,才能被使用,它在内存中存在多个复制,只有用“对象.实例变量”的方式来引用
    2. static成员方法

      Java中提供了static方法和非static方法

      • static方法是类的方法,不需要创建对象就可以被调用
      • 而非static方法是对象的方法,只有对象被创建出来后才可以被使用(static方法中不能使用this和super关键字,不能调用非static方法)
    3. static代码块

      • static代码块在类中是独立于成员变量和成员函数的代码块的。注意: 这些static代码块只会被执行一次
  9. final关键字的作用

  10. 说说Java异常体系主要用来干什么的 & 异常体系?

  11. Error和Exception的区别?

  12. 说说运行时异常和非运行时异常的区别?

  13. 如何自定义一个异常?

  14. 5个常见的运行时异常

  15. 软引用和弱引用的区别?

    • 软引用关联的对象只有在内存不足时才会被回收,而被弱引用关联的对象在JVM进行垃圾回收时总会被回收。(也就是说 弱引用在每次进行垃圾回收的时候都会被回收,软引用只会在内存不足的时候回收)
  16. Socket的定义

    • 即套接字,是应用层 与 TCP/IP 协议族通信的中间软件抽象层,表现为一个封装了 TCP / IP协议族 的编程接口(API)
  17. 给我说说线程的生命周期

  18. 线程死锁的原因 & 举个栗子 & 如何避免死锁

  19. 如何停止掉一个线程?

  20. wait()和sleep()的区别?

  21. Java中创建线程的2种方式 & 区别?

  22. StringBufferStringBuilder 的区别在哪里?

    StringBuffer和StringBuilder和String基本都是一样的,都是用来存放字符串的。

    • string:但string是不可变的,任何对string的改变都会重新创建新的string,而StringBuffer和StringBuilder是可变的的
    • StringBuffer:区别在StringBuffer支持并发操作,是线性安全的,适合在多线程中使用。
    • StringBuilder:不支持并发操作,线性不安全的,所以不合适在多线程中使用,但StringBuilder在单线程中性能比StringBuffer更高

Android核心

  1. Activity生命周期(具体可以去Activity的讲解里查看)

    • onCreate(在活动第一次启动时,触发该方法)
    • onStart(该方法表示活动将被展现给用户)
    • onResume(该方法表示活动准备好与用户进行交互)
    • onPause(该方法表示活动因为其他原因,被其他Activity,全屏的Dialog覆盖)
    • onStop(该方法表示活动不在想要展示给用户,如果内存不足则会进行回收)
    • onRestart (该方法表示活动从停止状态再次想要展示给用户)
    • onDestory(该方法表示活动被销毁,可能会有一定延迟才会被回收)
  2. Android四大组件

    • 活动 Activity(是所有程序的根本)
    • 服务 Service(Android组件中的一种,不可以自己运行,只能后台运行,可以与其他组件进行交互)
    • 广播 BroadcastReceiver(是一种在应用程序之间传递信息的一种机制,也可以在应用内部进行传递信息)
    • 内容提供者 Content Provider(Android提供第三方应用数据访问的机制)
  3. Service与IntentService的区别

    • Android中的Service是用于后台服务的,它不是一个独立的进程,也不是一个独立的线程,它是依赖与程序的主线程,也就是说它是运行来主线程上的,不推荐在Service中编写耗时操作
    • 但是如果必须要在Service中编写耗时操作,那么就需要使用IntentService
    • IntentService是继承Service的,它包含了Service的全部特性,生命周期
    • IntentService与Service不同的是,在IntentService进行onCreate的时候,内部开启了一个线程,可以去执行耗时操作
  4. Android 应用的结构

  5. Android 应用中保存数据

    • sharedPreference(用xml来保存应用中的数据,本地)
    • SQL(将应用数据保存到应用本地数据库中,应用本地)
    • File(将应用数据保存到创建的txt文件中,本地)
  6. 在 Android 应用中执行耗时操作

    • 使用Thread执行耗时操作(也就是在子线程中进行耗时操作,在将结果通过Handler传回主线程)
    • 使用AsyncTask执行耗时操作(也就是在子线程中进行耗时操作,可通过onProgressUpdate方法来修改UI)
  7. 两个 Fragment 之间进行通信

    • 使用接口来进行两个Fragment之间的通信,通过宿主Activity中转一下
    • 使用广播
  8. Android 的通知系统

  9. Android启动模式

    • standard(那里调用就去那里,可多次堆叠,可以创建多个相同的Activity)
    • singleTop(可多次实例化,但不可堆叠,当栈顶为相同的Activity则会调用onNewIntent()方法)
    • singleTask(当已被实例化,再次创建则会将自己以上的所有Activity全部销毁,在调用onNewIntent(),如没被实例化,那将会创建新的Task并实例化后在入栈)
    • singleInstance(存在于单独的栈中,在这个栈中,只有也仅有它一个)
  10. 什么是Fragment

    • Fragment相当于是Activity中的模块,它有着自己的布局,生命周期,单独处理自己的输入输出
  11. Fragment 的生命周期

    • onAttch(当Fragment与Activity发生关联时调用)
    • onCreate(创建Fragment时回调,如果想要保存Fragment基本组件,则在这里初始化)
    • onCreateView(首次绘制页面时调用,在此可以创建View。这里不能进行耗时操作)
    • onActivityCreated(在onCreate方法完成后返回,这里可以进行与Activity交互UI操作,不能在此之前与Activity进行交互)
    • onStart(启动Fragment时回调,此时Fragment可见,只是没有显示在前台,不能和用户进行交互)
    • onResume(Fragment在前台处于可见状态时返回,可以与用户交互)
    • onPause(Fragment处于暂停状态时返回,处于可见状态,但不能和用户交互)
    • onStop(停止Fragment时回调,处于完全不可见)
    • onDestoryView(销毁有关Fragment的视图,但还未与Activity解除绑定)
    • onDestory(销毁Fragment时回调)
    • onDetach(与Activity的关联被取消时调用)
  12. Android 的 Dialog

- 
  1. Android 的 View

  2. Fragment 和 Activity 有什么区别?它们之间又有什么关系?

  3. 解释一下 Android 中的 Intent

  4. onSaveInstanceState方法会在什么时候被执行?

    • 按下Home键时,因为系统不知道你在按下Home键之后要运行多少个程序,自然也不知道当前的Activity会不会销毁,所以系统则会调用onSaveInstanceState来保存那些非永久性的数据
    • 关闭屏幕
    • 从当前Activity开启另一个Activity
    • 屏幕方向发生变化时

    onSaveInstanceState() 这个方法是用来保存UI状态的,可以使用它来保存当前UI和你所想保存的东西

  5. 简述View Touch事件传递机制。

    1. 过程
      • dispatchTouchEvent -> onInterceptTouchEvent(该方法只在ViewGroup中有) -> onTouchEvent
    2. dispatchTouchEvent (进行事件分发,返回值是Boolean)
    3. onInterceptTouchEvent (进行事件拦截,该方法只在ViewGroup中有,View中是没此方法,一旦拦截,则执行ViewGroup的onTouchEvent,在ViewGroup中处理事件,而不会接着分发给View,且只调用一次,所以后面的事件都会交给ViewGroup来处理)
    4. onTouchEvent(进行事件处理)
  6. 为什么在子线程中执行 new Handler() 会抛出异常?

    • 是因为在创建Handler时,会先获取当前线程的Looper,如果Looper为空,则会异常
  7. invalidate()和postInvalidate()的区别?

    • invalidate和postInvalidate都是用来刷新View的,但是invalidate是用于主线程刷新,如果在子线程则需要配合Handler。而postInvalidate可以在子线程中直接调用

    invalidate() 请求重绘View树,即draw()过程,即用来刷新View的(谁调用他,谁就刷新)

  8. res目录和assets目录的区别?

    • res/raw中的文件是会被映射到R.java中的,可以直接使用资源ID,不可以有目录结构
    • assets中的文件是不会映射到R.java中的,如果需要使用则需要AssetsManager类来进行访问,可以创建子文件夹
  9. onTouch()、onTouchEvent()和onClick()关系?

    • 优先度 onTouch -> onTouchEvent -> onClick
    • 因此onTouchListener的onTouch会先触发,如果onTouch返回为false才会接着触发onTouchEvent
    • onClick内部是通过onTouchEvent来实现的
  10. 为什么子线程不能更新UI?

    • 只有创建视图层次结构的原始线程才能更新这个视图,也就是说只有主线程才有权力去更新UI
    • 假如允许多线程更新UI,但是访问UI是没有加锁的,一旦多线程抢占了资源,那么界面将会乱套更新了
    • 其实还是可以在子线程中更新UI的,前提是它要拥有自己的ViewRoot,ViewRoot是在onResume中的addView()创建的。一般来说在onCreate中通过子线程更新UI是可行的,但不推荐,因为Android UI操作并不是线程安全
  11. 在 onCreate中 runOnUiTherad -> onHandler(Looper.getMainLooper()).post -> Thread(runOnUiTherad) -> View.post

    runOnUiTherad (调用此方法就可以在主线程中执行)

    onHandler(Looper.getMainLooper())(创建Handler时传递了主线程的Looper,这样onHandler就会在主线程中运行)

    View.post(View.post() 的内部也是调用了 Handler)

  12. SharedPreference的apply和commit的区别?

    • apply(首先apply是没有返回结果的,其次apply是将修改的数据提交给内存,然后在异步提交给硬盘)
    • commit(commit是会返回一个Boolean,表明是否修改成功。commit是将数据同步提交给硬盘)
  13. ScrollView下嵌套一个ListView通常会出现什么问题?如何解决?

    • 问题:当ScrollView嵌套ListView时,ListView的高度设置为wrap_content时会产生,一般情况下ListView只显示的第一个Item。
    • 解决
      1. 手动设置ListView高度,只需要在给ListView设置完Adapter之后在实际测量高度并赋值
      2. 停止使用ScrollView嵌套ListView,改用ListView多Item
      3. 自定义可适应ScrollView的ListView,也就是重写ListView中的onMeasure方法
  14. 什么是OOM?检测OOM的机制是什么?如何避免?

    • OOM是内存泄漏
    • WeakReferenceReferenceQueue联合使用,在弱引用关联的对象被回收后,会将引用添加到ReferenceQueue;清空后,可以根据是否继续含有该引用来判定是否被回收;判定回收, 手动GC, 再次判定回收,采用双重判定来确保当前引用是否被回收的状态正确性;如果两次都未回收,则确定为泄漏对象。
    • 如何避免内存泄露:
      1. 使用缓存技术,比如Recache、DiskLruCache、对象重复并且频繁调用可以考虑对象池
      2. 对于引用生命周期不一样的对象,可以用软引用或弱引用SoftReferner WeakReferner
      3. 对于资源对象 使用finally 强制关闭
      4. 内存压力过大就要统一的管理内存
  15. 广播的两种注册形式

    • 静态注册(在AndroidManifest中进行注册)在AndroidManifest中进行注册后,不管改应用程序是否处于活动状态,都会进行监听。

      1
      2
      3
      4
      5
      <receiver android:name=".IncomingSMSReceiver">  
      <intent-filter>
      <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
      </intent-filter>
      </receiver>
    • 动态注册

      1
      2
      3
      IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");  
      IncomingSMSReceiver receiver = new IncomingSMSReceiver();
      registerReceiver(receiver, filter);
  16. 如何设计开发一个图片轮播组件?简述要点或写代码。

    1. 整个组件采用ViewPager

    2. 适配器继承自PagerAdapter

    3. 重写getCount(),isViewFromObject(View arg0, Object arg1),destroyItem(ViewGroup container, int position, Object object),instantiateItem(ViewGroup container, int position)四个方法。

      getCount(获取当前界面个数)

      isViewFromObject(判断是否由对象生成页面)

      destroyItem(回收Item)

      instantiateItem(加载Item)

    4. getCount代表返回的条目,要实现无限轮播,这里就要给出一个很大的值,我们可以采Integer.MAX_VALUE。其他的和普通ViewPager开发一样,在isViewFromObject返回arg0 == arg1,在destroyItem中摧毁滑出的View,container.removeView((View) object),在instantiateItem中添加对应的item,记得添加item,container.addView(child)。里面的postion都要做取余处理,避免数组越界。

    5. 最后,可以使用一个handler实现自动轮播,重写onTouchEvent来对自动轮播控制。

  17. Kotlin中协程和线程的区别?

    1. 线程
      • 线程的目的是为了提高CPU的资源使用率,使多个任务可以并行运行,是服务于机器的。线程的调度是系统来完成的,一般是抢占式的,根据优先级来分配
    2. 协程
      • 协程的目的是为了让多个任务之间更好的协作,是服务于人的。协程为了确保代码逻辑是顺序,所以调度是由开发者来定制的
  18. 从架构图看,android分为几个层?

    • 5层
      1. :Linux Kernel(Linux内核)
      2. Hardware Abstraction Layer(硬件抽象层)
      3. Libraries(系统运行库或者是c/c++ 核心库)
      4. Application Framework(开发框架包 )
      5. Applications(核心应用程序)

    img

  19. VideoView

    • 不可以控制大小(这里的大小就是指View的大小,给他设置高宽是不会生效的)
    • VideoView实际的尺寸可能并不是这个尺寸设置的大小. VideoView在测量自身的尺寸时会依据视频的真实尺寸来调整自己的大小。
  20. 使用SimpleAdapter作为 ListView的适配器,行布局中支持下列哪些组件?

    • 实现Checkable接口的View
    • TextView
    • ImageView
  21. 如何在任意位置关掉应用所有Activity & 如何在任意位置关掉指定的Activity?

  22. Activity任务栈是什么?在项目中有用到它吗?说给我听听

  23. 什么情况下Activity不走onDestory?

    • System.exit(0)(使用此方法来退出应用时,是不会触发onDestory)
    • 栈里面的第一个没有销毁的activity会执行onDestroy方法,其他的不会执行(从MainActivity跳转到activity-A(或者继续从activity-A再跳转到activity-B),这时候,从后台强杀,只会执行mainActivity的onDestroy方法,activity-A(以及activity-B)的onDestroy方法都不会执行)
  24. 什么情况下Activity会单独执行onPause?

    • 当Activity被一个透明的Dialog或者别的东西覆盖时,此时它依然与窗口管理器依然保持连接,系统继续维护其内部状态,所以它仍然可见,但它已经失去了焦点故不可与用户交互,所以被覆盖的Activity并不会执行onStop()方法,只会执行onPause
  25. 隐式 Intent 和 显式 Intent

    • 使用显式Intent时,我们需要指定启动那一个Activity
    • 使用隐式Intent时,只用告诉系统想做什么,系统会自动的找到符合的Activity来启动
  26. 什么是 Loader ?

  27. 什么是 NDK ,为什么它是有用的?

  28. 如何理解严格模式(StrictMode)

  29. 什么是 Lint ?它的用途是什么?

  30. ListView 和 RecyclerView 有什么区别?

  31. 如何理解上下文(Context)。怎么使用它?

  32. 为什么 Bundle 被用来传递数据,为什么不能使用简单的 HashMap 数据结构?

    Bundle本质上也是用ArrayMap来进行存储,所以也就是问为什么要用ArrayMap来进行存储。

    • ArrayMap:适合小数据存储,在数据量较大的时候,性能将退化。
    • HashMap :内部是使用数组+链表的结果,在数据量大的时候性能不错,但在数据小的时候,它的Entry Array比ArrayMap占更多的空间

    在Android中,多数传递都是较小的数据,所以使用Bundle (ArrayMap)更好。而且如果使用Intent来传递数据,Bundle的Parcelable序列化比HashMap 的Serializable性能更好

  33. 如何理解 Android 的 Dialog ?

    • 要在Activity中创建一个Dialog,可以在onCreate中调用showDialog(id),之后会回调onCreateDialog(int id,Bundle rags)这里返回的id就是showDiolog中传入的id,用来表示Dialog,之后就来在onCreateDialog中创建你自己的Dialog。最后还会调用onPrepareDialog(),之后就创建完毕。下次在调用(当前Activity不销毁)showDialog就不会允许onCreatesDialog,只会调用onPrepareDoalog
  34. 什么是 ViewGroup ,它与 View 的区别在哪里?

  35. 谈谈 Serializable 接口和 Parcelable 接口的区别。在 Android 中最好使用哪种接口?

  36. 当 Bitmap 占用较多内存时,你是怎么处理的?

  37. AsyncTask 的生命周期和(它所属的) Activity 的生命周期有什么关系?这种关系可能会导致什么样的问题? 如何避免这些问题发生?

  38. 什么是 NDK ,为什么它是有用的?

  39. 如何理解严格模式(StrictMode)

  40. 什么是 SurfaceView ?

  41. 你知道什么是视图树(View Tree)吗?怎样优化它的深度?

  42. 阐述一下 Android 中的 HashMap , ArrayMap 和 SparseArray

  43. 阐述一下 Looper, Handler 和 HandlerThread