Android 面试总结

前言

最近准备换工作,梳理和回顾被问及的技术问题和知识点 , 希望能为Android开发者提供有益的参考.

腾讯二面 Aug 1st, 2024

Activity相关

  1. android 中的四大组件

      1. Activities(活动):
      • Activity 是用户与应用程序交互的主要方式之一,代表一个用户界面屏幕。

      • 每个 Activity 都是一个独立的窗口,用于展示用户界面元素和接收用户输入。

      • 应用程序通常由多个 Activity 组成,用户可以在这些 Activity 之间进行切换。

      1. Services(服务):
      • Service 是在后台执行长时间运行操作或处理多次请求的组件,没有用户界面。

      • Service 可以在后台运行,即使用户切换到其他应用程序,Service 也可以继续运行。

      • 可以通过 Service 处理网络请求、播放音乐、执行文件 I/O 等操作。

      1. Broadcast Receivers(广播接收器):
      • Broadcast Receiver 是用于接收系统广播消息或应用程序内部广播消息的组件。

      • 可以监听系统事件或应用程序内部的事件,并在事件发生时做出响应。

      • 例如,可以通过 Broadcast Receiver 接收系统启动完成的广播、电量低警报等。

      1. Content Providers(内容提供器):
      • Content Provider 用于管理应用程序的数据,并提供数据给其他应用程序。

      • 可以通过 Content Provider 将应用程序的数据共享给其他应用程序,实现数据共享和访问。

      • Content Provider 可以用于访问应用程序内部的数据库、文件等数据。

  2. activity的启动模式

    • standard:标准启动模式(默认启动模式),每次都会启动一个新的 activity 实例;

    • singleTop:单独使用使用这种模式时,如果 Activity 实例位于当前任务栈顶,就重用栈顶实例,而不新建,并回调该实例 onNewIntent() 方法,否则走新建流程;

    • singleTask:这种模式启动的 Activity 只会存在相应的 Activity 的 taskAffinit 任务栈中,同一时刻系统中只会存在一个实例,已存在的实例被再次启动时,会重新唤起该实例,并清理当前 Task 任务栈该实例之上的所有 Activity,同时回调 onNewIntent() 方法;

    • singleInstance:这种模式启动的 Activity 独自占用一个 Task 任务栈,同一时刻系统中只会存在一个实例,已存在的实例被再次启动时,只会唤起原实例,并回调 onNewIntent() 方法;

      • singleInstance 的属性是禁止与其他 Activities 共享任务栈,所以启动模式为 SingleInstance 的 Activity 启动其他 Activity 时会默认带有 FLAG_ACTIVITY_NEW_TASK 属性。所以 Activity E 启动 Activity F 后,最后会存在三个任务栈,Activity F 会单独存在于一个任务栈中
  3. startActivity() 和 startActivityForResult()的区别

    • startActivity()

      • startActivity() 方法用于启动一个新的 Activity,但不期望获取从该 Activity 返回的结果。

      • 适用于单向的页面跳转,比如从一个页面导航到另一个页面,不需要返回结果。

    • startActivityForResult()

      • startActivityForResult() 方法用于启动一个新的 Activity,期望并等待从该 Activity 返回结果。

      • 被启动的 Activity 在完成后会返回一个结果给调用它的 Activity。

      • 适用于需要在新 Activity 完成后获取结果的情况,比如从设置页面返回用户的选择结果等。

    • 使用示例:

      • startActivity() 示例:

        // 启动一个新的 Activity,不需要获取返回结果
        Intent intent = new Intent(this, SecondActivity.class);
        startActivity(intent);
        

        startActivityForResult() 示例:

        // 启动一个新的 Activity,并等待结果返回
        Intent intent = new Intent(this, SecondActivity.class);
        startActivityForResult(intent, REQUEST_CODE);
        
    • 在被启动的 Activity 中设置返回结果:

      • // 在被启动的 Activity 中设置返回结果
        Intent returnIntent = new Intent();
        returnIntent.putExtra("result", "Hello from SecondActivity!");
        setResult(Activity.RESULT_OK, returnIntent);
        finish();
        
    • 在调用它的 Activity 中处理返回结果:

      • // 在调用它的 Activity 中处理返回结果
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
          if (requestCode == REQUEST_CODE) {
              if (resultCode == Activity.RESULT_OK) {
                  String result = data.getStringExtra("result");
                  // 处理返回的结果
              }
          }
        }
        
  4. Activity.startActivity() 和 Application.startActivity()的区别

    • Activity.startActivity() 将新的 Activity 加入当前 Activity 的任务栈。

    • Application.startActivity() 必须使用 FLAG_ACTIVITY_NEW_TASK 标志,因为 Application 不属于任何任务栈

      • 如果不使用FLAG_ACTIVITY_NEW_TASK,会抛出异常 android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
  5. Activity各生命周期

    • onCreate():Activity 被创建时调用,用于初始化。

    • onStart():Activity 即将变得可见时调用。

    • onResume():Activity 获取用户焦点并可以与用户交互时调用。

    • onPause():Activity 失去用户焦点但仍然可见时调用。

    • onStop():Activity 不再可见时调用。

    • onDestroy():Activity 被销毁之前调用,用于清理资源。

  6. activity A 打开 activity B 再回退到 ActivityA 的生命周期

  7. 生命周期是固定的吗?有其他的可能吗?

  8. taskAffinity属性的作用

  9. 应用打开系统相册这个页面,相册这个页面是加到当前应用的任务栈里面吗

    - 加入到当前的任务栈中
    

service相关

  1. service的两种启动模式

    • Service 的启动方式
  2. activity A startService, activity B bindService ,然后ActivityA stopService,会发生什么

    • Service 停止:当 Activity A 调用 stopService() 时,Service 会被停止,并最终调用 onDestroy() 来销毁 Service

    • 绑定的 Activity 处理:Activity BServiceConnection 会收到 onServiceDisconnected() 通知,表示 Service 已经被销毁。

  3. activity A startService, activity B bindService ,然后ActivityB unBindService,会发生什么

    • Service 的生命周期:

      • Service 在被 startService() 启动后会继续运行,直到显式地调用 stopSelf()stopService()

      • Activity A 调用 stopService() 时,Service 会被停止,即使 Activity B 仍然绑定到它。

    • unbindService():

      • Activity A 调用 stopService(),即使 Activity B 仍然绑定到 ServiceService 也会被停止。

      • 一旦 Service 被停止,系统会调用 onDestroy() 方法来销毁 Service。此时,Activity BServiceConnection 回调方法(如 onServiceDisconnected())将被调用,以通知 Activity B 其绑定的 Service 已经被销毁。

    • Activity B 的行为:

      • Service 被停止后,Activity B 会收到通知(onServiceDisconnected()),并且必须处理 Service 连接的断开情况。

      • 如果 Activity B 需要继续与 Service 交互,它可能需要在 Service 重新启动或重新绑定。

  4. service怎么单独放在一个进程

    • android:process=":my_process" 指定 Service 运行在一个名为 my_process 的独立进程中。前缀 : 表示这是一个私有进程,仅属于该应用。如果不加前缀,表示这是一个全局进程,可能会与其他应用共享。
  5. service怎么单独放在一个进程有什么好处

    • 长时间运行的任务:

      • 当你有需要长时间运行的后台任务时,将 Service 放在单独的进程中可以确保这些任务在后台稳定运行,而不会干扰前台的用户体验。
    • 高内存消耗任务:

      • Service 执行的任务需要大量内存(如大数据处理、复杂计算等),将其放在单独进程中可以防止其影响主进程的内存使用。
    • 高安全性需求:

      • 处理敏感数据或需要高安全性操作的服务可以放在单独进程中,以提高安全性和隔离性。
  6. 不同进程获取的service对象是同一个吗

    • 不是
  7. 同一个进程获取的server是同一个对象吗

    • 单一实例:

      • Android 确保在同一个进程中,一个 Service 只有一个实例。这意味着无论你通过 startService() 还是 bindService() 来访问服务,都会引用到同一个 Service 实例。
    • 绑定和启动服务的行为:

      • 当你调用 bindService() 时,onBind() 方法会被调用,并返回一个 IBinder 对象。

      • 当你调用 startService() 时,onStartCommand() 方法会被调用。

      • 如果你同时使用 bindService()startService() 来访问同一个服务,这些调用都会作用在同一个 Service 实例上。

  8. Aidl 客户端掉用的是A方法,在remote端掉用的是B方法,什么原因导致的

广播相关

  1. 广播的两种启动方式和区别

  2. 有序广播

  3. 怎么制定广播只发送给B接收器

  4. 广播可以开启子线程去请求网络吗

    • 在 Android 中,BroadcastReceiver 是在主线程(UI 线程)中运行的,因此网络操作直接在主线程中是不允许的,因为这会导致应用的 ANR(Application Not Responding,应用无响应)问题。你需要将网络请求放在子线程中进行。
  5. 广播中可以调用startActivity吗

ContentProvider相关

  1. ContentProvider怎么使用
  2. 怎么调用系统的ContentProvider
  3. ContentProvider可以进行多线程操作吗
  4. 多个应用操作同一个ContentProvider,会有问题吗

其它

  1. ListView中图片加载错乱问题
  2. Glide 源码
  3. 如何加载一张大图
  4. sp构造方法传入的模式有什么区别

快手二面 Jul 29th, 2024

算法

  1. 【23】合并K个生序链表

给你一个链表数组,每个链表都已经按升序排列。
// 示例 1:
//
// 输入:lists = 1,4,5],[1,3,4],[2,6
//输出:[1,1,2,3,4,4,5,6]
//解释:链表数组如下:
//[
// 1->4->5,
// 1->3->4,
// 2->6
//]

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        Queue<ListNode> pq = new PriorityQueue<>((v1, v2) -> v1.val - v2.val);
        for (ListNode node: lists) {
            if (node != null) {
                pq.offer(node);
            }
        }

        ListNode dummyHead = new ListNode(0);
        ListNode tail = dummyHead;
        while (!pq.isEmpty()) {
            ListNode minNode = pq.poll();
            tail.next = minNode;
            tail = minNode;
            if (minNode.next != null) {
                pq.offer(minNode.next);
            }
        }

        return dummyHead.next;
    }
}

腾讯一面 Jul 9th, 2024

  1. SDK提供给外部应用,外部应用稳定复现的问题,我们sdk复现不了。外部应用提给我们的只有release包,应该怎么解决

  2. 编写sdk应该注意什么

  3. 58同城首页关注哪些核心业务指标

  4. 了解过bugly的原理吗

  5. android 奔溃日志输出的原理

  6. sdk 怎么去获取崩溃日志

  7. 好看app视频关注哪些核心业务指标

  8. 视频帧率、码率怎么监控

  9. ANR和卡顿是怎么监控

  10. 加载一张大图

    • 对于普通的图片,加载的思路很简单就是压缩大小,用Options来获得大小然后和当前屏幕大小进行比较,然后以一定的值压缩。

      • 获取大图尺寸

        • BitmapFactory.Options options = new BitmapFactory.Options();
          options.inJustDecodeBounds = true;
          Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.qb, options);
          
      • 获取ImageVIew的尺寸,缩放减小内存

        • 根据ImageView大小计算缩放比例inSampleSize

        • 选择占内存小的颜色模式,设置option.inPreferredConfig,有以下值可以选择

      • 加载

    • 但对于超大图片,Android提供了[BitmapRegionDecoder]

商汤二面 Jul 8th, 2024

  1. View 绘制流程的优化点

  2. 怎么学习前沿知识

  3. android 不同版本的对比

  4. android 组件化

  5. android 进程间通信

京东四面 Jul 8th, 2024

  1. SAN
  2. 电量优化
  3. 视频帧率优化
  4. 用户反馈进入应用显示无网,但是其他app都是有网
  5. android 绘制的流程
  6. 自定义View,写一个棋盘,棋盘个数50*50,每个棋盘的宽度自适应;2500个棋盘,随机1秒将背景颜色变成蓝色
  7. 过滤掉重复的区域
  8. android 新特性
  9. 跨端方面

美团二面 Jul 5th, 2024

  1. RN 为主,andorid原生比较少

猿辅导一面 Jul 5th, 2024

  1. kotlin的扩展方法原理

  2. 代理属性原理

  3. by lazy 的原理

    https://www.jianshu.com/p/5d5bff9269f1
    
  4. kotlin 协程原理

  5. handler 原理

  6. handler的内存泄漏

  7. handler的内存泄漏 的gcRoot 是那个类

    • 主线程 Looper 的静态成员变量sMainLooper

    • 子线程 应该是当前线程对象

    • Thread成员变量 -> ThreadLocalMap 成员变量 -> Entry[] ->

    • Entry是继承WeakReference ,WeakReference构造方法,

      	  static class Entry extends WeakReference<ThreadLocal<?>> {
      	    /** The value associated with this ThreadLocal. */
      	    Object value;
      	  
      	    Entry(ThreadLocal<?> k, Object v) {
      	      super(k);
      	      value = v;
      	    }
      	  }
      
    • key 是ThreadLocal,value 时 Looper对象

    • Looper持有 MessageQunue

    • MessageQunue 持有 Message

  8. 项目相关

  9. 增量编译

  10. MVC、MVP、MVVM

  11. LiveData的问题

  12. jetpack都有哪些

  13. 性能优化、启动优化、层级优化

  14. 算法题:View的最大层级

   public static int maxDeep(View view) {
          //view不会有子view所以就返回0
          if (!(view instanceof ViewGroup)) {
              return 0;
          }
          ViewGroup viewGroup = (ViewGroup) view;
          //是viewgroup如果并没有子view,那么也是最底层的view
          if (viewGroup.getChildCount() == 0) {
              return 0;
          }
          //记录最大层数
          int max = 0;
          //广度遍历view
          for (int i = 0; i < viewGroup.getChildCount(); i++) {
              //如果viewGroup拥有子view,所以层数+1,然后递归算它的子view的层数
              int deep = maxDeep(viewGroup.getChildAt(i)) + 1;
              //取最大值
              max = Math.max(deep,max);
          }
          return max;
  }

最后

整理中。。。

  • 21
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值