ViewGroup
computeScroll()方法是在View类的draw()方法中被调用的,因此重写computeScroll()相似滚动效果时是讲ViewGroup进行移动的app
onInterceptTouchEvent(MotionEvent ev)当没有子类或者有子类但没有消费事件能力时,只会拦截到ACTION_DOWN事件,(dispatchTouchEvent(MotionEvent ev)通过第一次派发后,mFirstTouchTarget依然为空,就不进行拦截直接交给本身的onTouchEvent(MotionEvent event)处理了)后续的事件都不会调用本方法。但onTouchEvent(MotionEvent event)中全部的事件都会触发 Scroller 速度计算类(滚动计算类),其实就是一个为了实现有中间过程的一个类,单纯的数据计算,这样很好的作到了视图和数据的分开。异步
startScroll()只是对基本的配置进行了设置,并无作什么对视图实质性的操做, 因此在重写computeScroll()时,须要调用computeScrollOffset()后才会生成新的getCurrX()getCurrY(),scrollTo(mScroller.getCurrX(), mScroller.getCurrY())去一点一点移动到指定位置;另外须要调用postInvalidate()才能刷新看到效果。函数
MotionEvent
MotionEventCompat.getActionMasked(ev)获取的只有动做信息的action,没有点的pointerId信息。post
ACTION_CANCEL 当用户保持按下操做,并从你的控件转移到外层控件时会触发优化
ViewDragHelper
一个手势拖动的实现类,用于自定义的ViewGroup。this
IntentService
onStartCommand(Intent intent, int flags, int startId) 运行在主线程中,因此操做UI相关的能够放在这。spa
onHandleIntent(Intent intent) 结束任务后自动回收。线程
系统回收、手机管家
手机管家不会对launcher进行清理。code
在应用进行升级时,本身能接受到本身的升级广播。系统只会结束相关包名的activity,若是该activity不在task根部,并不会退出整个栈中的数据,若是在根部,那么会结束整个task。对象
Dialog
当dialog为普通dialog时,须要依赖activity,因此传递进去的context必须为activity。 若是设置getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST),那么context需为applicationContext。
ExecutorService
一个任务队列,全部提交的任务是异步执行的。 当ExecutorService.submit(Callable).get()去获取执行结果时,该方法会进入死循环获取结果,阻塞后面的代码。
Android应用中的默认加载器。
他们的区别是:
DexClassLoader能够加载任何路径的apk/dex/jar
PathClassLoader只能加载/data/app中的apk,也就是已经安装到手机中的apk。这个也是PathClassLoader做为默认的类加载器的缘由,由于通常程序都是安装了,在打开,这时候PathClassLoader就去加载指定的apk(解压成dex,而后在优化成odex)就能够了。
1.@SuppressLint("NewApi")
2. protected void launchTargetActivity(final String className) {
3. File dexOutputDir = this.getDir("dex", 0);
4. final String dexOutputPath = dexOutputDir.getAbsolutePath();
5. ClassLoader localClassLoader = ClassLoader.getSystemClassLoader();
6. DexClassLoader dexClassLoader = new DexClassLoader(mDexPath,
7. dexOutputPath, null, localClassLoader);
8. try {
9. Class> localClass = dexClassLoader.loadClass(className);
10. Constructor> localConstructor = localClass
11. .getConstructor(new Class[] {});
12. Object instance = localConstructor.newInstance(new Object[] {});
13. Log.d(TAG, "instance = " + instance);
14.
15. Method setProxy = localClass.getMethod("setProxy",
16. new Class[] { Activity.class });
17. setProxy.setAccessible(true);
18. setProxy.invoke(instance, new Object[] { this });
19.
20. Method onCreate = localClass.getDeclaredMethod("onCreate",
21. new Class[] { Bundle.class });
22. onCreate.setAccessible(true);
23. Bundle bundle = new Bundle();
24. bundle.putInt(FROM, FROM_EXTERNAL);
25. onCreate.invoke(instance, new Object[] { bundle });
26. } catch (Exception e) {
27. e.printStackTrace();
28. }
29. }
说明:程序不难理解,思路是这样的:采用DexClassLoader去加载apk,而后若是没有指定class,就调起主activity,不然调起指定的class。activity被调起的过程是这样的:首先经过类加载器去加载apk中activity的类并建立一个新对象,而后经过反射去调用这个对象的setProxy方法和onCreate方法,setProxy方法的做用是将activity内部的执行所有交由宿主程序中的proxy(也是一个activity),onCreate方法是activity的入口,setProxy之后就调用onCreate方法,这个时候activity就被调起来了。
Launcher启动方式建立
来回切换默认launcher时的建立过程,(standard模式singleTask模式,其余未验证)
02-27 10:13:30.768 24902-24902/com.justsy.launcher I/MAIN_ACTIVITY: null create 233216691 >> 普通图标点击运行
02-27 10:14:01.829 24902-24902/com.justsy.launcher I/MAIN_ACTIVITY: null create 149814510 >> home键运行
02-27 10:14:37.277 25235-25235/com.justsy.launcher I/MAIN_ACTIVITY: null create 500170786 >> home键运行
02-27 10:15:11.097 25424-25424/com.justsy.launcher I/MAIN_ACTIVITY: null create 500170786 >> home键运行
02-27 10:15:11.097 25424-25424/com.justsy.launcher I/MAIN_ACTIVITY: null create 500170786 >> home键运行
一、都没有重用的bundle。二、第二次home键后建立的对象都是同一个
事件传递
dispatchTouchEvent
最早调用的方法,负责事件的分发,有源代码,通常不会去动这个函数。里面有调用onInterceptTouchEvent方法。
onInterceptTouchEvent
判断是否须要拦截事件。当不拦截时,事件会逐层传递,值得注意的是,一旦return true,后续事件将再也不调用 onInterceptTouchEvent方法,而是直接交由onTouchEvent方法处理。
onTouchEvent
最后事件处理的地方,这里通常会写重写后事件处理的东西。