- 说明:部分内容来自网络,若有侵权请联系我删除
Android - Java
-
补间动画 :是对某个View进行一系列的动画的操作,包括淡入淡出(Alpha),缩放(Scale),平移(Translate),旋转(Rotate)四种模式。
-
帧动画 : 将多张图片组合起来进行播放,类似于早期电影的工作原理,很多App的loading是采用这种方式
-
属性动画 : 属性动画不再仅仅是一种视觉效果了,而是一种不断地对值进行操作的机制,并将值赋到指定对象的指定属性上,可以是任意对象的任意属性
-
打开ActivityA
onCreate(A) -> onStart(A) -> onResume(A) -
打开ActivityB
onPause(A) -> onCreate(B) -> onStart(B) -> onResume(B) -> onStop(A) -
回到ActivtyA
onPause(B) -> onRestart(A) -> onStart(A) -> onResume(A) -> onStop(B) -> onDestory(B)
- 当用户按下 Home 键时
- 长按 Home 键选择其他程序时
- **从一个 Activity 切换到另一个 Activity **
- 按下电源键或者锁屏时
- 屏幕方向切换时(如果不指定configchange属),在屏幕切换之前,系统会销毁 activity,在屏幕切换之后系统又会自动地创建activity,所以 onSaveInstanceState 一定会被执行
- 释义 HandlerThread 是可以创建带有 looper 新线程的类
- 链接 http://blog.csdn.net/javazejian/article/details/52426353
- 等待补充
- 内存溢出 : OUT OF MEMORY 是指程序在申请内存时超出了系统能分配给你的,于是产生溢出
- 内存泄漏 : MEMORY LEAK 是指系统分配出去的内存无法回收了
//1
Looper.getMainLooper() == Looper.myLooper();
//2
Looper.getMainLooper().getThread() == Thread.currentThread();
//3
Looper.getMainLooper().getThread().getId() == Thread.currentThread().getId();
| 面向对象六大原则 | 单例模式 | Builder模式 |
| 原型模式 | 简单工厂 | 工厂方法模式 |
| 抽象工厂模式 | 策略模式 | 状态模式 |
| 责任链模式 | 解释器模式 | 命令模式 |
| 观察者模式 | 备忘录模式 | 迭代器模式 |
| 模板方法模式 | 访问者模式 | 中介者模式 |
| 代理模式 | 组合模式 | 适配器模式 |
| 装饰模式 | 享元模式 | 外观模式 |
- 两个参数的意义: 父控件对View的宽高约束
- http://blog.csdn.net/xmxkf/article/details/51490283
-
绘制过程:View的绘制过程是从ViewRoot 的 performTraversals 方法开始的, 它经过 measure、layout 和 draw 三个过程才能最终将一个 View 绘制出来,其中 measure 用来测量 View 的宽高,layout 用来确定 view 在容器中的位置,draw 则负责将 view 绘制在屏幕上
-
流程图
-
链接
-
书籍参考
- 《Android开发艺术探索》第四章 P176
ActivityManagerService ->
ActivityStackSupervisor ->
ActivityStack ->
ActivityStackSupervisor ->
ApplicationThread
- 链接
-
Handler 是Android类库提供的用于接受、传递和处理消息或Runnable对象的处理类,它结合Message、MessageQueue和Looper类以及当前线程实现了一个消息循环机制,用于实现任务的异步加载和处理
-
主要用途
-
执行定时任务 指定任务时间,在某个具体时间或某个时间段后执行特定的任务操作,例如使用Handler提供的postDelayed(Runnable r,long delayMillis)方法指定在多久后执行某项操作
-
线程间的通信 在执行较为耗时的操作时,Handler负责将子线程中执行的操作的结果传递到UI线程,然后UI线程再根据传递过来的结果进行相关UI元素的更新
-
-
Handler用法
-
根据上面的图片,我们现在来解析一下异步消息处理机制
-
Message:消息体,用于装载需要发送的对象
-
handler:它直接继承自Object。作用是:在子线程中发送Message或者Runnable对象到MessageQueue中;在UI线程中接收、处理从MessageQueue分发出来的Message或者Runnable对象。发送消息一般使用Handler的sendMessage()方法,而发出去的消息经过处理后最终会传递到Handler的handlerMessage()方法中
-
MessageQueue:用于存放Message或Runnable对象的消息队列。它由对应的Looper对象创建,并由Looper对象管理。每个线程中都只会有一个MessageQueue对象
-
Looper:是每个线程中的MessageQueue的管家,循环不断地管理MessageQueue接收和分发Message或Runnable的工作。调用Looper的loop()方法后,就会进入到一个无限循环中然后每当发现MessageQueue中存在一条消息,就会将它取出,并调用Handler的handlerMessage()方法。每个线程中也只会有一个Looper对象
-
-
Handler和Looper对象是属于线程内部的数据,不过也提供与外部线程的访问接口,Handler就是公开给外部线程的接口,用于线程间的通信。Looper是由系统支持的用于创建和管理MessageQueue的依附于一个线程的循环处理对象,而Handler是用于操作线程内部的消息队列的,所以Handler也必须依附一个线程,而且只能是一个线程
-
链接
-
定义
- 用于维护全局应用程序状态的基础类
- 代表应用程序的类,也属于Android中的一个系统组件
- 继承关系: 继承自 ContextWarpper 类
-
Application 与 Context
- Activity、Service、Application 都是 Context 的子类。Context 是一个抽象类,具体的实现是在 ContextImpl 类中。因此应用程序 APP 共用的 Context 数目公式为:
context数 = Service数 + Actvity数 + 1(Application 对应的 Context 实例)
- Activity、Service、Application 都是 Context 的子类。Context 是一个抽象类,具体的实现是在 ContextImpl 类中。因此应用程序 APP 共用的 Context 数目公式为:
-
特点
-
实例创建方式:单例模式
- 每个 APP 运行时会首先自动创建 application 类并实例化 application 对象且只有一个(即 application 类是单例模式)
- 可以通过继承 application 来实现自定义的 application 类
-
实例形式:全局模式,即不同组件都可以获得 application 对象且都是同一个
-
生命周期:等于 APP 的生命周期.
-
-
连接
-
APK安装的主要步骤
- 将 apk 文件复制到 /data/app/ 目录下
- 解压 apk ,拷贝文件, 创建应用的数据目录
- 解析 apk 的AndroidManifinest.xml 文件
- 显示快捷方式
-
链接
-
在 View 的默认实现中 View 的测量宽/高和最终宽/高是相等的,只不过 测量宽高(getMeasureWidth/Height)是在 view 的 measure 过程中调用的,而 view 的 最终宽高(getWidth/Height)是在 view 的 layout 过程中调用的;即两者的赋值时机不同,测量宽高比最终宽高获取的时机稍微早点;
-
在一般开发中这两者的值是一样的,但是也会存在特殊情况,
-
比如在 view 的 layout 方法中:
public void layout(int l, int t, int r, int b){ super.layout(l, t, r+100, b+100); }这个步骤就会导致测量宽高比最终宽高小 100px
-
另一种情况是在某些情况下 View 需要多次 measure 才能确定自己的测量宽高,在前几次的测量宽高过程中得出的值可能和最终宽高的不一致,但最终来说:测量宽高和最终宽高相等
-
-
Android事件分发流程
Activity(Windwos) -> ViewGroup -> View- 对于
dispatchTouchEvent,onTouchEvent返回 true 就是自己消费了,返回 false 就传到父View 的onTouchEvent方法 - ViewGroup 想把事件分发给自己的
onTouchEvent,需要在onInterceptTouchEvent方法中返回 true 把事件拦截下来 - ViewGroup 的
onInterceptTouchEvent默认不拦截,所以super.onInterceptTouchEvent() = false - View(这里指没有子View)没有拦截器,所以 View 的
dispatchTouchEvent的super.dispatchTouchEvent(event)默认把事件分发给自己的onTouchEvent
- 对于
-
链接
- 等待补充
- 等待补充
- 等待补充
- 等待补充
-> 进程数*16M
-
有视图的地方就有 Window,比如 Activity、Dialog、Toast、PopUpWindows、菜单 等视图都对应着一个window.
-
连接
-
Dialog初化始时是通过Context.getSystemServer 来获取 WindowManager,而如果用Application或者Service的Context去获取这个WindowManager服务的话,会得到一个WindowManagerImpl的实例,这个实例里token也是空的。之后在Dialog的show方法中将Dialog的View(PhoneWindow.getDecorView())添加到WindowManager时会给token设置默认值还是null。 如果这个Context是Activity,则直接返回Activity的mWindowManager,这个mWindowManager在Activity的attach方法被创建,Token指向此Activity的Token,mParentWindow为Activity的Window本身
-
答案
那为什么一定要是Activity的Token呢?我想使用Token应该是为了安全问题,通过Token来验证WindowManager服务请求方是否是合法的。如果我们可以使用Application的Context,或者说Token可以不是Activity的Token,那么用户可能已经跳转到别的应用的Activity界面了,但我们却可以在别人的界面上弹出我们的Dialog,想想就觉得很危险。
-
原因
- Error
- OOM , 内存溢出
- StackOverFlowError
- RuntimeException(比如空指针异常)
-
如何避免
- 注意内存的使用和管理
- 可以实现Thread.UncaughtExceptionHandler接口的uncaughtException方法
-
对于使用了Boardcast Receive、ContentObserver、File、Cursor、Stream、Bitmap等资源的时候没有销毁。
解决方法 -> 应该在不使用的时候关闭或者注销 -
静态内部类持有外部成员变量
解决方法 -> 可以使用若引用 -
使用了 context 持有 Activity 导致 Activity无法释放
解决方法 -> 使用 ApplicationContext -
集合中没有使用的对象没有及时 remove
-
handler 引起的内存泄漏
解决方法 -> 使用若引用持有 Activity等的 Context -
设置过的Listener没有及时移除
解决方法 -> 在destory 里 设置 Listener 为 null
- 每个进程都会创建一个独立的虚拟机
- 实现原理 利用
Transform - 代码示例
public class GlideRoundTransform extends BitmapTransformation { private static float radius = 0f; /** * 构造函数 默认圆角半径 4dp * * @param context Context */ public GlideRoundTransform(Context context) { this(context, 4); } /** * 构造函数 * * @param context Context * @param dp 圆角半径 */ public GlideRoundTransform(Context context, int dp) { super(context); radius = Resources.getSystem().getDisplayMetrics().density * dp; } @Override protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) { return roundCrop(pool, toTransform); } private static Bitmap roundCrop(BitmapPool pool, Bitmap source) { if (source == null) return null; Bitmap result = pool.get(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888); if (result == null) { result = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888); } Canvas canvas = new Canvas(result); Paint paint = new Paint(); paint.setShader(new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP)); paint.setAntiAlias(true); RectF rectF = new RectF(0f, 0f, source.getWidth(), source.getHeight()); canvas.drawRoundRect(rectF, radius, radius, paint); return result; } @Override public String getId() { return getClass().getName() + Math.round(radius); } }


