Android版本差异
https://developer.android.com/about/versions/oreo/index.html
持久化存储方式
https://segmentfault.com/a/1190000008949310
缓存
图片缓存
https://binglumeng.github.io/2017/03/21/%E5%9B%BE%E7%89%87%E7%BC%93%E5%AD%98LruCache%E5%92%8CDiskLruCache%E4%BD%BF%E7%94%A8/
https://www.kancloud.cn/digest/android222/138556
https://www.jianshu.com/p/97455f080065
长连接
https://blog.csdn.net/carson_ho/article/details/79522975
Android产品研发问题
https://blog.csdn.net/qq_23547831/article/details/51645787
Android后台优化
https://developer.android.com/guide/background/index.html
https://developer.android.com/topic/performance/background-optimization.html
AlarmManager
https://juejin.im/entry/588628e8128fe10065eb62a9
Broadcast
https://www.jianshu.com/p/f01faada90da
保持设备唤醒
https://developer.android.com/training/scheduling/index.html
进程保活
https://segmentfault.com/a/1190000006251859
https://github.com/xingda920813/HelloDaemon
https://blog.csdn.net/xiangzhihong8/article/details/77919053
https://blog.csdn.net/AndrExpert/article/details/75045678
http://www.infoq.com/cn/articles/wechat-android-background-keep-alive
https://juejin.im/entry/58acf391ac502e007e9a0a11
Android45678区别和改进 App层
https://www.zhihu.com/question/29639050
https://blog.csdn.net/qq_14859923/article/details/78257904
http://www.jensondev.me/2017/07/26/Android%E5%90%84%E7%89%88%E6%9C%AC%E6%96%B0%E5%8A%9F%E8%83%BD%E5%8F%8A%E5%8C%BA%E5%88%AB/
https://blog.csdn.net/huang_rong12/article/details/51252186
进程什么时候销毁
http://www.cnblogs.com/lesliefang/p/5379212.html
Android优化checklist
https://aeli.gitbooks.io/android-training-course/performance/memory.html
Android开源框架源码解析
http://a.codekk.com/
反射
https://blog.csdn.net/yongjian1092/article/details/7364451
三、JAVA反射机制提供了什么功能
Java反射机制提供如下功能:
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判段任意一个类所具有的成员变量和方法
在运行时调用任一个对象的方法
在运行时创建新类对象
动态代理
代理:
- 隐藏委托类的实现
- 解耦,不改变委托类代码情况下做一些额外处理,比如添加初始判断及其他公共操作
静态:代理类在程序运行前已经存在的代理方式称为静态代理。静态代理可以理解为对象的组合。
实现动态代理包括三步:
(1). 新建委托类;
(2). 实现InvocationHandler接口,这是负责连接代理类和委托类的中间类必须实现的接口;
(3). 通过Proxy类新建代理类对象。
public class TimingInvocationHandler implements InvocationHandler {
private Object target;
public TimingInvocationHandler() {}
public TimingInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = System.currentTimeMillis();
Object obj = method.invoke(target, args);
System.out.println(method.getName() + " cost time is:" + (System.currentTimeMillis() - start));
return obj;
}
}
public class Main {
public static void main(String[] args) {
// create proxy instance
TimingInvocationHandler timingInvocationHandler = new TimingInvocationHandler(new OperateImpl());
Operate operate = (Operate)(Proxy.newProxyInstance(Operate.class.getClassLoader(), new Class[] {Operate.class},
timingInvocationHandler));
// call method of proxy instance
operate.operateMethod1();
System.out.println();
operate.operateMethod2();
System.out.println();
operate.operateMethod3();
}
}
public Object invoke(Object proxy, Method method, Object[] args)
函数需要去实现,参数:
proxy表示下面2.3 通过 Proxy.newProxyInstance() 生成的代理类对象。
method表示代理对象被调用的函数。
args表示代理对象被调用的函数的参数。
调用代理对象的每个函数实际最终都是调用了InvocationHandler的invoke函数。这里我们在invoke实现中添加了开始结束计时,其中还调用了委托类对象target的相应函数,这样便完成了统计执行时间的需求。
invoke函数中我们也可以通过对method做一些判断,从而对某些函数特殊处理。
这里我们先将委托类对象new OperateImpl()作为TimingInvocationHandler构造函数入参创建timingInvocationHandler对象;
然后通过Proxy.newProxyInstance(…)函数新建了一个代理对象,实际代理类就是在这时候动态生成的。我们调用该代理对象的函数就会调用到timingInvocationHandler的invoke函数(是不是有点类似静态代理),而invoke函数实现中调用委托类对象new OperateImpl()相应的 method(是不是有点类似静态代理)。
public static Object newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h)
loader表示类加载器
interfaces表示委托类的接口,生成代理类时需要实现这些接口
h是InvocationHandler实现类对象,负责连接代理类和委托类的中间类
我们可以这样理解,如上的动态代理实现实际是双层的静态代理,开发者提供了委托类 B,程序动态生成了代理类 A。开发者还需要提供一个实现了InvocationHandler的子类 C,子类 C 连接代理类 A 和委托类 B,它是代理类 A 的委托类,委托类 B 的代理类。用户直接调用代理类 A 的对象,A 将调用转发给委托类 C,委托类 C 再将调用转发给它的委托类 B。
动态代理得原理:
http://a.codekk.com/detail/Android/Caij/%E5%85%AC%E5%85%B1%E6%8A%80%E6%9C%AF%E7%82%B9%E4%B9%8B%20Java%20%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86
public final class $Proxy0 extends Proxy
implements Operate
{
private static Method m4;
private static Method m1;
private static Method m5;
private static Method m0;
private static Method m3;
private static Method m2;
public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
public final void operateMethod1()
throws
{
try
{
h.invoke(this, m4, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
从中我们可以看出动态生成的代理类是以$Proxy为类名前缀,继承自Proxy,并且实现了Proxy.newProxyInstance(…)第二个参数传入的所有接口的类。
如果代理类实现的接口中存在非 public 接口,则其包名为该接口的包名,否则为com.sun.proxy。
其中的operateMethod1()、operateMethod2()、operateMethod3()函数都是直接交给h去处理,h在父类Proxy中定义为
protected InvocationHandler h;
即为Proxy.newProxyInstance(…)第三个参数。
所以InvocationHandler的子类 C 连接代理类 A 和委托类 B,它是代理类 A 的委托类,委托类 B 的代理类。
Anotation注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface MethodInfo {
String author() default "[email protected]";
String date();
int version() default 1;
}
public class App {
@MethodInfo(
author = “[email protected]”,
date = "2014/02/14",
version = 2)
public String getAppName() {
return "trinea";
}
}
public static void main(String[] args) {
try {
Class cls = Class.forName("cn.trinea.java.test.annotation.App");
for (Method method : cls.getMethods()) {
MethodInfo methodInfo = method.getAnnotation(
MethodInfo.class);
if (methodInfo != null) {
System.out.println("method name:" + method.getName());
System.out.println("method author:" + methodInfo.author());
System.out.println("method version:" + methodInfo.version());
System.out.println("method date:" + methodInfo.date());
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
依赖注入
通过 @Inject 注解了构造函数之后,在 Activity 中的 Boss 属性声明之前也添加 @Inject 注解。像这种在属性前添加的 @Inject 注解的目的是告诉 Dagger 哪些属性需要被注入。
public class MainActivity extends Activity {
@Inject Boss boss;
...
}
最后,我们在合适的位置(例如 onCreate() 函数中)调用 ObjectGraph.inject() 函数,Dagger 就会自动调用上面 (1) 中的生成方法生成依赖的实例,并注入到当前对象(MainActivity)。
public class MainActivity extends Activity {
@Inject Boss boss;
@Override
protected void onCreate(Bundle savedInstanceState) {
ObjectGraph.create(AppModule.class).inject(this);
}
...
}
具体怎么注入即设置的过程后面会详细介绍,这里简单透露下,APT 会在 MainActivity 所在 package 下生成一个辅助类 MainActivity$$InjectAdapter,这个类有个 injectMembers() 函数,代码类似:
public void injectMembers(MainActivity paramMainActivity) {
paramMainActivity.boss = ((Boss)boss.get());
……
}
上面我们已经通过 ObjectGraph.inject() 函数传入了 paramMainActivity,并且 boss 属性是 package 权限,所以 Dagger 只需要调用这个辅助类的 injectMembers() 函数即可完成依赖注入,这里的 boss.get() 会调用 Boss 的生成函数。
到此为止,使用 Dagger 的 @Inject 方式将一个 Boss 对象注入到 MainActivity 的流程就完成了。
public class Human {
...
@Inject Father father;
...
public Human() {
}
}
public class Human {
...
Father father;
...
public Human() {
father = new Father();
}
}
切面编程
Android view绘制
http://a.codekk.com/detail/Android/lightSky/%E5%85%AC%E5%85%B1%E6%8A%80%E6%9C%AF%E7%82%B9%E4%B9%8B%20View%20%E7%BB%98%E5%88%B6%E6%B5%81%E7%A8%8B
measure 过程由measure(int, int)方法发起,从上到下有序的测量 View,在 measure 过程的最后,每个视图存储了自己的尺寸大小和测量规格。 layout 过程由layout(int, int, int, int)方法发起,也是自上而下进行遍历。在该过程中,每个父视图会根据 measure 过程得到的尺寸来摆放自己的子视图。
measure 过程会为一个 View 及所有子节点的 mMeasuredWidth 和 mMeasuredHeight 变量赋值,该值可以通过 getMeasuredWidth()和getMeasuredHeight()方法获得。而且这两个值必须在父视图约束范围之内,这样才可以保证所有的父视图都接收所有子视图的测量。如果子视图对于 Measure 得到的大小不满意的时候,父视图会介入并设置测量规则进行第二次 measure。比如,父视图可以先根据未给定的 dimension 去测量每一个子视图,如果最终子视图的未约束尺寸太大或者太小的时候,父视图就会使用一个确切的大小再次对子视图进行 measure。
Android view事件
http://a.codekk.com/detail/Android/Trinea/%E5%85%AC%E5%85%B1%E6%8A%80%E6%9C%AF%E7%82%B9%E4%B9%8B%20View%20%E4%BA%8B%E4%BB%B6%E4%BC%A0%E9%80%92
(1) 事件从 Activity.dispatchTouchEvent()开始传递,只要没有被停止或拦截,从最上层的 View(ViewGroup)开始一直往下(子 View)传递。子 View 可以通过 onTouchEvent()对事件进行处理。
(2) 事件由父 View(ViewGroup)传递给子 View,ViewGroup 可以通过 onInterceptTouchEvent()对事件做拦截,停止其往下传递。
(3) 如果事件从上往下传递过程中一直没有被停止,且最底层子 View 没有消费事件,事件会反向往上传递,这时父 View(ViewGroup)可以进行消费,如果还是没有被消费的话,最后会到 Activity 的 onTouchEvent()函数。
(4) 如果 View 没有对 ACTION_DOWN 进行消费,之后的其他事件不会传递过来。
(5) OnTouchListener 优先于 onTouchEvent()对事件进行消费。