公共技术点之 Android 动画基础
公共技术点之 Java 动态代理
公共技术点之依赖注入
公共技术点之 View 事件传递
公共技术点之 View 绘制流程
一、Android的Framework和Android apk的打包过程
底层的Binder驱动,IPC的核心,SGL 2D绘图,OpenGL 3D绘图
二、多线程
AsyncTask:
AsyncTask的缺陷和问题
关于线程池:asynctask对应的线程池ThreadPoolExecutor都是进程范围内共享的,都是static的,所以是asynctask控制着进程范围内所有的子类实例。由于这个限制的存在,当使用默认线程池时,如果线程数超过线程池的最大容量,线程池就会爆掉(3.0后默认串行执行,不会出现这个问题)。针对这种情况,可以尝试自定义线程池,配合asynctask使用。
关于默认线程池:核心线程池中最多有CPU_COUNT+1个,最多有CPU_COUNT*2+1个,线程等待队列的最大等待数为128,但是可以自定义线程池。线程池是由AsyncTask来管理的,线程池允许tasks并行运行,xuyao注意的是并发情况下数据的一致性问题,新数据可能会被老数据覆盖掉,类似volatile变量。所以希望tasks能够串行运行的话,使用SERIAL_EXECUTOR。
自定义线程池:executeOnExecutor(Executor exec,Params… params) 自定义Executor
execute(Params… params){return executeOnExecutor(sDefaultExecutor,params);}
AsyncTask在不同的SDK版本中的区别:
调用AsyncTask的excute方法不能立即执行程序的原因分析及改善方案
通过查阅官方文档发现,AsyncTask首次引入时,异步任务是在一个独立的线程中顺序的执行,也就是说一次只能执行一个任务,不能并行的执行,从1.6开始,AsyncTask引入了线程池,支持同时执行5个异步任务,也就是说同时只能有5个线程运行,超过的线程只能等待,等待前面的线程某个执行完了才被调度和运行。换句话说,如果一个进程中的AsyncTask实例个数超过5个,那么假如前5个都运行很长时间的话,那么第6个只能等待机会了。这是AsyncTask的一个限制,而且对于2.3以前的版本无法解决。如果你的应用需要大量的后台线程去执行任务,那么你只能放弃使用AsyncTask,自己创建线程池来管理Thread,或者干脆不用线程池直接使用Thread也无妨。不得不说,虽然AsyncTask较Thread使用起来方便,但是它最多只能同时运行5个线程,这也大大局限了它的实力,你必须要小心设计你的应用,错开使用AsyncTask的时间,尽力做到分时,或者保证数量不会大于5个,否则就会遇到上次提到的问题。可能是Google意识到了AsyncTask的局限性了,从Android3.0开始对AsyncTask的API作出了一些调整:每次只启动一个线程执行一个任务,完成之后再执行第二个任务,也就是相当于只有一个后台线程在执行所提交的任务。
1、生命周期
很多开发者会认为一个在Activity中创建的AsyncTask会随着Activity的销毁而销毁。然而事实并非如此。AsyncTask会一直执行,直到doInBackground()方法执行完毕。然后,如果cancel(boolean)被调用,那么onCancelled(Result result)方法会被执行;否则,执行onPostExecute(Result result)方法。如果我们的Activity销毁之前,没有取消AsyncTask,这有可能让我们的AsyncTask崩溃(crash)。因为它想要处理的view已经不在了。所以,我们总是必须确保在销毁活动之前取消任务。总之,我们使用AsyncTask需要确保AsyncTask正确的取消。
2、内存泄漏
如果AsyncTask被声明为Activity的非静态的内部类,那么AsyncTask会保留一个对Activity的引用。如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄漏。
3、结果丢失
屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。
4、并行还是串行
在Android1.6之前的版本,AsyncTask是串行的,在1.6至2.3的版本,改成了并行的。在2.3之后的版本又做了 修改,可以支持并行和串行,当想要串行执行时,直接执行execute()方法,如果需要执行executeOnExecutor(Executor)。
三、Android机制
1、Linux Sandbox 沙箱机制:Android将数据分为system和data两个区。其中system是只读的,dada用来存放应用自己的数据,这保证了系统数据不会被随意改写。
应用之间的数据相互独立,每个应用都会有一个user id和group id,只有相同的user id并且来自同一个作者,才能访问它们的数据。作者通过对apk签名来标识自己,签名和uid构成了双重的保证。
2、用户权限机制:文件权限,UID,GID
3、用户权限机制:Android permission机制限制应用访问特定的资源,例如照相机、网络、外部存储等api
4、如何让两个app运行在同一个进程里?
- 1>两个app要用相同的private key来签名
- 2>两个app的Manifest文件中要添加一样的属性 android:sharedUserId(设置成相同的UID)
四、Binder机制;参考原文
五、NDK
Dalvik虚拟机在调用一个成员函数的时候,如果发现该成员函数是一个JNI方法,那么就会直接跳到它的地址去执行。也就是说,JNI方法是直接在本地操作系统执行的,而不是Dalvik虚拟机解释器执行。由此也可以看出,JNI方法是Android应用程序与本地操作系统直接进行通信的一个手段。
JNI原理:
Dalvik虚拟机JNI方法的注册过程分析
例子:当libnanosleep.so文件被加载的时候,函数JNI_OnLoad就会被调用。在函数JNI_OnLoad中,参数vm描述的是当前线程中的Dalvik虚拟机,通过调用它的成员函数GetEnv就可以获得一个JNIEnv对象。有了这个JNIEnv对象之后,我们就可以调用另外一个函数jniRegisterNativeMethods来向当前进程的Dalvik虚拟机注册一个JNI方法。
六、Android系统启动过程,App启动过程
App启动过程:
从桌面点击到activity启动的过程
1、Launcher线程捕获onclick的点击事件,调用Launcher.startActivitySafely,进一步调用Launcher.startActivity,最后调用父类Activity的startActivity。
2、Activity和ActivityManagerService交互,引入Instrumentation,将启动请求交给Instrumentation,调用Instrumentation.execStartActivity。
3、调用ActivityManagerService的startActivity方法,这里做了进程切换(具体过程请查看源码)。
4、开启Activity,调用onCreate方法
七、Activity,Fragment,Service生命周期
常见的例子:程序正运行着来电话了,这个程序咋办呢?中止了呗,如果中止的时候新出的一个Activity是全屏的onPause->onStop,恢复的时候onStart->onResume,如果打断这个应用程序的是一个Theme为Translucent或者Dialog的Activity那么只是onPause,恢复的时候onResume。
onPause:恢复的时候onResume
onCreate:在这里创建界面,做一些数据的初始化工作
onStart:到这一步变成用户可见不可交互的
onPause:到这一步是可见但不可交互的,系统会停止动画等消耗CPU的事情,应该在这里保存你的一些 数据,因为这个时候你的程序的优先级降低,有可能被 系统回收。在这里保存的数据,应该在onResume里读出来。注意:这个方法里做的事情时间要短,因为下一个Activity不会等到这个方法完成才启动。
onStop:变得不可见,被下一个Activity覆盖了(onPause和onStop的区别是否可见)
onDestroy:这是Activity被干掉前最后一个被调用方法了,可能是外面类调用finish方法或者是系统为了节省空间将它暂时性的干掉,可以用isFinishing()来判断它,如果你有一个ProgressDialog在线程中转动,请在onDestroy里把它cancel掉,不然等线程结束的时候,调用Dialog的cancel会抛出异常的。
onPause,onstop,onDestroy,三种状态下,Activity都有可能被系统干掉。
启动另一个Activity然后finish,先调用旧Activity的onPause方法,然后调用新的Activity和onCreate->onStart->onResume方法,然后调用旧Activity的onStop->onDestroy方法。
如果没有调用finish那么onDestroy方法不会被调用,而且在onStop之前还会调用onSavedInstanceState方法
onRestart方法执行完了之后还会调用onStart方法
fragment:[SupportFragmentManager,childFragment]
service:
Android Service的生命周期
android-Service和Thread的区别
Service和Intent Service:没啥区别,只是IntentService在onCreate方法中开启新的HandlerThread去执行。
Service运行的进程和线程:当它运行的时候如果是LocalService,那么对应的Service是运行在主进程的main线程上的。如onCreate,onStart这些函数都是在系统调用的时候在主进程的main线程上运行的。如果是RemoteSevice,那么对应的Service则是运行在独立的main线程上。
服务不是单一的进程,服务没有自己的进程,应用程序可以不同,服务运行在相同的进程中
服务不是线程,可以在线程中工作
在应用中,如果是长时间的在后台运行,而且不需要交互的情况下,使用服务
同样是在后台运行,不需要交互的情况下,如果只是完成某个任务,之后就不需要运行,而且可能是多个任务,需要长时间运行的情况下使用线程
如果任务占用CPU时间多,资源大的情况下,要使用线程
Thread的运行是独立于Activity的,也就是说当一个Activity被finish之后,如果你没有主动停止Thread或者Thread里的run方法没有执行完毕的话,Thread就会一直执行。