概述:见过很多App启动的速度都很慢(包括自己以前写的),于是想了一下:启动的时候是不是可以启动一个新的线程来加载和初始化数据呢?于是写了一个小Demo

APP启动流程:

Application构造函数--->attachBaseContext()--->onCreat()--->Activity生命周期

当在上述调用链中进行耗时任务时将会导致APP启动延时故尽量不要执行耗时任务

开启新线程优化数据加载(初始化数据)

加入新线程执行结果:(在MainActivity的onCreat也计时)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Application的attachBaseContext方法:
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
Log.i("TAG", "attachBaseContext时间:=" + System.currentTimeMillis());

HandlerThread thread = new HandlerThread("compute");
thread.start();

Handler h = new Handler(thread.getLooper());
h.post(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10000000; i++) {
total += i;
}
}
});

Log.i("TAG", "attachBaseContext" + total);
}

不加线程直接循环的结果:

概述:单例模式是最简单的,也是用的比较多的,这里记录一下常见几种单例的写法的优缺点。

代码:

饿汉式

1
2
3
4
5
6
7
8
9
10
//线程安全但耗资源
class Singleton {
private static final Singleton instance = new Singleton();

private Singleton() { }

public static Singleton getInstance() {
return instance;
}
}

懒汉式

1
2
3
4
5
6
7
8
9
10
11
12
class Singleton {   
private static Singleton instance = null; //延迟加载

private Singleton() { }

synchronized public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
  • 在方法上加锁:每次调用方法都用锁,效率低下,我们可以考虑在对象为null时才锁

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public static Singleton getInstance() {   
    if (instance == null) {
    //第二个线程进来了
    synchronized (Singleton.class) {
    //第一个线程走到这里
    instance = new Singleton();
    }
    }
    return instance;
    }
  • 这样做线程又不安全了如上注释

用双重锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Singleton {   
private volatile static Singleton instance = null;

private Singleton() { }

public static Singleton getInstance() {
//第一重判断
if (instance == null) {
//锁定代码块
synchronized (Singleton.class) {
//第二重判断
if (instance == null) {
instance = new Singleton(); //创建单例实例
}
}
}
return instance;
}
}

即实现懒加载又线程安全的方式

1
2
3
4
5
6
7
8
9
10
11
12
class Singleton {  
private Singleton() {
}

private static class HolderClass {
private final static Singleton instance = new Singleton();
}

public static Singleton getInstance() {
return HolderClass.instance; //初始化类时才初始化外部类对象:懒加载
}
}

概述:阅读《深入理解JAVA虚拟机》第七章时的几个例子。

代码:

  • 引用数组的初始化
  • 常量的初始化
  • 子类父类静态字段的初始化
1
2
3
4
5
6
public class SuperClass {
static{
System.out.println("SuperClass被初始化了");
}
public static int value = 123;
}

1
2
3
4
5
6
7
public class SubClass extends SuperClass {

static {
System.out.println("SubClass 初始化了");
}

}

1
2
3
4
5
6
7
public class ConstClass {
static {
System.out.println("Const 被初始化了");
}
//常量在编译阶段会调入类的常量池中,本质上并没有直接引用到定义常量的类中,因此不会触发定义常量的类的初始化
public static final String HELLO_WORD = "hello word";
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//测试代码
public class Test {

public static void main(String[] args) {
//1.new一个类的数组时这个类不会被初始化
// SuperClass[] a = new SuperClass[12];
// System.out.println("1");

//2、编译期常量,类不会被初始化
// System.out.println(ConstClass.HELLO_WORD);

//3、通过子类来引用父类的静态字段只会触发父类的初始化
// System.out.println(SubClass.value);

}

}

总结:

  • 1、new一个类的数组时这个类不会被初始化
  • 2、编译期常量,类不会被初始化
  • 3、通过子类来引用父类的静态字段只会触发父类的初始化

概述:总感觉设计模式这东西是可遇而不可求的,没有大量的代码经验很难理解它(记住和理解是有天壤之别的)。放假的时候看到过一个项目,当时是站在学习自定义View的角度分析它的源码的,觉得这代码写的很优雅,直到今天看了策略模式我才突然想起这个项目,恍然大悟,原来那就是策略模式。

策略模式

通用类图:

这里的抽象策略角色就是上述项目里的BaseIndicatorController

其所有的具体策略角色为项目中所有的子类

Context封装角色就是项目里的AVLoadingIndicatorView

多阅读优秀源码,见多识广,才能理解设计模式。