Welcome to Ray's Blog

Stay Hungry Stay Foolish - Steve Jobs

0%

常用知识点笔记一


MVC/MVP/MVVM

MVC:Model View Controller
  1. View 传递指令到 Controller;
  2. Controller 起到不同层面间的组织作用,用于控制应用程序的流程。它处理事件并做出响应。“事件”包括用户的行为和数据 Moldel 的改变;
  3. Model 将新的数据发送到 View,用户得到反馈;
  4. 所有通信都是单向进行。
    MVC
MVP:Model View Presenter
  1. 各部分之间的通信,都是双向的;
  2. View 与 Model 不发生联系,都通过 Presenter 传递;
  3. View 非常薄,不部署任何业务逻辑,称为“被动视图”(passive view),即没有任何主动性,而 Presenter 非常厚,所有逻辑都部署在那里。
    MVP
MVVM:Model View ViewModel
  1. MVP 模式升级版;
  2. 采用双向绑定,Model 的变动,自动反映在 ViewModel 中,反之亦然。
    MVVM

为什么不可以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
2
3
List<Object> list = new ArrayList<String>(); //this isn't valid
List<Object> list = new ArrayList<Object>(); //valid
List < ? extends Object> list = new ArrayList<String>();//valid

HashMap 和 Hashtable、ConcurrentHashMap 区别?

  1. Hashtable 是全线程安全,不能以 null 作为 k,v;
  2. HashMap 是非线程安全的,可以以 null 作为 k,v;
  3. CurrentHashMap 是 java5 引进替代 Hashtable 的,细粒度的线程安全,可以同步锁定部分数据,而不阻塞其他线程对数据的修改;

请简述 Handler 机制

  1. 主线程中,启动时会调用Looper.prepare()方法,会初始化一个Looper对象,放入ThreadLocal中,接着调用Looper.loop()方法不断循环MessageQueueHandler的创建依赖当前线程中的Looper,如果当前线程中没有Looper则必须调用Looper.prepare()HandlersendMessageXX()方法将message发送到MessageQueue中,即调用MessageQueue.queueMessage()方法插入一条MessageLooper则不断的轮询从MessageQueue中取出消息,即无限 for 循环调用MessageQueue.next(),该方法是一个阻塞方法,当有没有信息的时候就会被阻塞。当循环到获取消息不为空时,回调 Handler 的 handleMessage 方法。

AsyncTask 使用场景有哪些?它有什么缺点?如何解决?

  1. AsyncTask 使用在一些需要耗时操作的场景,耗时操作完成后更新主线程,或者在操作过程中对主线程 UI 进行更新(主要是 progress);
  2. 缺陷:AsyncTask 内部维护着一个长度为 128 的线程池,同时可以执行 5 个工作线程,还有一个缓冲队列,当线程池已有 128 个线程,缓冲队列已满时,如果此时向线程提交任务,将会抛出RejectedExecutionException异常;
  3. 解决:创建一个控制线程来处理 AsyncTask 的调用判断,如果线程池满了则新线程睡眠否者继续请求 AsyncTask;
  4. 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 的三个模式EXACTLYAT_MOSTUNSPECIFIED的不同处理,然后需要使用setMeasuredDimension设置 view 的 width 和 height;
最后,在 onDraw 方法中使用 canvas 绘制我们需要的图像;
如果需要处理触摸冲突事件,那么需要实现onTauchEventonInterceptTouchEvent方法,处理冲突事件;

Activity 在被意外销毁的情况下,如何恢复数据?

  1. 可以在onSaveInstanceState中简要保存的数据保存起来,可以通过Bundle进行临时保存,然后在onCreate中的Bundle中取出来进行恢复。
  2. 或者调用onRestoreInstanceState(Bundle savedInstanceState)方法;

Activity 的常规生命周期?

onCreate–>onResume–>onStart–>onPause–>onStop–>onDestory

Fragment 的常规生命周期是怎样的?

onAttach–>onCreateView–>onActivityCreated–>onStart–>onResume–>onPause–>onStop–>onDestoryView–>onDestory–>onDetach

Android 的存储形式有哪些?

  1. 数据库 SQLite 方式存储,支持基础的 SQL 语法,官方提供SQLiteDataBase类来操作,并且支持轻量级的事务;
  2. SharedPreference存储简单的参数信息,本质为文件存储的 XML;
  3. file 存储,常用来存储大数据量的数据,需要 io 操作;
  4. ContentProvider方式,可以向外部程序曝露数据;
  5. net 方式,网络存储数据方式,通过网络请求方式数据交互;

如何判断应用是否被强杀?如何解决该问题?

可以在Application中定义一个 static 常量,赋值为-1,然后在欢迎界面修改值为 0,如果被强杀,application被重新初始化,这时候在新生的Activity中根据常量值判断应用是否被强制杀死。在Activity的父类中封装应用被强杀的逻辑,然后根据是否被强杀处理不同的逻辑。

JSON 的优点有哪些? JSON/XML 对比链接

Json 格式简单,兼容性高,易于读写,并且传输的带宽小,方便解析,并且服务端容易生成;

Android 动画类型和区别?

  1. Android3.0(SDK 11)之前,动画有补间动画(TWEEN)和帧动(Frame)画两种。补间动画支持:缩放,位移,透明度,旋转;帧动画是将图片按照一定顺序播放;

  2. Android3.0(SDK 11)之后,新增了ValueAnimator的属性动画,通过不断的修改 View 的属性来产生动画效果;

  3. 注意:补间动画的位移不会改变组件的交互事件位置,但是属性动画是可以改变。如一个 Button 使用了补间动画的位移,那么它本身的点击事件响应区域仍然在原位置,但是使用属性动画改变了 Button 的位置之后,点击事件的响应位置也会相应的在新的 button 位置;

  4. 估值器和插值器

    • 插值器(Interpolator): TimeInterpolator(时间插值器):LinearInterpolator(线性插值器:匀速动画)、AccelerateDecelerateInterpolator(加速减速插值器:俩头快,中间慢)和DecelerateInterpolator(减速插值器:速度越来越慢);
    • 估值器(Evaluator):TypeEvaluator(类型估值器):IntEvaluator(针对整型属性)、FloatEvaluator(针对浮点型属性)、ArgbEvaluator(针对 color 属性)
  5. 采用ValueAnimator,监听动画过程,自己实现属性的改变:ValueAnimator本身不作用任何对象,就是说直接使用没有任何动画效果。它可以对一个值做动画,然后我们就可以家监听器动画过程,在动画过程中修改我们的对象的属性值,这将就间接的使我们的对象做了动画。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* 采用ValueAnimator,监听动画过程,实现对象属性的改变
* @param target
* @param start
* @param end
*/
public void performValueAnimator(final View target, final int start, final int end) {
ValueAnimator animator = ValueAnimator.ofFloat(1, 100);//创建动画对象
//添加动画更新监听
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
//创建一个整型估值器
private IntEvaluator intEvaluator = new IntEvaluator();
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//获取当前动画的进度值,整型1-100之间
int currentValue = (int) animation.getAnimatedValue();
Log.d(TAG, "onAnimationUpdate: currentValue = "+currentValue);
//获取当前进度咱整个动画过程的比例,浮点型0-1之间
float fraction = animation.getAnimatedFraction();
//直接调用整型估值器,通过比例计算出尺寸,然后设置给View
target.getLayoutParams().width = intEvaluator.evaluate(fraction, start, end);
target.requestLayout();
}
});
}

assets、res/raw 目录的区别?

  1. assets:用于存放需要打包到应用程序的静态文件,如数据库文件等,以便部署到设备中,这些文件不会被生成任何的资源 ID,必须使用AssetsManager管理这些文件,该目录还支持任意深度的子目录;
  2. res:用户存放应用程序的资源,这些资源将被打包编译生成 ID,通过 R.id.xx 来调。不支持深度子目录。
  • res/xml:存放通用的 xml 文件;
  • res/menu:存放 xml 格式的菜单描述文件;
  • res/values:存放字符串,尺寸值等;
  • res/raw:存放通用的文件,该文件夹内的文件将不会被编译成二进制文件,而是按照原样复制到设备上,但是仍然会生成对应的 ID,可以通过 R.id.xx 方式调用。通常存放如音频,视频等文件。

OOM 主要 Reason 及处理方式?

  1. 对象资源没有关闭。eg.CursorFile等;
  2. Bitmap的占用内存过大,且未及时回收;
    可以采用降低bitmap采样率(通常有argb8888argb565argb4444)方法减小bitmap占用内存:
1
2
3
BitmapFactory.Options options = newBitmapFactory.Options();
options.inSampleSize = 2;//图片宽高都为原来的二分之一,即图片为原来的四分之一
Bitmap bitmap =BitmapFactory.decodeStream(cr.openInputStream(uri), null, options); preview.setImageBitmap(bitmap);
  1. 尽量使用applicationcontenxt来替代activitycontext
  2. 注册的广播,监听等未及时取消;
  3. 集合中的对象没有及时清理,特别是 static 的集合,更需要及时清理集合内对象;
  4. 强引用对象,不能被 GC 回收,长期存在于内存当中;

Service 知识小结

  1. 启动方式
    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
    Android_service_lifecycle
  1. Service与线程Thread是俩个概念,Service运行于主线程,如果要在Service运行耗时任务,那么仍然需要开启新线程去执行耗时任务;
  2. IntentServiceService区别
    • 会创建独立的worker程序来处理所有的Intent请求;
    • 创建独立的worker线程来处理onHandleIntent方法实现的代码,无需处理多线程问题;
    • 所有请求完成之后会自动停止,无需手动停止;
    • ServiceonBind方法提供默认实现,返回null
    • ServcieonStartCommand提供默认实现,将请求的Intent添加到队列中;