《Android开发艺术探索》学习笔记

来源:互联网 发布:博悦娱乐网络检测 编辑:程序博客网 时间:2024/09/21 09:29

最近在阅读《Android开发艺术探索》这本书,有一些知识点在这里记录下来,以供自己日后查阅。这篇文章将会随着学习不断更新。

1.在Android中,x轴和y轴的正方向分别为右和下。

2.TouchSlop是系统所能识别出的被认为是滑动的最小距离,换句话说,当手指在屏幕上滑动的时候,如果两次滑动之间的距离小于这个常量,那么系统就不会认为你在进行滑动操作。这是一个常量,和设备有关,在不同的设备上这个值可能是不同的。

3.掌握滑动的方法是实现绚丽的自定义控件的基础。通过三种方式可以实现View的滑动:第一种是通过View本身提供的scrollTo/scrollBy方法来实现滑动;第二种是通过动画给View施加平移效果来实现滑动;第三种是通过改变View的LayoutParams使得View重新布局从而实现滑动。

4.对比如上三种方法:

  • scrollTo/scrollBy:操作简单,适合对View内容的滑动。
  • 动画:操作简单,主要适用于没有交互的View和实现复杂的动画效果。
  • 改变布局参数:操作稍微复杂,适用于有交互的View。

5.View的一大难题滑动冲突,它的解决方法的理论基础就是事件分发机制。

  • public boolean dispatchTouchEvent(MotionEvent ev)
    用来进行事件的分发。如果事件能够传递给当前View,那么此方法一定会被调用,返回结果受当前View的onTouchEvent和下级View的dispatchTouchEvent方法的影响,表示是否消耗当前事件。
  • public boolean onInterceptTouchEvent(MotionEvent event)
    在上述方法内部调用,用来判断是否拦截某个事件,如果当前View拦截了某个事件,那么在同一个事件序列当中,此方法不会被再次调用,返回结果表示是否拦截当前事件。
  • public boolean onTouchEvent(MotionEvent event)
    在dispatchTouchEvent方法中调用,用来处理点击事件,返回结果表示是否消耗当前事件,如果不消耗,则在同一个事件序列中,当前View无法再次接收到事件。

简单地描述一下点击事件的传递规则:对于一个根ViewGroup来说,点击事件产生后,首先会传递给它,这时它的dispatchTouchEvent就会被调用,如果这个ViewGroup的onInterceptTouchEvent方法返回true就表示它要拦截当前事件,接着事件就会交给这个ViewGroup处理,即它的onTouchEvent方法就会被调用;如果这个ViewGroup的onInterceptTouchEvent方法返回false就表示它不拦截当前事件,这时当前事件就会继续传递给它的子元素,接着子元素的dispatchTouchEvent方法就会被调用,如此反复直到事件被最终处理。

6.View的绘制流程是从performTraversals方法开始的,它经过measure,layout和draw三个过程才能最终将一个View绘制出来,其中measure用来测量View的宽和高,layout用来确定View在父容器中的放置位置,而draw则负责将View绘制在屏幕上。(详见P175)

7.RemoteViews在Android中的使用场景有两种:通知栏(自定义通知栏)和桌面小部件。

8.Android中所有的视图都是通过Window来呈现的,不管是Activity,Dialog还是Toast,它们的视图实际上都是附加在Window上的,因此Window实际是View的直接管理者。

9.Android中四大组件:Activity,Service,BroadcastReceiver,ContentProvider。除了BroadcastReceiver以外,其他三种组件都必须在Manifest文件中注册。

10.从开发的角度来说,Handler是Android消息机制的上层接口,这使得开发过程中只需要和Handler交互即可。Handler的使用过程很简单,通过它可以轻松地将一个任务切换到Handler所在的线程中去执行。很多人认为Handler的作用是更新UI,这的确没错,但是更新UI仅仅是Handler的一个特殊的使用场景。具体来说是这样的:有时候需要在子线程中进行耗时的I/O操作,可能是读取文件或者访问网络等,通过Handler将更新UI的操作切换到主线程执行。本质上说,Handler并不是专门用于更新UI的,只是常被用来更新UI。

Android的消息机制主要是指Handler的运行机制,Handler的运行需要底层的MessageQuene和Looper的支撑。MessageQuene的中文翻译是消息队列,它的内部存储了一组信息,它是采用单链表的数据结构来存储消息列表。由于MessageQuene只是一个消息的存储单元,他不能去处理信息,而Looper(循环)就填补了这个功能,Looper会以无限循环的形式去查找是否有新信息,如果有的话就处理信息,否则就一直等待着。Looper中还有一个特殊的概念,那就是ThreadLocal,ThreadLocal并不是线程,他的作用是可以在每个线程中存储和提供数据。我们知道,Handler创建的时候会采用当前线程的Looper来构造消息循环系统,那么Handler内部通过ThreadLocal来获取当前线程的Looper。当然需要注意的是,线程是默认没有Looper的,如果需要使用Handler就必须为线程创建Looper。我们经常提到的主线程,也叫UI线程,他就是ActivityThread,ActivityThread被创建时就会初始化Looper,这也是在主线程中可以默认使用Handler的原因。

  • ThreadLocal可以在不同的线程中维护一套数据的副本并且彼此互不干扰。在不同线程中访问的是同一个ThreadLocal对象,但是它们通过ThreadLocal获取到的值却是不一样的。

  • MessageQuene主要包含两个操作:插入和读取。读取操作本身会伴随着删除操作,插入和读取对应的方法分别为enqueueMessage和next,其中enqueueMessage的作用是往消息队列中插入一条信息,而next的作用是从消息队列中取出一条消息并将其从消息队列中移除。

  • Looper在Android消息机制中扮演着消息循环的角色,它会不停地从MessageQueue中查看是否有新消息,如果有新消息就会立刻处理,否则就一直阻塞在那里。

11.Android的线程和线程池:对于AsyncTask来说,它的底层用到了线程池,对于IntentService和HandlerThread来说,它们的底层直接使用了线程。
AsyncTask封装了线程池和Handler,它主要是为了方便开发者在子线程中更新UI。
HandlerThread是一种具有消息循环的线程,在它的内部可以使用handler。
IntentService是一个服务,系统对其进行了封装使其可以更方便地执行后台任务。IntentService内部采用HandlerThread来执行任务,当任务执行完后IntentService会自动退出。(P391)由于IntentService是服务的原因,导致它的优先级比单纯的线程要高很多,所以它比较适合执行一些高优先级的后台任务,因为它优先级高不容易被杀死。

线程池的优点可以概括为以下三点:

  • 重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销。
  • 能有效控制线程池的最大并发数,避免大量的线程之间因互相抢占系统资源而导致的阻塞现象。
  • 能够对线程进行简单的管理,并提供定时执行以及指定间隔循环执行等功能。

ThreadPoolExecutor是线程池的真正实现。Android中有四种线程池:

  • FixedThreadPool
    它是一种线程数量固定的线程池,当线程处于空闲状态时,它们并不会被回收,除非线程池被关闭了。当所有的线程都处于活动状态时,新任务都会处于等待状态,直到有线程空闲出来。由于该线程池只有核心线程并且核心线程不会被回收,这意味着它的相应速度更快。

  • CachedThreadPool
    它是一种线程数量不定的线程池,只有非核心线程,其最大线程数是Integer.MAX_VALUE。当线程中的线程都处于活动状态时,线程池会创建新的线程来处理新任务,否则就会使用空闲的线程来处理新任务。线程池中的空闲线程都有超时机制,超过时长为60秒,超过60s闲置线程就会被回收。(P410)

  • ScheduledThreadPool
    它的核心线程数量是固定的,而非核心线程数是没有限制的,当非核心线程闲置时就会立刻被回收。这类线程池主要用于执行定时任务和具有固定周期的重复任务。

  • SingleThreadExecutor
    这类线程池只有一个核心线程,它确保所有任务都在同一个线程中按顺序执行,这使得任务之间不需要处理线程同步的问题。

12.标签:标签在UI的结构优化中起着非常重要的作用,它可以删减多余的层级。 只能作为XML布局的根标签使用。(尽量在项目中使用)

1 0
原创粉丝点击