Android 面试题

  • 什么是应用程序?

    • Android 中的 Application 类是 Android 应用中的基类,其中包含所有其他组件(例如 Activity 和服务)。在创建应用/软件包的进程时,Application 类或 Application 类的任何子类都会在任何其他类之前实例化。
  • 什么是 Context?

    • 上下文是系统的句柄;它提供诸如解析资源、获取数据库和首选项的访问权限等服务。Android 应用程序具有活动。上下文就像是应用程序当前运行的环境的句柄。
      应用程序上下文:此上下文与应用程序的生命周期相关联。当您需要生命周期与当前上下文分开的上下文,或者将上下文传递到活动范围之外时,可以使用应用程序上下文。
      活动上下文:此上下文在活动中可用。此上下文与活动的生命周期相关联。当您需要在活动范围内传递上下文,或者需要生命周期附加到当前上下文的上下文时,应该使用活动上下文。
  • 什么是 ABI 管理?

    • 不同的 Android 手机使用不同的 CPU,而 CPU 又支持不同的指令集。每种 CPU 和指令集组合都有自己的应用程序二进制接口 (ABI)。ABI 非常精确地定义了应用程序的机器代码在运行时应该如何与系统交互。您必须为希望应用程序使用的每种 CPU 架构指定一个 ABI。您可以在此处查看完整规格
  • 为什么字节码不能在Android中运行?

    • Android 使用 DVM(Dalvik 虚拟机)而不是 JVM(Java 虚拟机)。
  • Gradle 中的 BuildType 是什么?它有什么用途?

    • 构建类型定义了 Gradle 在构建和打包 Android 应用时使用的属性。
    • 构建类型定义模块的构建方式,例如是否运行 ProGuard。
    • 产品风格定义了构建的内容,例如构建中包含哪些资源。
    • Gradle 为项目产品风格和构建类型的每种可能组合创建一个构建变体。
  • 解释一下Android中的构建过程:

    • 第一步是使用 aapt(Android 资产打包工具)工具编译资源文件夹 (/res)。这些文件被编译为一个名为 R.java 的类文件。这是一个只包含常量的类。
    • 第二步,javac 将 java 源代码编译为 .class 文件,然后通过 sdk 'tools' 中包含的“dx”工具将类文件转换为 Dalvik 字节码。输出为 classes.dex。
    • 最后一步涉及 android apkbuilder,它接受所有输入并构建 apk(android 打包密钥)文件。
  • 什么是Android应用程序架构?

    • Android 应用程序架构具有以下组件:
      a。活动 - 提供应用程序绘制其 UI 的窗口
      b。服务 - 它将执行后台功能
      c。意图 - 它将执行活动之间的互连和数据传递机制
      d。资源外部化 - 字符串和图形
      e。通知 - 灯光、声音、图标、通知、对话框和提示
      f。内容提供商 - 它将与应用程序之间共享数据
  • Android中的Manifest文件和R.java文件是什么?

    • 清单:每个应用程序的根目录中都必须有一个 AndroidManifest.xml 文件(具有该名称)。清单向 Android 系统提供有关应用程序的基本信息,这些信息是系统在运行任何应用程序代码之前必须拥有的信息。它包含您的软件包的信息,包括应用程序的组件,例如活动、服务、广播接收器、内容提供商等。
    • R.Java:它是由 aapt(Android Asset Packaging Tool)自动生成的文件,其中包含 res/ 目录下所有资源的资源 ID。
  • 描述活动

    • 活动基本上是用户界面的容器或窗口。
  • 活动的生命周期

    • OnCreate():这是视图首次创建时的情况。这通常是我们创建视图、从包中获取数据等的地方。
    • OnStart():当 Activity 对用户可见时调用。如果 Activity 转到前台,则调用 onResume();如果 Activity 隐藏,则调用 onStop()。
    • OnResume():当 Activity 开始与用户交互时调用。此时,您的 Activity 位于 Activity 堆栈的顶部,用户输入将发送到该 Activity。
    • OnPause():当活动进入后台但尚未被终止时,作为活动生命周期的一部分进行调用。
    • OnStop():当您不再对用户可见时调用。
    • OnDestroy():活动结束时调用
    • OnRestart():在您的活动停止之后、再次启动之前调用
  • onCreate() 和 onStart() 有什么区别?

    • onCreate() 方法在 Activity 生命周期中被调用一次,要么在应用程序启动时,要么在 Activity 被销毁然后重新创建时(例如在配置更改期间)。
    • 每当 Activity 对用户可见时,就会调用 onStart() 方法,通常在 onCreate() 或 onRestart() 之后。
  • 在什么情况下活动只会调用 onDestroy 而没有 onPause() 和 onStop()?

    • 如果在 Activity 的 OnCreate 方法中调用了 finish(),系统将直接调用 onDestroy() 方法。
  • 为什么要在 Activity 类的 onCreate() 中执行 setContentView() ?

    • 由于 Activity 的 onCreate() 仅被调用一次,因此大多数初始化都应在此进行。在 onResume() 或 onStart()(被调用多次)中设置内容效率低下,因为 setContentView() 是一项繁重的操作。
  • 活动中的 onSavedInstanceState() 和 onRestoreInstanceState() ?

    • OnRestoreInstanceState()- 当 Activity 在之前被销毁后被重新创建时,我们可以从系统传递给 Activity 的 Bundle 中恢复已保存的状态。onCreate()onRestoreInstanceState()回调方法都接收包含实例状态信息的同一个 Bundle。但是,由于onCreate()无论系统是在创建 Activity 的新实例还是重新创建上一个实例,都会调用该方法,因此您必须在尝试读取状态 Bundle 之前检查它是否为空。如果为空,则系统正在创建 Activity 的新实例,而不是恢复上一个被销毁的实例。
    • onSaveInstanceState()- 是一种在暂停活动之前存储数据的方法。
  • Android 中的启动模式?

    • 标准:在启动活动的任务中创建一个新的活动实例。可以创建活动的多个实例,并且可以将多个实例添加到相同或不同的任务中。
      • 示例:假设有一个活动堆栈 A -> B -> C。现在,如果我们以启动模式“标准”再次启动 B,则新的堆栈将是 A -> B -> C -> B。
    • SingleTop:它与标准相同,但如果堆栈顶部存在活动的前一个实例,则它不会创建新实例,而是将意图发送给活动的现有实例。
      • 例子:假设有一个 Activity 堆栈为 A -> B,现在我们以“singleTop”启动 C,新的堆栈就会像往常一样变成 A -> B -> C。
      • 现在如果有一个活动堆栈 A -> B -> C。如果我们以启动模式“singleTop”再次启动 C,新的堆栈仍然是 A -> B -> C。
    • SingleTask:始终会创建一个新任务,并将新实例推送到该任务作为根实例。因此,如果活动已在任务中,则意图将重定向到 onNewIntent(),否则将创建一个新实例。一次只会存在一个活动实例。
      • 例子:假设有一个活动堆栈 A -> B -> C -> D 。现在如果我们以启动模式“singleTask”启动 D ,新的堆栈将像往常一样是 A -> B -> C -> D 。
      • 现在假如有一个活动堆栈 A -> B -> C -> D。如果我们再次以启动模式“singleTask”启动活动 B,则新的活动堆栈将为 A -> B。活动 C 和 D 将被销毁。
    • SingleInstance:与单任务相同,但系统不会在与此活动相同的任务中启动任何活动。如果启动了新活动,则会在单独的任务中启动。
      • 例如:假设有一个 Activity 堆栈 A -> B -> C -> D。如果我们再次启动 Activity B,并以启动模式为“singleTask”,则新的 Activity 堆栈将是:
      • 任务 1 — A -> B -> C 和任务 2 — D
  • 当用户旋转屏幕时,Activity 如何响应?

    • 当屏幕旋转时,当前的 Activity 实例将被销毁,并在新的方向创建新的 Activity 实例。屏幕旋转时,首先调用 onRestart() 方法。其他生命周期方法的调用流程与首次创建 Activity 时类似。
  • 如何防止屏幕旋转时数据重新加载和重置?

    • 目前最常见的方法是结合使用 ViewModel 和 onSaveInstanceState()。那么我们该怎么做呢?
    • ViewModel基础知识:ViewModel 具有生命周期感知能力。换句话说,如果 ViewModel 的所有者因配置更改(例如旋转)而被销毁,则 ViewModel 不会被销毁。所有者的新实例将重新连接到现有的 ViewModel。因此,如果您旋转某个 Activity 三次,您就创建了三个不同的 Activity 实例,但您只有一个 ViewModel。
    • 因此,常见的做法是将数据存储在 ViewModel 类中(因为它在配置更改期间保留数据)并使用 OnSaveInstanceState 存储少量 UI 数据。
    • 例如,假设我们有一个搜索屏幕,并且用户在 Edittext 中输入了一个查询。这会导致在 RecyclerView 中显示项目列表。现在,如果屏幕旋转,防止数据重置的理想方法是将搜索项目列表存储在 ViewModel 中,并将用户在活动的 OnSaveInstanceState 方法中输入的查询文本存储在其中。
  • 提及两种在使用 Intent 调用新 Activity 时清除 Activity 返回堆栈的方法

    • 第一种方法是使用 FLAG_ACTIVITY_CLEAR_TOP 标志。第二种方法是结合使用 FLAG_ACTIVITY_CLEAR_TASK 和 FLAG_ACTIVITY_NEW_TASK。
  • FLAG_ACTIVITY_CLEAR_TASK 和 FLAG_ACTIVITY_CLEAR_TOP 有什么区别?

    • FLAG_ACTIVITY_CLEAR_TASK用于清除任务中的所有活动,包括调用的类的任何现有实例。通过 Intent 启动的活动将成为原本为空的任务列表的新根。此标志必须与 FLAG_ACTIVITY_NEW_TASK 结合使用。
    • 另一方面,如果设置了FLAG_ACTIVITY_CLEAR_TOP ,并且任务列表中存在此 Activity 的旧实例,则除非删除所有其他活动,并且该旧活动将成为任务列表的根。否则,如果没有该活动的实例,则将其新实例作为任务列表的根。结合使用 FLAG_ACTIVITY_NEW_TASK 是一种很好的做法,但不是必需的。
  • 描述内容提供商

    • ContentProvider 可在收到请求时将数据从一个应用程序提供给另一个应用程序。它管理对结构化数据集的访问。它提供定义数据安全性的机制。ContentProvider 是将一个进程中的数据与另一个进程中运行的代码连接起来的标准接口。
    • 当您想要访问ContentProvider中的数据时,您必须使用应用程序上下文中的 ContentResolver 对象作为客户端与提供程序进行通信。提供程序对象接收来自客户端的数据请求、执行请求的操作并返回结果。
  • 使用内容提供程序访问数据:

    • 首先确保您的 Android 应用具有必要的读取访问权限。然后,通过在 Context 对象上调用 getContentResolver() 来获取对 ContentResolver 对象的访问权限,并使用 ContentResolver.query() 构建查询来检索数据。
    • ContentResolver.query() 方法返回一个 Cursor,因此您可以使用 Cursor 方法从每一列中检索数据。
  • 描述服务

    • 服务是一种可以在后台执行长时间运行的操作的应用组件,它不提供用户界面。即使用户未与您的应用交互,它也可以运行在后台。以下是三种不同类型的服务:
      • 前台服务:前台服务执行一些用户可察觉的操作。例如,我们可以使用前台服务播放音轨。必须向用户显示通知。
      • 后台服务:后台服务执行用户不会直接注意到的操作。在 Android API 级别 26 及更高版本中,使用后台服务受到限制,建议在这些情况下使用WorkManager 。
      • 绑定服务:当应用程序组件通过调用 bindService() 绑定到服务时,服务即被绑定。绑定服务提供客户端-服务器接口,允许组件与服务交互、发送请求、接收结果。绑定服务仅在另一个应用程序组件绑定到它时运行。
  • Service 与 Intent Service 之间的区别

    • Service是 Android 服务的基类,可以对其进行扩展以创建任何服务。直接扩展 Service 的类在主线程上运行,因此它将阻塞 UI(如果有),因此应仅用于短任务,或应使用其他线程来执行较长的任务。
    • IntentService是 Service 的一个子类,可按需处理异步请求(表示为“Intent”)。客户端通过 startService(Intent) 调用发送请求。服务根据需要启动,使用工作线程依次处理每个 Intent,并在完成工作时自行停止。
  • AsyncTasks 和 Threads 之间有什么区别?

    • 应该使用线程将长时间运行的操作与主线程分开,以提高性能。但它无法优雅地取消,也无法处理 Android 的配置更改。您无法从线程更新 UI。
    • AsyncTask可用于处理持续时间短于 5ms 的工作项。使用 AsyncTask,您可以更新 UI,而不像 Java Thread。但许多长时间运行的任务会阻碍性能。
  • Service、Intent Service、AsyncTask 和线程之间的区别

    • Android 服务是用于在后台执行操作(例如播放音乐)的组件。它没有任何 UI(用户界面)。即使应用程序被销毁,服务也会无限期地在后台运行。
    • AsyncTask允许您在用户界面上执行异步工作。它在工作线程中执行阻塞操作,然后在 UI 线程上发布结果,而无需您自己处理线程和/或处理程序。
    • IntentService是服务的一个基类,可按需处理异步请求(以 Intent 表示)。客户端通过 startService(Intent) 调用发送请求;服务根据需要启动,使用工作线程依次处理每个 Intent,并在完成工作时自行停止。
    • 线程是程序中的单一顺序控制流。线程可以被认为是在主进程内运行的微型进程
  • 什么是处理程序?

    • 处理程序是用于管理线程的对象。它接收消息并编写有关如何处理消息的代码。它们在 Activity 的生命周期之外运行,因此需要正确清理它们,否则会出现线程泄漏。
    • 处理程序允许后台线程和主线程之间的通信。
    • 当我们需要每隔 x 秒/分钟重复执行后台任务时,Handler 类是首选。
  • 什么是作业调度?

    • Job Scheduling api,顾名思义,允许安排作业,同时让系统根据内存、电源和连接条件进行优化。
    • JobScheduler 支持批量调度作业。Android 系统可以合并作业,从而减少电池消耗。JobManager 可以自动处理网络不可靠性,从而使上传处理更加轻松。它还可以在应用程序重启后继续运行。
    • 场景:
      • 设备连接到电源后应执行的任务
      • 需要网络访问或 Wi-Fi 连接的任务。
      • 非关键任务或非用户面对的任务
      • 应定期批量运行的任务,且时间安排并不严格
      • 参考
  • AsyncTask 的生命周期和 Activity 之间有什么关系?这会导致什么问题?如何避免这些问题?

    • AsyncTask 不依赖于包含它的 Activity 的生命周期。因此,例如,如果您在 Activity 内启动 AsyncTask,并且用户旋转设备,则 Activity 将被销毁(并将创建一个新的 Activity 实例),但 AsyncTask 不会消失,而是继续存在直到完成。
    • 然后,当 AsyncTask 完成时,它不会更新新 Activity 的 UI,而是更新 Activity 的前一个实例(即,创建该 Activity 时但不再显示的实例!)。这可能会导致异常(如果您使用 findViewById 等来检索 Activity 内的视图,则类型为 java.lang.IllegalArgumentException:View not attachment to window manager)。
    • 这也可能会导致内存泄漏,因为 AsyncTask 保留对 Activity 的引用,只要 AsyncTask 保持活动状态,就会阻止 Activity 被垃圾收集。
    • 出于这些原因,使用 AsyncTasks 执行长时间运行的后台任务通常不是一个好主意。相反,对于长时间运行的后台任务,应该采用不同的机制(例如服务)。
    • 注意:AsyncTasks 默认使用串行执行器在单个线程上运行,这意味着它只有 1 个线程并且每个任务一个接一个地运行。
  • onTrimMemory() 方法是什么?

    • onTrimMemory():当操作系统确定某个进程应该从其进程中移除不需要的内存时调用。例如,当进程进入后台并且没有足够的内存来维持所需的后台进程运行时,就会发生这种情况。
    • Android 可以通过多种方式从您的应用中回收内存,或者在必要时完全终止您的应用,以释放内存用于关键任务。为了帮助平衡系统内存并避免系统需要终止您的应用进程,您可以ComponentCallbacks2在 Activity 类中实现该接口。提供的 onTrimMemory() 回调方法允许您的应用在前台或后台监听内存相关事件,然后释放对象以响应应用生命周期或指示系统需要回收内存的系统事件。参考
  • Android 绑定服务

    • 绑定服务是一种允许其他 Android 组件(如活动)绑定到它并发送和接收数据的服务。绑定服务不仅可以由与本地服务在同一进程中运行的组件使用,而且在不同进程中运行的活动和服务也可以绑定到它并发送和接收数据。
    • 在实现绑定服务时,我们必须扩展 Service 类,但也必须重写 onBind 方法。此方法返回一个实现 IBinder 的对象,可用于与服务进行交互。
    • 使用 Android Messenger 实现 Android 绑定服务
    • 基于 Messenger 的服务可以与不同进程中的其他组件进行通信,这称为进程间通信 (IPC),而无需使用 AIDL。
    • 服务处理程序:此组件处理与服务本身交互的客户端的传入请求。
    • Messenger:此类用于创建实现 IBinder 接口的对象,以便客户端可以与服务进行交互。
    • 示例实现:链接
  • AIDL 与 Messenger 队列

    • AIDL 适用于需要进行应用程序级通信以进行数据和控制共享的情况,描述它的场景可以是:一个应用程序需要来自“联系人”应用程序的所有联系人的列表(内容部分位于此处),此外它还希望显示通话时长,您还可以将其与该应用程序断开连接(控制部分位于此处)。
    • 在 Messenger 队列中,您更多地进入应用程序并使用线程和进程来管理包含消息的队列,因此这里不会受到外部服务的干扰。
    • 如果您想绑定远程服务(例如在另一个进程中运行),则需要 Messenger。
  • 什么是线程池?它比使用多个单独的线程更有效吗?

    • 创建和销毁线程会占用很高的 CPU 空间,因此当我们需要同时执行大量小而简单的任务时,创建自己的线程的开销会占用相当一部分 CPU 周期,并严重影响最终的响应时间。
    • ThreadPool 由一个任务队列和一组工作线程组成,这使得它能够运行一个任务的多个并行实例。
  • Serializable 和 Parcelable 之间的区别?

    • Serializable 是一个标准 Java 接口。Parcelable 是一个 Android 特定接口,您可以自行实现序列化。它被设计为比 Serializable 更高效(这种方法的问题在于使用了反射,并且处理速度很慢。这种机制还倾向于创建大量临时对象并导致大量垃圾收集。)
    • 序列化 序列化是将对象转换为字节流的过程,以便将对象存储到内存中,以便可以在以后重新创建它,同时仍然保留对象的原始状态和数据。
    • 如何禁止序列化?我们可以将变量声明为瞬态。
  • 活动与服务之间的区别

    • 活动基本上是用户界面的容器或窗口。服务是用于在后台执行操作的组件。它没有 UI。
  • 如何从后台服务更新 Activity 的 UI

    • 我们需要在活动中注册一个 LocalBroadcastReceiver。并使用来自后台服务的意图发送带有数据的广播。只要活动处于前台,UI 就会从后台更新。确保在活动的 onStop() 方法中取消注册广播接收器,以避免内存泄漏。我们还可以注册一个 Handler 并使用 Handler 传递数据。我已经详细介绍了一个示例实现。您可以在此处查看
  • 什么是意图?

    • Intent 是可用于向 Android 各个组件传递信息的消息。例如,启动活动、打开 webview 等。
    • 两种意图-
      • 隐式:隐式意图是当您调用系统默认意图时,例如发送电子邮件、发送短信、拨号。
      • 显式:显式意图是当您从同一应用程序的另一个活动调用一个应用程序活动时。
  • 什么是粘性意图?

    • Sticky Intents 允许功能和服务之间的通信。
    • sendStickyBroadcast()执行称为粘性的 sendBroadcast(Intent),即,您发送的 Intent 在广播完成后仍然存在,以便其他人可以通过的返回值快速检索该数据registerReceiver(BroadcastReceiver, IntentFilter)
    • 例如,如果您采用 ACTION_BATTERY_CHANGED 的意图来获取电池变化事件:当您为该操作调用 registerReceiver() 时 - 即使 BroadcastReceiver 为空 - 您将获得该操作最后一次广播的 Intent。因此,您可以使用它来查找电池的状态,而不必注册电池中所有未来的状态变化。
  • 什么是待定意图?

    • 如果您希望某人在未来的时间点代表您执行任何 Intent 操作,那么我们将使用 Pending Intent。
  • 什么是动作?

    • 意图描述。例如,ACTION_CALL - 用于执行调用
  • 什么是意图过滤器?

    • 指定活动/服务可以响应的意图类型。
  • 描述片段:

    • Fragment 是附加到 Activity 的 UI 实体。Fragment 可以通过附加到不同的 Activity 中来重复使用。Activity 可以附加多个 Fragment。Fragment 必须附加到 Activity,并且其生命周期将取决于其宿主 Activity。
  • 描述片段生命周期

    • onAttach():片段实例与活动实例相关联。片段和活动尚未完全初始化。通常,您会在此方法中获得对使用该片段进行进一步初始化工作的活动的引用。
    • onCreate():系统在创建 fragment 时调用此方法。您应该初始化 fragment 的基本组件,以便在 fragment 暂停或停止,然后恢复时保留这些组件。
    • onCreateView():当 Fragment 第一次绘制其用户界面时,系统会调用此回调。要为 Fragment 绘制 UI,您必须从此方法返回一个 View 组件,该组件是 Fragment 布局的根。如果 Fragment 未提供 UI,则可以返回 null。
    • onActivityCreated():当创建主机活动时,onActivityCreated() 在 onCreateView() 方法之后被调用。活动和片段实例以及活动的视图层次结构都已创建。此时,可以使用 findViewById() 方法访问视图。示例。在此方法中,您可以实例化需要 Context 对象的对象
    • onStart():一旦 fragment 变得可见,就会调用 onStart() 方法。
    • onResume():片段变为活跃状态。
    • onPause():系统调用此方法作为用户离开片段的第一个迹象。这通常是您应提交应在当前用户会话之后保留的任何更改的地方。
    • onStop():通过调用 onStop() 来停止 Fragment
    • onDestroyView():调用此方法后 Fragment 视图将被销毁
    • onDestroy():调用来对片段的状态进行最终清理,但是不保证会被 Android 平台调用。
  • 片段和活动有什么区别?解释一下两者之间的关系。

    • Activity 是一个应用程序组件,它提供一个屏幕,用户可以与之交互来执行某些操作,而 Fragment 表示 Activity 中的一种行为或用户界面的一部分(具有自己的生命周期和输入事件,可以随意添加或删除)。
  • 什么时候应该使用片段而不是活动?

    • 当有 UI 组件将在多个活动中使用时。
    • 当有多个视图可以并排显示时(viewPager tabs)
    • 当你有需要在 Activity 重启后保留的数据(例如保留的 Fragment)时
  • 在后台堆栈中添加/替换片段有什么区别?

    • replace删除现有 fragment 并添加新 fragment。这意味着当您按下返回按钮时,被替换的 fragment 将被创建,并且其 onCreateView 将被调用。
    • add保留现有片段并添加新片段,这意味着现有片段将处于活动状态,并且它们不会处于“暂停”状态,因此当按下后退按钮时,不会为现有片段(在添加新片段之前存在的片段)调用 onCreateView。
    • 在fragment的生命周期事件中,onPause、onResume、onCreateView等生命周期事件在replace时会被调用,但在add时不会被调用。
  • 为什么建议仅使用默认构造函数来创建 Fragment?

    • 您应该通过 bundle 传递参数的原因是,当系统恢复片段时(例如,配置更改时),它会自动恢复您的 bundle。这样,您就可以保证将片段的状态正确地恢复到片段初始化时的状态。
  • 您正在用另一个 Fragment 替换一个 Fragment — 如何确保用户可以通过按“返回”按钮返回到前一个 Fragment?

    • 我们需要通过调用事务addToBackStack()之前的操作将每个 Fragment 事务保存到后台堆栈中commit()
  • 将片段添加到返回堆栈期间以及从返回堆栈弹出时调用的回调:

    • addOnBackStackChangedListener在片段被添加或从后栈移除时调用。请使用此链接作为参考
  • 什么是保留碎片

    • 默认情况下,当配置发生变化时,Fragment 会与其父 Activity 一起被销毁并重新创建。调用setRetainInstance(true)可让我们绕过此销毁和重新创建循环,在重新创建 Activity 时向系统发出信号以保留 Fragment 的当前实例。
  • FragmentPagerAdapter 和 FragmentStatePagerAdapter 之间的区别?

    • FragmentPagerAdapter:用户访问的每个页面的片段都将存储在内存中,尽管视图将被销毁。因此,当页面再次可见时,将重新创建视图,但不会重新创建片段实例。这可能会导致使用大量内存。当我们需要将整个片段存储在内存中时,应该使用 FragmentPagerAdapter。FragmentPagerAdapter 调用detach(Fragment)事务而不是remove(Fragment)
    • FragmentStatePagerAdapter:当 Fragment 实例对用户不可见时(除了 Fragment 的已保存状态),该实例将被销毁。这样只会使用少量内存,并且可用于处理较大的数据集。当我们必须使用动态 Fragment(如带有小部件的 Fragment)时,应该使用它,因为它们的数据可以存储在 savedInstanceState 中。而且,即使有大量 Fragment,它也不会影响性能。
  • Android 中的 Toast 是什么?

    • Android Toast 可用于在短时间内显示信息。Toast 包含要快速显示的消息,并在一段时间后消失。
  • Android 中的 Loader 是什么?

    • Loader API 于 API 级别 11 中引入,用于从数据源加载数据以显示在 Activity 或 Fragment 中。Loader 会在配置更改后保留并缓存结果,以防止重复查询。
    • 示例实现
  • Dialog 和 DialogFragment 有什么区别?

    • 一个显示对话框窗口的 F​​ragment,该对话框窗口浮动在其 Activity 窗口之上。此 Fragment 包含一个对话框对象,它会根据 Fragment 的状态适当地显示该对象。对话框完全依赖于 Activity。如果屏幕旋转,对话框将被关闭。对话框 Fragment 还会处理方向和配置更改。
  • 边距和填充之间的区别?

    • Padding 是容器内部添加的空间,例如,如果是按钮,padding 是按钮内部添加的空间。Margin 是容器外部添加的空间。
  • 什么是视图组?它们与视图有何不同?

    • View:View 对象是 Android 中用户界面 (UI) 元素的基本构建块。View 是一个简单的矩形框,可响应用户的操作。例如 EditText、Button、CheckBox 等。View 指的是类android.view.View,它是所有 UI 类的基类。
    • ViewGroup : ViewGroup 是不可见的容器。它包含 View 和 ViewGroup。例如,LinearLayout 是包含 Button(View) 的 ViewGroup,也包含其他 Layout。ViewGroup 是 Layouts 的基类。
  • 常规 .png 和九宫格图像之间有什么区别?

    • 它是可调整大小的位图资源之一,可用作设备上的背景或其他图像。NinePatch 类允许在九个部分中绘制位图。四个角未缩放;图像的中间在两个轴上缩放,四个边缘在一个轴上缩放。
  • RelativeLayout 和 LinearLayout 之间的区别?

    • 线性布局- 垂直或水平排列元素,即按行或列排列。
    • 相对布局- 相对于父元素或其他元素排列元素。
  • 什么是 ConstraintLayout?

    • 它允许您创建具有平面视图层次结构(无嵌套视图组)的大型复杂布局。它与 RelativeLayout 类似,所有视图都根据同级视图与父布局之间的关系进行布局,但它比 RelativeLayout 更灵活,并且更易于与 Android Studio 的布局编辑器一起使用。
    • 示例实现
    • 您可以在此处阅读有关如何使用 ConstraintLayout 实现简单应用程序的更多信息,由我撰写 :)
  • 何时可能使用 FrameLayout?

    • 框架布局旨在包含单个项目,因此当您需要显示单个视图时,它们是一种有效的选择。
    • 如果您将多个视图添加到 FrameLayout,那么它会将它们一个堆叠在另一个之上,因此如果您需要重叠视图,FrameLayouts 也很有用,例如,如果您正在实现覆盖或 HUD 元素。
  • 什么是适配器?

    • 一个适配器负责将每个数据条目转换为一个视图,然后可以将其添加到AdapterView(ListView/RecyclerView)中。
  • 如何支持不同屏幕尺寸?

    • 创建灵活的布局 - 创建适用于不同屏幕尺寸的响应式布局的最佳方法是使用 ConstraintLayout 作为 UI 中的基础布局。ConstraintLayout 允许您根据布局中与其他视图的空间关系指定每个视图的位置和大小。这样,所有视图都可以随着屏幕尺寸的变化一起移动和拉伸。
    • 创建可拉伸的九宫格位图
    • 避免硬编码布局大小 - 使用 wrap_content 或 match_parent。创建替代布局 - 应用应提供替代布局,以针对特定屏幕尺寸优化 UI 设计。例如:平板电脑的不同 UI
    • 使用最小宽度限定符。例如,您可以创建一个名为 main_activity 的布局,该布局针对手机和平板电脑进行了优化,方法是在目录中创建该文件的不同版本,如下所示:
      • res/layout/main_activity.xml # 适用于手机(可用宽度小于 600dp)
      • res/layout-sw600dp/main_activity.xml # 适用于 7 英寸平板电脑(宽度 600dp 及更大)。
      • 最小宽度限定符指定屏幕两侧中最小的一侧,而不管设备当前的方向如何,因此它是指定可用于布局的整体屏幕尺寸的简单方法。
  • 概述创建自定义视图的过程:

    • 创建一个类,该类是视图的子类
    • 创建一个 res/values/attrs.xml 文件并声明您想要在自定义视图中使用的属性。
    • 在您的 View 类中,添加一个构造函数方法,实例化 Paint 对象,并检索您的自定义属性。
    • 覆盖 onSizeChanged() 或 onMeasure()。
    • 通过重写 onDraw() 来绘制你的视图。
    • 示例实现
  • 简要描述一些可以优化 View 使用的方法

    • 检查过度透支:在 Android 设备上安装您的应用,然后启用“调试 GPU 概览”选项。
    • 展平视图层次结构:使用 Android Studio 的“层次结构查看器”工具检查视图层次结构。
    • 测量每个视图完成测量、布局和绘制阶段所需的时间。您还可以使用 Hierarchy Viewer 来识别需要优化的渲染管道部分。
  • Android 中的位图池?

    • 位图池是一种简单的技术,旨在重复使用位图,而不是每次都创建新的位图。当您需要位图时,您可以检查位图堆栈以查看是否有可用的位图。如果没有可用的位图,则创建一个新的位图,否则从堆栈中弹出一个位图并重复使用它。然后,当您使用完位图后,您可以将其放入堆栈中。在此处查找更多信息
  • 如何将位图加载到内存?

  • Android 中的权限保护级别有哪些?

    • 普通- 风险较低的权限,允许请求权限的应用访问独立的应用级功能,对其他应用、系统或用户的风险极小。系统会在安装时自动向请求权限的应用授予此类权限,而无需征求用户的明确批准。
    • 危险- 风险较高的权限。应用程序请求的任何危险权限都可能向用户显示,并要求用户确认后才能继续,或者可以采取其他方法避免用户自动允许使用此类设施。
    • 签名- 仅当请求权限的应用程序使用与声明权限的应用程序相同的证书进行签名时,系统才会授予该权限。如果证书匹配,系统将自动授予权限,而无需通知用户或征求用户的明确批准。
    • SignatureOrSystem - 系统仅授予 Android 系统映像中的应用程序或使用与声明该权限的应用程序相同的证书签名的应用程序的权限。
  • 什么是应用程序无响应 (ANR) 错误,以及如何防止它发生在应用程序中?

    • 当您的界面超过 5 秒没有响应时,系统会显示 ANR 对话框,这通常是因为您阻塞了主线程。为避免遇到 ANR 错误,您应尽可能将工作移出主线程。
  • Android 中的单例类是什么?

    • 单例类是只能创建一个可由所有其他类共享的对象的类。
    <span style="background-color:var(--bgColor-muted, var(--color-canvas-subtle))"><span style="color:var(--fgColor-default, var(--color-fg-default))"><span style="background-color:var(--bgColor-muted, var(--color-canvas-subtle))"><code>private static volatile RESTService instance;
     protected RESTService(Context context) {
         super(context);
     }
     
     public static RESTService getInstance(Context context) {
     if (instance == null) {
        synchronized (RESTService.class) {
           if (instance == null) instance = new RESTService(context);
             }
         }
         return instance;
     }
    </code></span></span></span>
  • SharedPreferences 中的 commit() 和 apply() 有什么区别?

    • commit()同步写入数据并根据结果立即返回成功或失败的布尔值。
    • apply()是异步的,不会返回任何布尔响应。此外,如果存在未完成的 apply() 并且我们执行另一个 commit()。commit() 将被阻止,直到 apply() 未完成。
  • RecyclerView 如何工作?

    • 让我们首先了解一下 RecyclerView 的背景知识,这对于理解onBindViewHolder()RecyclerView 内部的方法是必不可少的。
    • RecyclerView 旨在显示长列表(或网格)项目。假设您想要显示 100 行内容。一种简单的方法是创建 100 个视图,每行一个,然后将它们全部布局。但这样做会造成浪费,因为在任何时候,屏幕上只能显示 10 个左右的项目,其余项目将不在屏幕上。因此,RecyclerView 只会创建屏幕上的 10 个左右的视图。这样,您的速度和内存使用率将提高 10 倍。
    • 但是当您开始滚动并需要开始显示下一个视图时会发生什么?
      • 同样,一个简单的方法是为您需要显示的每个新行创建一个新视图。但是这样,当您到达列表末尾时,您将创建 100 个视图,并且您的内存使用量将与第一种方法相同。而且创建视图需要时间,所以您的滚动很可能不会很流畅。这就是为什么 RecyclerView 利用了这样一个事实:当您滚动时,新行会出现在屏幕上,而旧行会消失在屏幕上。不是为每个新行创建新视图,而是通过将新数据绑定到旧视图来回收和重用旧视图。
      • 这发生在 onBindViewHolder()方法内部。最初,您将获得新的未使用的视图持有者,并且您必须用要显示的数据填充它们。但是,随着滚动,您将开始获得用于屏幕外行的视图持有者,并且您必须用新数据替换它们所持有的旧数据。
  • RecyclerView 与 ListView 有何不同?

    • ViewHolder 模式:Recyclerview 实现了 ViewHolders 模式,但在 ListView 中这不是强制性的。RecyclerView 在滚动时会回收并重用单元格。
    • 什么是 ViewHolder 模式? - ViewHolder 对象将每个组件视图存储在 Layout 的标签字段内,因此您可以立即访问它们,而无需重复查找它们。在 ListView 中,代码可能会findViewById()在 ListView 滚动期间频繁调用,这会降低性能。即使适配器返回膨胀视图以供回收,您仍然需要查找元素并更新它们。避免重复使用的一种方法findViewById()是使用“视图持有者”设计模式。
    • LayoutManager:在 ListView 中,唯一可用的视图类型是垂直 ListView。RecyclerView 将列表与其容器分离,因此我们可以通过设置 LayoutManager 在运行时轻松地将列表项放入不同的容器(linearLayout、gridLayout)中。
    • 项目动画器:ListViews 缺乏对良好动画的支持,但 RecyclerView 为其带来了全新的维度。
  • 如何在 Android 中实现滑动动画

    <span style="background-color:var(--bgColor-muted, var(--color-canvas-subtle))"><span style="color:var(--fgColor-default, var(--color-fg-default))"><span style="background-color:var(--bgColor-muted, var(--color-canvas-subtle))"><code><set xmlns:android="http://schemas.android.com/apk/res/android"
      android:shareInterpolator="false">
     <translate android:fromXDelta="-100%" android:toXDelta="0%"
              android:fromYDelta="0%" android:toYDelta="0%"
              android:duration="700"/>
     </set>
    </code></span></span></span>

  • Android 中的 Arraymap/SparseArray 与 HashMap 有什么区别?

  • 如何减少 apk 大小?

    • 通过在发布构建类型中添加以下几行来在项目中启用 proguard。
    • 启用 shrinkResources。
    • 通过在“resConfigs”中添加所需资源名称来剥离所有未使用的区域设置资源。
    • 将所有图像转换为 webp 或矢量可绘制图像。
    • 关于该主题的文章
  • 如何减少 Android 应用程序的构建时间?

    • 查看这篇精彩的文章
    • 我从文章中得到的信息是:我们可以向 gradle.properties 文件添加一些命令:
      • org.gradle.configureondemand=true- 此命令将告诉 gradle 仅构建真正需要构建的项目。
      • 使用守护进程 - org.gradle.daemon=true- 守护进程即使在构建完成后也会在后台保持 Gradle 实例的运行。这将消除初始化 Gradle 所需的时间,并显著减少构建时间。
      • org.gradle.parallel=true- 允许 Gradle 并行构建您的项目。如果您的项目中有多个模块,则通过启用此功能,Gradle 可以并行运行独立模块的构建操作。
      • 增加堆大小 - org.gradle.jvmargs=-Xmx3072m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8- 从 android studio 2.0 开始,gradle 在进程中使用 dex 来减少项目的构建时间。通常,在构建应用程序时,多个 dx 进程在不同的 VM 实例上运行。但是从 Android Studio 2.0 开始,所有这些 dx 进程都在单个 VM 中运行,并且该 VM 也与 gradle 共享。这显著减少了构建时间,因为所有 dex 进程都在相同的 VM 实例上运行。但这需要更大的内存来容纳所有 dex 进程和 gradle。这意味着您需要增加 gradle 守护进程所需的堆大小。默认情况下,守护进程的堆大小约为 1GB。
    • 确保不使用动态依赖。即不要使用
      implementation 'com.android.support:appcompat-v7:27.0.+'
      此命令意味着 gradle 每次构建应用程序时都会上线并检查最新版本。
      而是使用固定版本,即'com.android.support:appcompat-v7:27.0.2'
  • Android 架构组件?

  • MVC、MVP 和 MVVM 之间的区别?

    • MVC是模型-视图-控制器架构,其中模型指的是数据模型类。视图指的是 xml 文件,控制器处理业务逻辑。这种架构的问题在于单元测试。由于模型不与任何东西绑定,因此可以轻松测试它。控制器与 android api 紧密耦合,因此很难进行单元测试。由于视图和控制器紧密耦合,因此模块化和灵活性是一个问题。如果我们更改视图,控制器逻辑也应该更改。维护也是一个问题。
    • MVP 架构:Model-View-Presenter 架构。View 包括 xml 和活动/片段类。因此,活动最好实现一个视图接口,以便于单元测试(因为这可以在没有视图的情况下工作)。示例实现
    • MVVM:模型-视图-视图模型架构。模型包括数据、数据处理工具、业务逻辑。视图模型负责包装模型数据并为视图准备数据。它还提供了一个钩子,用于将事件从视图传递到模型。 示例实现

相关推荐

  1. Android 面试

    2024-06-18 10:02:06       23 阅读
  2. Android面试汇总-Handler

    2024-06-18 10:02:06       24 阅读
  3. Android面试汇总-Jetpack组件

    2024-06-18 10:02:06       27 阅读
  4. Android笔试面试AI答之Activity(2)

    2024-06-18 10:02:06       23 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-18 10:02:06       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-18 10:02:06       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-18 10:02:06       82 阅读
  4. Python语言-面向对象

    2024-06-18 10:02:06       91 阅读

热门阅读

  1. WDF驱动开发-注册表项

    2024-06-18 10:02:06       30 阅读
  2. 15.2 测试-网格测试、基准测试与测试覆盖率

    2024-06-18 10:02:06       27 阅读
  3. WPF 布局控件 Grid表格

    2024-06-18 10:02:06       24 阅读
  4. C++值单例模式与auto_ptr

    2024-06-18 10:02:06       29 阅读
  5. MySQL触发器基本结构

    2024-06-18 10:02:06       31 阅读
  6. 从零开始精通Onvif之图片抓拍

    2024-06-18 10:02:06       28 阅读
  7. PHP之EOF定界符

    2024-06-18 10:02:06       26 阅读
  8. 科研辅助工具

    2024-06-18 10:02:06       25 阅读
  9. Unity与Android交互通信系列(6)

    2024-06-18 10:02:06       27 阅读
  10. idea git stash报错Too many revisions specified

    2024-06-18 10:02:06       31 阅读