Android面试题

1.Activity的四种启动模式及其应用场景

  四  种: (1) standard   (2) singleTop   (3) singleTask  (4) singleInstance
  应用场景: 
          (1) 默认启动模式,适用于大多数Activity
          (2) 适合接收通知启动的内容显示页面。例如QQ消息推送点击后的展示页面
          (3) 适合作为程序入口点。如浏览器的主界面,不管从多少个应用启动浏览器,只启动主界面一次,其余情况走onNewIntent,并清空主界面上面的其他页面。打开之前的页面就ok,不再新建
          (4) 适合需要与程序分离开的页面。例如闹铃提醒,将闹铃提醒与闹铃设置分离

 参考:https://www.aliyun.com/jiaocheng/21147.html

2.如何安全退出已调用多个Activity的Application

(1) 抛出异常强制退出:
   该方法通过抛异常,使程序Force Close。
   验证可以,但是,要解决的问题是,如何使程序结束掉,而不弹出Force Close的窗口。
  //安全结束进程 android.os.Process.killProcess(android.os.Process.myPid());
(2) 记录打开的Activity:
   每打开一个Activity,就记录下来。在需要退出时,关闭每一个Activity即可。
   Listlists;  在application全集的环境里面
   lists=new ArrayList();
   lists.add(activity);
   for(Activity activity : lists)
    { activity.finish(); }
(3) 发送特定广播:
   在需要结束应用时,发送一个特定的广播,每个Activity收到广播后,关闭即可。
   //给某个Activity注册接受广播的意图
       registerReceiver(receiver,filter)
   //如果接受到的是关闭activity的广播,就调用finish()方法,把当前的Activity结束掉。
(4) 递归退出
   在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理,递归关闭。
    # 为了编程方便,最好定义一个Activity基类,处理这些共通问题
(5) 通过intent的flag来实现,intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)激活一个新的Activity,然后在新的Activity的onCreate()方法里finish()掉。

3.Android中常见的设计模式

(1)单例模式
(2)建造者Builder模式,如AlertDialog
(3)观察者模式,如eventbus
(4)适配器模式

 参考:https://blog.csdn.net/u010568407/article/details/51911677

4.Android自定义View的一般步骤

一般分为:扩展、组合、重写,通常步骤:
(1)在res的values文件夹下新建attrs文件,并在其中获取要使用的属性
(2)继承相关view(假如有合适的view),在构造方法中获取相关的属性
(3)在onMeasure中为属性赋值
(4)在onLayout中设置控件摆放位置(viewgroup)
(5)在onDraw中绘制相关的自定义view
(5)重写onTouchEvent中手势相关方法
(6)在要使用的自定义view中的xml中设置相关属性

 参考:https://blog.csdn.net/h55l55/article/details/51348197
 参考:https://www.jianshu.com/p/369f66035666

5.Service有哪些启动方法,有什么区别,怎样停用Service

(1) 通过startService :
        Service会经历 onCreate->onStart,运行,stopService停止服务并调用onDestroy方法
(2) 通过bindService :
        Service会运行onCreate->onBind,这个时候调用者和Service绑定在一起。
        调用者退出了,Service就会调用onUnbind->onDestroyed方法;
        调用者也可以通过调用unbindService来停止服务,执行onUnbind->onDestroyed方法。
注意:
  (1) Service的onCreate的方法只会被调用一次,无论多少次的startService或bindService,Service只被创建一次;如果先是bind了,那么start的时候就直接运行Service的onStart 方法,如果先是start,那么bind的时候就直接运行onBind方法。
  (2) 如果service运行时调用了bindService,这时再调用stopService,service是不会调用onDestroy方法的,service就stop不掉了,只能调用UnbindService, service就会被销毁
  (3) 如果service通过startService 被start之后,多次调用startService 的话,service会多次调用onStart方法。多次调用stopService的话,service只会调用一次onDestroyed方法。
  (4) 如果一个service通过bindService被start之后,多次调用bindService的话,service只会调用一次onBind方法;多次调用unbindService的话会抛出异常

6.注册广播的方式和区别,以及广播的种类

   继承BroadcastReceiver
(1) 在清单文件中声明,添加
     
        
             
        
     

 (2) 代码进行注册如:
     IntentFilter filter =  new IntentFilter("android.provider.Telephony");
     MyReceiver receiver = new MyReceiver();
     registerReceiver(receiver.filter);

区别:
   (1) 第一种是常驻型(静态注册),也就是说当应用程序关闭后,如果有信息广播来,
       程序也会被系统调  用自动运行。
   (2) 第二种不是常驻型广播(动态注册),也就是说广播跟随程序的生命周期

普通广播、有序广播和本地广播

 参考:https://www.jianshu.com/p/ea5e233d9f43

7.什么是 ANR 如何避免它?

    ANR:Application Not Responding,主线程(Activity、Service)是 5 秒,
         BroadCastReceiver 是 10 秒。
  解决方案:将耗时操作,如访问网络、Socket通信、查询大量SQL语句、复杂逻辑计算等放在子线程中, 然后通过 handler.sendMessage、 runonUITread、AsyncTask 等方式更新 UI。

8.谈谈Android OOM和内存泄漏

  OOM:(out of memory)当APP所需要的内存超过系统分配的内存值就会导致内存溢出程序崩溃
  内存泄漏:当一个对象本应被JVM回收但他依然被一个正在使用的对象所持有,从而无法回收;内存泄漏也是造成内存溢出的主要原因。
  内存泄漏原因:
  (1)单例模式中传递了Activity的Context,生命周期不对等
  (2)资源对象未关闭(Cursor、File等)
  (3)接收器或监测器只注册未取消(广播、EventBus等)
  (4)非静态匿名内部类Handler由于持有外部类Activity的引用所造成的内存泄漏(使用弱应用并调用removeCallbacksAndMessages移除)                      

 参考:https://blog.csdn.net/qq_28607155/article/details/76148989

9.Android 补间动画和属性动画的区别?

补间动画和属性动画区别是属性是否改变,补间动画中View进行改变后点击事件依然是原位置,而属性动画则是跟随新位置进行响应

10.跨进程通信的几种方式

(1)使用Intent跳转例如跳转到拨打电话
(2)AIDL通信,通过接口共享数据
(3)广播:例如系统的开机、网络变化的广播
(4)ContentProvider:数据库存储数据共享

11.View的分发机制,滑动冲突

分发机制:主要包括三个方法dispatchTouchEvent事件分发,onInterceptTouchEvent拦截事件,onTouchEvent事件处理
滑动冲突:同向滑动冲突:如ScrollView嵌套ListView需要动态设置ListView的高度;异向滑动冲突:判断滑动方向大小进行拦截

参考:https://www.jianshu.com/p/d82f426ba8f7

12.Serializable和Parcelable的区别?

Serializable:Java自带的序列化,本质是使用了反射,会在序列化的过程中产生很多临时对象从而造成频繁的GC
Parcelable:Android专有的,本质是将完整的对象分解成Intent支持的数据类型
Parcelable序列的数据写在内存中,而Serializable则通过IO写在磁盘所以Parcelable更快但Serializable更持久

13.Fragment生命周期、懒加载、两种Adapter之间的区别

生命周期:onAttach - onCreate - onCreateView - onActivityCreated - onResume - onPause - onStop - onDestroyView - onDestroy - onDetach
懒加载:重写setUserVisibleHint方法并判断是否进行加载
FragmentPagerAdapter:每一个生成的 Fragment 都将保存在内存之中,适用于静态的数量比较少的Fragment
FragmentStatePagerAdapter:会对limit外的Fragment进行回收只是在Fragment销毁前会调用onSaveInstanceState对数据进行保存,然后再创建时读取这些数据

参考: https://blog.csdn.net/lk2021991/article/details/84981662
   https://www.jianshu.com/p/25a02f5a15b3

14.简述TCP,UDP,Socket

TCP:通过网络的三、四次握手完成一串数据的发送
UDP:通过IP端口号向指定位置发送一串数据,无论是否成功接收
Socket:实时连接(IM即时通讯、蓝牙传送数据)

15.HTTP与HTTPS的区别

(1)HTTPS采用加密传输协议而HTTP采用明文传输协议故HTTPS更加安全
(2)HTTPS加入了SSL层需要SSL证书
(3)HTTPS规范端口443,HTTP规范端口80

16.RecyclerView和ListView的区别

(1)缓存:RecyclerView缓存了View+ViewHolder+Flag,而ListView只缓存View
(2)刷新:RecyclerView支持局部刷新而ListView只能全局刷新
(3)动画:recyclerView中,内置有许多动画API,例如: notifyDataInserted(), notifyItemMoved()等;如果需要自定义动画效果,可以通过实现(RecyclerView.ItemAnimator类)完成自定义动画效果,然后调用RecyclerView.setItemAnimator();但是ListView并没有实现动画效果,但我们可以在Adapter自己实现item的动画效果;

17.IntentService解析

IntentService是Service的子类,本质上是一个默认开启了单独的工作线程的Service;由于onBind方法默认返回null,所以无法通过bindService的方式启动;无需主动调用stopSelf只要工作线程的任务执行完毕它会自动结束

18.Intent 能传递多大 Size 的数据?解决方法

(1)Intent 无法传递大数据是因为其内部使用了 Binder 通信机制,Binder 事务缓冲区限制了传递数据的大小。
(2)Binder 事务缓冲区的大小限定在 1MB(进程共享),对于大数据,例如长字符串、Bitmap 等,不要考虑 Intent 传递数据的方案。
 解决方法:使用 EventBus 的粘性事件来解决

19.SurfaceView和View的区别

SurfaceView是View的子类,View是在主线程更新UI,而SurfaceView采用双缓存技术,在单独的线程中更新UI故不会阻塞主线程,通常用于频繁刷新View如视频的播放

20.Android中进程的优先级

前台进程 - 可见进程 - 服务进程 - 后台进程 - 空进程

21.为什么不能在子线程更新UI ?

(1) ViewRootImpl(onResume之后创建)中会检查当前线程是否是主线程,不是主线程就会抛出异常
(2) 系统不建议在子线程访问UI是由于Android的UI控件不是线程安全的,如果在多线程中并发访问可能会导致UI控件处于不可预期的状态

22.Service保活

(1)使用前台服务startForeground
(2)manifest将Service的优先级提升到最大1000
(3)在startCommand中手动设置返回START_STICKY(服务被杀死会自动重启)
(4)在Service的onDestroy中注册广播,然后收到广播后重启服务

23.Handler实现原理

(1)由于Android不允许在子线程更新UI,所以就有了handler,当然他的作用就是实现线程间的通信
(2)Handler主要包括Handler,message,looper,messageQueue; 
    ① Message:Message有两个关键的成员变量:target(就是发送消息的  Handler)、callback:调用Handler.post(Runnable)时传入的Runnable类型的任务。post事件的本质也是创建了一个Message,将我们传入的这个runnable赋值给创建的Message的callback这个成员变量。
    ② MessageQueue:消息队列用于存放消息,其中重点关注next()方法,它会返回下一个待处理的消息。
    ③ Looper:Looper消息轮询器其实是连接Handler和消息队列的核心。想要在一个线程中创建一个Handler,首先要通过Looper.prepare()创建Looper,之后还得调用Looper.loop()开启轮询。
    prepare():这个方法做了两件事:首先通过ThreadLocal.get()获取当前线程中的Looper,如果不为空则抛出RuntimeException。否则创建Looper,并通过ThreadLocal.set(looper)将当前线程与刚刚创建的Looper绑定。值得注意的是,上面的消息队列的创建其实就是发生在Looper的构造函数中。
    loop():这个方法开启了整个事件机制的轮询。其本质是开启一个死循环,不断地通过MessageQueue的next()方法获取消息msg。拿到消息后会调用msg.target.dispatchMessage()来做处理。综上也就是调用handler.dispatchMessage()
(3)Handler:Handler重点在于发送消息和处理消息。
    ① 发送消息。其实发送消息除了 sendMessage 之外还有 sendMessageDelayed 和 post 以及 postDelayed 等等不同的方式。但它们的本质都是调用了 sendMessageAtTime。在 sendMessageAtTime 这个方法中调用了 enqueueMessage。在 enqueueMessage 这个方法中做了两件事:通过 msg.target = this 实现了消息与当前 handler 的绑定。然后通过 queue.enqueueMessage 实现了消息入队。
    ② 处理消息。 消息处理的核心其实就是dispatchMessage()这个方法。这个方法里面的逻辑很简单,先判断 msg.callback 是否为 null,如果不为空则执行这个 runnable。如果为空则会执行我们的handleMessage方法。

24.Looper死循环为什么不会导致应用卡死?

(1) 主线程的主要方法就是消息循环,一旦退出消息循环,那么你的应用也就退出了,Looer.loop方法可能会引起主线程的阻塞,但只要它的消息循环没有被阻塞,能一直处理事件就不会产生ANR异常。
(2) 造成ANR的不是主线程阻塞,而是主线程的Looper消息处理过程发生了任务阻塞,无法响应手势操作,不能及时刷新UI。
(3) 阻塞与程序无响应没有必然关系,虽然主线程在没有消息可处理的时候是阻塞的,但是只要保证有消息的时候能够立刻处理,程序是不会无响应的。

25.EventBus源码

(1) 通过调用getDefault()里面采用单利双重锁模式创建Eventbus对象
(2) 构造方法中采用ConCurrentHashMap来保存粘性事件
(3) register订阅:利用反射获取订阅者所有的函数
(4) post:publisher发布事件
(5) unregister:subscriber移除对应的eventType,取消事件订阅

你可能感兴趣的:(Android面试题)