Android VM虚拟机中运行的文件后缀名是:.dex
MediaPlayer对象从停止状态到Start()之前必然要调用的方法:prepare()
Handle机制原理:
Message:message就是一个数据模型吧,它的作用仅限于线程之间通信的时候传递消息,他可以携带少量数据,用于线程之间传递信息,常用的四个字段target,what,obj,arg
handler:它主要用于发送和接收消息,有三个主要方法,这里实现基本功能,不探讨具体细节。sendMessage();dispatchMessage();handleMessage();
MessageQueue:是消息队列,主要存放所有handler发送过来的消息,这些消息会一直存放消息队列中,等待被处理,每一个线程只有一直MessageQueue队列。消息队列里面有一个入栈和出栈函数,这两个函数的关系是一个生产者和消费者的关系,我们在Looper.loop方法中通过while死循环方法不断检测生产者方法,一旦消息队列不为空,立即取出消息并处理,同时消息的总数量也相应需要改变。
Looper:每个线程通过Handler发送的消息都保存在,MessageQueue中,Looper通过调用loop()的方法,就会进入到一个无限循环当中,然后每当发现Message Queue中存在一条消息,就会将它取出,并传递到Handler的handleMessage()方法中。每个线程中只会有一个Looper对象。一个线程对应一个looper对象,一个looper对应一个消息队列。
使用Handler遇到的问题?
比如说子线程更新UI,是因为触发了checkThread方法检查是否在主线程更新UI,还有就是子线程中没有Looper,这个原因是因为Handler的机制引起的,因为Handler发送Message的时候,需要将Message放到MessageQueue里面,而这个时候如果没有Looper的话,就无法循环输出MessageQueue了,这个时候就会报Looper为空的错误。
主线程怎么通知子线程?
可以利用HandlerThread进行生成一个子线程的Handler,并且实现handlerMessage方法,然后在主线程里面也生成一个Handler,然后通过调用sendMessage方法进行通知子线程。同样,子线程里面也可以调用sendMessage方法进行通知主线程。这样做的好处比如有些图片的加载啊,网络的访问啊可能会比较耗时,所以放到子线程里面做是比较合适的。
非UI线程真的不能更新UI吗?
不一定,之所以子线程不能更新界面,是因为Android在线程的方法里面采用checkThread进行判断是否是主线程,而这个方法是在ViewRootImpl中的,这个类是在onResume里面才生成的,因此,如果这个时候子线程在onCreate方法里面生成更新UI,而且没有做阻塞,就是耗时多的操作,还是可以更新UI的。
Android更新UI的方式?
1、runOnUIThread 2、handler post 3、handler sendMessage 4、view post
Android为啥只允许在主线程更新UI:
多线程并发访问资源需要遵循重要的原则:原子性、可见性、有序性。没有同步机制的情况下,多个线程同时读写内存可能会导致意料之外的问题。
多线程同时操作 UI 也一样,如果想要允许多个线程更新 UI,就要设计对应的同步机制,为了避免这种问题,Android 系统直接规定只允许在 UI 线程更新 UI。
除了线程安全外,还有个原因: UI 组件的生命周期并不确定
线程引用导致的内存泄漏问题: 我们知道每个 View 都持有当前 Context, Activity 的引用,如果子线程持有某个 View 的引用,继而持有了对应 Activity 引用,那么在线程返回之前,即使该 Activity 不可用,也无法回收,这就造成了 内存泄漏。
除了持有 View,线程隐式持有 Activity 也可能导致内存泄漏,只要子线程没有结束,引用关系就一直存在。
比如在 Activity 中创建个内部 AsyncTask、在 Activity 里创建个 Handler
正如 Android Studio 提示的那样,内部线程工具类持有外部类引用,可能会导致 内存泄漏。
Android 系统为了避免过度复杂的线程安全问题,特地规定只允许在主线程中更新 UI。而开发者,为了避免上述问题,需要注意的是:不要在任何子线程持有UI组件,或者Activity的引用。
Android 系统为我们提供了Android多线程以下几种工具类:
AsyncTask :主线程、子线程间任务的切换
HandlerThread :为某个任务/回调单独开一个线程
ThreadPool :管理多个线程,并发执行任务
IntentService :在子线程中获取 Intent,用于执行由 UI 出发的后台 Service
多线程存在的意义:
由于Android开发中,许多操作需要UI线程执行,如:系统事件、输入事件、服务、闹钟、UI绘制等。。。由于主线程只有一个,而所有任务都是串行执行的,如果我们在哪个操作中包含大量的网络请求,I/O将会影响后续用户的后续操作。最为明显的是界面绘制、响应是否及时。为了避免耗时较久的操作导致“掉帧”,我们会把这些操作从主线程换到子线程,这样其他操作不会受到影响,用户体验也会流畅很多。
多线程:
一个线程主要有三个状态:开始、执行、结束。
当线程存活期间,我们会让它执行大量的任务,当任务完成或者主动取消时,线程功成身退。
很多情况下,我们会有很多线程同时存活、执行任务,这时需要添加一个 任务队列,让线程不停地从队列中获取任务,同时有其他线程向其中添加任务,典型的 生产者-消费者 模型。如果我们来实现这个模型,需要写三个角色:生产者线程、消费者线程、任务队列,同时还要保证它们的协作有条不紊。Android 系统替我们实现了上述类,分别是:MessageQueue、Handler、Looper
MessageQueue 就是任务队列,保存着不同类型任务的载体。
Looper 就是我们所说的 “消费者”,它不停地从任务队列中获取任务并执行
Handler 就是 “生产者”,它把任务从其他线程送到 MessageQueue 中。Handler 可以指定任务在任务队列中的位置,也可以按照一定的时间延迟送货
HandlerThread 就是上述三个组件的组合。