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,取消事件订阅