MVC/MVP/MVVM
MVC:Model View Controller
- View 传递指令到 Controller;
- Controller 起到不同层面间的组织作用,用于控制应用程序的流程。它处理事件并做出响应。“事件”包括用户的行为和数据 Moldel 的改变;
- Model 将新的数据发送到 View,用户得到反馈;
- 所有通信都是单向进行。
MVP:Model View Presenter
- 各部分之间的通信,都是双向的;
- View 与 Model 不发生联系,都通过 Presenter 传递;
- View 非常薄,不部署任何业务逻辑,称为“被动视图”(passive view),即没有任何主动性,而 Presenter 非常厚,所有逻辑都部署在那里。
MVVM:Model View ViewModel
- MVP 模式升级版;
- 采用双向绑定,Model 的变动,自动反映在 ViewModel 中,反之亦然。
为什么不可以List< Object > list = new ArrayList< String >
?
原因:stackOverfLow: 泛型不支持多态性
One sentence, because
Generic types are not polymorphic
i.e., even though java.lang.String is a subtype of java.lang.Object polymorphism doesn’t apply to generic types. It only applies to collection types. thus
1 | List<Object> list = new ArrayList<String>(); //this isn't valid |
HashMap 和 Hashtable、ConcurrentHashMap 区别?
- Hashtable 是全线程安全,不能以 null 作为 k,v;
- HashMap 是非线程安全的,可以以 null 作为 k,v;
- CurrentHashMap 是 java5 引进替代 Hashtable 的,细粒度的线程安全,可以同步锁定部分数据,而不阻塞其他线程对数据的修改;
请简述 Handler 机制
- 主线程中,启动时会调用
Looper.prepare()
方法,会初始化一个Looper
对象,放入ThreadLocal
中,接着调用Looper.loop()
方法不断循环MessageQueue
,Handler
的创建依赖当前线程中的Looper
,如果当前线程中没有Looper
则必须调用Looper.prepare()
。Handler
的sendMessageXX()
方法将message
发送到MessageQueue
中,即调用MessageQueue.queueMessage()
方法插入一条Message
,Looper
则不断的轮询从MessageQueue
中取出消息,即无限 for 循环调用MessageQueue.next()
,该方法是一个阻塞方法,当有没有信息的时候就会被阻塞。当循环到获取消息不为空时,回调 Handler 的 handleMessage 方法。
AsyncTask 使用场景有哪些?它有什么缺点?如何解决?
- AsyncTask 使用在一些需要耗时操作的场景,耗时操作完成后更新主线程,或者在操作过程中对主线程 UI 进行更新(主要是 progress);
- 缺陷:AsyncTask 内部维护着一个长度为 128 的线程池,同时可以执行 5 个工作线程,还有一个缓冲队列,当线程池已有 128 个线程,缓冲队列已满时,如果此时向线程提交任务,将会抛出
RejectedExecutionException
异常; - 解决:创建一个控制线程来处理 AsyncTask 的调用判断,如果线程池满了则新线程睡眠否者继续请求 AsyncTask;
- Android 3.0(API 11)之前线程之间是并行执行的。在 3.0 之后增加了
SerialExcutor
线程用来串行执行异步线程。真正执行任务的是THREAD_POOL_EXCUTOR
线程。如果需要在 3.0 之后并行执行线程,那么只需要调用ExcuteOnExcutor
方法即可.
简述自定义 View 流程
首先,在res/values/attrs.xml
里面自定义需要使用的属性;
然后,在自定义 view 的构造方法中使用context.obtainStyledAttributes(attrs,R.styleable.attrName)
读取这些自定义属性(注意recycle()
资源);
接着,在 onMeasure 方法中处理 view 的宽高策略。Measure 的三个模式EXACTLY
、AT_MOST
、UNSPECIFIED
的不同处理,然后需要使用setMeasuredDimension
设置 view 的 width 和 height;
最后,在 onDraw 方法中使用 canvas 绘制我们需要的图像;
如果需要处理触摸冲突事件,那么需要实现onTauchEvent
、onInterceptTouchEvent
方法,处理冲突事件;
Activity 在被意外销毁的情况下,如何恢复数据?
- 可以在
onSaveInstanceState
中简要保存的数据保存起来,可以通过Bundle
进行临时保存,然后在onCreate
中的Bundle
中取出来进行恢复。 - 或者调用
onRestoreInstanceState(Bundle savedInstanceState)
方法;
Activity 的常规生命周期?
onCreate–>onResume–>onStart–>onPause–>onStop–>onDestory
Fragment 的常规生命周期是怎样的?
onAttach–>onCreateView–>onActivityCreated–>onStart–>onResume–>onPause–>onStop–>onDestoryView–>onDestory–>onDetach
Android 的存储形式有哪些?
- 数据库 SQLite 方式存储,支持基础的 SQL 语法,官方提供
SQLiteDataBase
类来操作,并且支持轻量级的事务; SharedPreference
存储简单的参数信息,本质为文件存储的 XML;- file 存储,常用来存储大数据量的数据,需要 io 操作;
ContentProvider
方式,可以向外部程序曝露数据;- net 方式,网络存储数据方式,通过网络请求方式数据交互;
如何判断应用是否被强杀?如何解决该问题?
可以在Application
中定义一个 static 常量,赋值为-1,然后在欢迎界面修改值为 0,如果被强杀,application
被重新初始化,这时候在新生的Activity
中根据常量值判断应用是否被强制杀死。在Activity
的父类中封装应用被强杀的逻辑,然后根据是否被强杀处理不同的逻辑。
JSON 的优点有哪些? JSON/XML 对比链接
Json 格式简单,兼容性高,易于读写,并且传输的带宽小,方便解析,并且服务端容易生成;
Android 动画类型和区别?
Android3.0(SDK 11)之前,动画有补间动画(TWEEN)和帧动(Frame)画两种。补间动画支持:缩放,位移,透明度,旋转;帧动画是将图片按照一定顺序播放;
Android3.0(SDK 11)之后,新增了
ValueAnimator
的属性动画,通过不断的修改 View 的属性来产生动画效果;注意:补间动画的位移不会改变组件的交互事件位置,但是属性动画是可以改变。如一个 Button 使用了补间动画的位移,那么它本身的点击事件响应区域仍然在原位置,但是使用属性动画改变了 Button 的位置之后,点击事件的响应位置也会相应的在新的 button 位置;
估值器和插值器
- 插值器(Interpolator): TimeInterpolator(时间插值器):
LinearInterpolator
(线性插值器:匀速动画)、AccelerateDecelerateInterpolator
(加速减速插值器:俩头快,中间慢)和DecelerateInterpolator
(减速插值器:速度越来越慢); - 估值器(Evaluator):TypeEvaluator(类型估值器):
IntEvaluator
(针对整型属性)、FloatEvaluator
(针对浮点型属性)、ArgbEvaluator
(针对 color 属性)
- 插值器(Interpolator): TimeInterpolator(时间插值器):
采用
ValueAnimator
,监听动画过程,自己实现属性的改变:ValueAnimator
本身不作用任何对象,就是说直接使用没有任何动画效果。它可以对一个值做动画,然后我们就可以家监听器动画过程,在动画过程中修改我们的对象的属性值,这将就间接的使我们的对象做了动画。
1 | /** |
assets、res/raw 目录的区别?
- assets:用于存放需要打包到应用程序的静态文件,如数据库文件等,以便部署到设备中,这些文件不会被生成任何的资源 ID,必须使用
AssetsManager
管理这些文件,该目录还支持任意深度的子目录; - res:用户存放应用程序的资源,这些资源将被打包编译生成 ID,通过 R.id.xx 来调。不支持深度子目录。
- res/xml:存放通用的 xml 文件;
- res/menu:存放 xml 格式的菜单描述文件;
- res/values:存放字符串,尺寸值等;
- res/raw:存放通用的文件,该文件夹内的文件将不会被编译成二进制文件,而是按照原样复制到设备上,但是仍然会生成对应的 ID,可以通过 R.id.xx 方式调用。通常存放如音频,视频等文件。
OOM 主要 Reason 及处理方式?
- 对象资源没有关闭。eg.
Cursor
,File
等; Bitmap
的占用内存过大,且未及时回收;
可以采用降低bitmap
采样率(通常有argb8888
、argb565
、argb4444
)方法减小bitmap
占用内存:
1 | BitmapFactory.Options options = newBitmapFactory.Options(); |
- 尽量使用
application
的contenxt
来替代activity
的context
; - 注册的广播,监听等未及时取消;
- 集合中的对象没有及时清理,特别是 static 的集合,更需要及时清理集合内对象;
- 强引用对象,不能被 GC 回收,长期存在于内存当中;
Service 知识小结
- 启动方式
startService
非绑定启动Service
。生命周期:onCreate
(如果该Serivce
未启动执行,反之不执行该方法)–》onStartCommand
(2.0 之前是onStart
方法)–》running–》onDestory
bindService
绑定式启动Serivce
。生命周期:onCreate
(如果Service
未启动执行,反之则不执行该方法)–》onBind
–》onUnbind
–》onDestory
- 先后采用非绑定和绑定方式启动
Service
。生命周期:onCreate
(if needed)–》onStartCommand
–》onBind/onRebind
–》running–》onUnbind
–》onDestory
Service
与线程Thread
是俩个概念,Service
运行于主线程,如果要在Service
运行耗时任务,那么仍然需要开启新线程去执行耗时任务;IntentService
与Service
区别- 会创建独立的
worker
程序来处理所有的Intent
请求; - 创建独立的
worker
线程来处理onHandleIntent
方法实现的代码,无需处理多线程问题; - 所有请求完成之后会自动停止,无需手动停止;
- 为
Service
的onBind
方法提供默认实现,返回null
; - 为
Servcie
的onStartCommand
提供默认实现,将请求的Intent
添加到队列中;
- 会创建独立的