0%

startService()
  • 启动的服务处于“启动的”状态,一旦启动,service就在后台运行,即使启动它的应用组件已经被销毁了
  • 通常started状态的service执行单任务并且==不返回任何结果==给启动者
bindService()
  • 一个绑定的service提供一个允许组件与service交互的接口,可以发送请求、获取返回结果,还可以通过夸进程通信来交互(IPC)。
  • ==绑定的service只有当应用组件绑定后才能运行==,多个组件可以绑定一个service,当调用unbind()方法时,这个service就会被销毁了。
注意:==service与activity一样都存在与当前进程的主线程中==,所以,一些阻塞UI的操作,比如耗时操作不能放在service里进行,比如另外开启一个线程来处理诸如网络请求的耗时操作。
IntentService
  • IntentService使用队列的方式将请求的Intent加入队列,然后开启一个worker thread(线程)来处理队列中的Intent,对于异步的startService请求,IntentService会处理完成一个之后再处理第二个,每一个请求都会在一个单独的worker thread中处理,==不会阻塞应用程序的主线程==

参考

Android service服务-张雪源的博客

懒汉式

  • 使用时才实例化
  • 使用场景:单例使用次数不多、功能复杂,占用内存大、实例化时间长、特定场景、延迟加载。
  • ==线程不安全==:多个线程可能会并发调用他的newInstance方法导致多个线程可能会创建多份相同的单例出来。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class Singleton{
    private static Singleton instance = null;

    private Singleton(){}

    public static Singleton newInstance(){
    if(null == instance){
    instance = new Singleton();
    }
    return instance;
    }
    }

懒汉式同步锁

使用同步锁synchronized (Singleton.class)解决线程不安全问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Singleton {

private static Singleton instance = null;

private Singleton(){
}

public static Singleton getInstance() {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}

return instance;
}
}

双重校验锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Singleton {

private static volatile Singleton instance = null;

private Singleton(){
}

public static Singleton getInstance() {
// if already inited, no need to get lock everytime
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}

return instance;
}
}

饿汉式

  • 简单快速,实例化快
  • 使用场景:占用内存较小的、应用启动时加载初始化的
  • 线程安全:因为JVM只会加载一次单例类
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class Singleton{

    private static Singleton instance = new Singleton();

    private Singleton(){}

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

jvm的类加载机制

JVM已经为我们提供了同步控制

  • 在static{}区块中初始化的数据
  • 访问final字段时
  • …..

静态内部类

  • 简洁
  • 使用场景:
  • 线程安全:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public class Singleton{
    //内部类,在装载该内部类时才会去创建单利对象
    private static class SingletonHolder{
    public static Singleton instance = new Singleton();
    }

    private Singleton(){}

    public static Singleton newInstance(){
    return SingletonHolder.instance;
    }

    public void doSomething(){
    //do something
    }
    }

    枚举类

  • 最简单
  • 线程安全:
    1
    2
    3
    4
    5
    6
    7
    8
    public enum Singleton{
    //定义一个枚举的元素,它就是Singleton的一个实例
    instance;

    public void doSomething(){
    // do something ...
    }
    }

使用方法

1
2
3
4
public static void main(String[] args){
Singleton singleton = Singleton.instance;
singleton.doSomething();
}

参考

ANDROID设计模式之单例模式

参考

创建RxJava.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class RxBus {
private static volatile RxBus instance;
private final Subject<Object, Object> BUS;

// PublishSubject只会把在订阅发生的时间点之后来自原始Observable的数据发射给观察者
public RxBus() {
BUS = new SerializedSubject<>(PublishSubject.create());
}

// 单例RxBus
public static RxBus getDefault() {
if (instance == null) {
synchronized (RxBus.class) {
if (instance == null) {
instance = new RxBus();
}
}
}
return instance;
}

// 发送一个新的事件
public void post(Object o) {
BUS.onNext(o);
}

// 根据传递的 eventType 类型返回特定类型(eventType)的 被观察者
public <T> Observable<T> toObservable(Class<T> eventType) {
return BUS.ofType(eventType);
// 这里感谢小鄧子的提醒: ofType = filter + cast
// return bus.filter(new Func1<Object, Boolean>() {
// @Override
// public Boolean call(Object o) {
// return eventType.isInstance(o);
// }
// }) .cast(eventType);
}
}

使用

1
2
3
4
5
6
RxBus.getDefault().toObservable(String.class).subscribe(new Action1<String>() {
@Override
public void call(String s) {
Toast.makeText(BleActivity.this,s,Toast.LENGTH_SHORT).show();
}
});

注意取消订阅

  • CompositeSubscription 可以把 Subscription 收集到一起,方便 Activity 销毁时取消订阅,防止内存泄漏。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    private CompositeSubscription allSubscription = new CompositeSubscription();
    //添加订阅到列表
    allSubscription.add(RxBus.getDefault()
    .toObserverable(OneEvent.class).subscribe(this::response));
    //销毁时删除订阅
    @Override
    protected void onDestroy() {
    super.onDestroy();
    if (allSubscription != null && !allSubscription.isUnsubscribed())
    allSubscription.unsubscribe();
    }

启动图标

  • hdpi 72*72
  • mdpi 48*48
  • xhdpi 96*96
  • xxhdpi 144*144
  • xxxhdpi 192*192

参考网址

使用过的操作符

  • concat 连接多个Observables(被观察者)
    concat
    最多有9个参数,但是可以嵌套,传的数据必须是相同类型
  • mergeDelayError 合并发送
    MergeDelayError
    合并两个发送,如果一个出错不马上发送错误,而是延时到都发送完
  • interval 定时循环发送
    interval
  • map 数据类型转换(同步)
    map
  • flatmap 传入数据,生成新的Observable,一般处理异步任务,连接能实现concat功能
    flatmap
  • distinct 过滤去重操作符
    distinct
  • distinct(Func1) 自定义过滤操作符
    distintF1
    可以以其中的某个重复项为过滤条件
  • repeat 重复发送
    repeat
    重复订阅
  • retry 错误重试
    retry
    发送一个错误(onError),重新订阅
  • retryWhen(Func1) 判断错误,根据错误(func1)决定是否重新订阅
    retryWhen
    发送一个错误(onError),通过func1处理错误,决定是否再次订阅
  • Timeout 超时发送一个onError
    Timeout
  • zip 组合
    zip
  • zipwith 组合
    zipwith
    两个都发送onnext后组合,如果另外一个未发,等待组合后才开始发下一个
  • delay 延时发送
    delay

button点击事件

1
2
3
4
5
6
7
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

}
});
button.performClick(); //触发点击事件

从上面代码理解:
被观察者Observable—–>button—–>一些操作,事件,任务(相当于我们不知道button什么时候被点击)
观察者Observer/Subscriber—–>OnClickListener—–>决定事件触发的时候将有怎样的行为
订阅Subscribe—–>setOnClickListener—–>注册事件关联
事件onNext()/onCompleted()/onError()—–>onClick()—–>回调,最终结果(Subscriber多了onStart()``unsubscribe())

Observable 被观察者

创建被观察者

  • creat() 最基本的创造事件序列的方法
1
2
3
4
5
6
7
8
9
Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello");
subscriber.onNext("Hi");
subscriber.onNext("Aloha");
subscriber.onCompleted();
}
});
  • just() 快捷创建事件序列
1
2
3
4
5
6
Observable observable = Observable.just("Hello", "Hi", "Aloha");
// 将会依次调用:
// onNext("Hello");
// onNext("Hi");
// onNext("Aloha");
// onCompleted();
  • from() 传入的数组或 Iterable 拆分成具体对象后,依次发送出来
1
2
3
4
5
6
7
String[] words = {"Hello", "Hi", "Aloha"};
Observable observable = Observable.from(words);
// 将会依次调用:
// onNext("Hello");
// onNext("Hi");
// onNext("Aloha");
// onCompleted();
  • ActionX 自定义(onCompleted,onError,onNext) 无返回值
  • FuncX 有返回值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Action1<String> onNextAction = new Action1<String>() {
// onNext()
@Override
public void call(String s) {
Log.d(tag, s);
}
};
Action1<Throwable> onErrorAction = new Action1<Throwable>() {
// onError()
@Override
public void call(Throwable throwable) {
// Error handling
}
};
Action0 onCompletedAction = new Action0() {
// onCompleted()
@Override
public void call() {
Log.d(tag, "completed");
}
};

// 自动创建 Subscriber ,并使用 onNextAction 来定义 onNext()
observable.subscribe(onNextAction);
// 自动创建 Subscriber ,并使用 onNextAction 和 onErrorAction 来定义 onNext() 和 onError()
observable.subscribe(onNextAction, onErrorAction);
// 自动创建 Subscriber ,并使用 onNextAction、 onErrorAction 和 onCompletedAction 来定义 onNext()、 onError() 和 onCompleted()
observable.subscribe(onNextAction, onErrorAction, onCompletedAction);

Scheduler 线程控制(调度器)

  • Schedulers.immediate():直接在当前线程运行,相当于不指定线程。这是默认的 Scheduler
  • Schedulers.newThread():总是启用新线程,并在新线程执行操作。
  • Schedulers.io(): I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。行为模式和 newThread() 差不多,区别在于 io() 的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。
  • Schedulers.computation():计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。
  • AndroidSchedulers.mainThread():指定的操作将在 Android 主线程运行。
1
2
3
4
5
6
7
8
9
Observable.just(1, 2, 3, 4)
.subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程
.observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer number) {
Log.d(tag, "number:" + number);
}
});

变换

  • map()
  • flatMap()

android 系统自带了文本转语音的功能

一般手机都有Pico TTS功能,但是没有中文语言包
解决方案: 安装google 语音装文本tts服务或者讯飞tts等兼容系统接口的TTs

文字转语音的代码比较少

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
TextToSpeech mTts;
mTts=new TextToSpeech(this, new TextToSpeech.OnInitListener() {
@Override
public void onInit(int status) {
// status can be either TextToSpeech.SUCCESS or TextToSpeech.ERROR.
if (status == TextToSpeech.SUCCESS) {
// Set preferred language to US english.
// Note that a language may not be available, and the result will indicate this.
int result = mTts.setLanguage(Locale.CHINA);
// Try this someday for some interesting results.
// int result mTts.setLanguage(Locale.FRANCE);
if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
// Lanuage data is missing or the language is not supported.
Log.e(TAG, "Language is not available.");
Intent installIntent = new Intent();
installIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installIntent);
} else {
// Check the documentation for other possible result codes.
// For example, the language may be available for the locale,
// but not for the specified country and variant.
// The TTS engine has been successfully initialized.
// Allow the user to press the button for the app to speak again.
Log.i(TAG,"初始化成功");
mTts.speak("初始化成功",TextToSpeech.QUEUE_FLUSH,null);
}
} else {
// Initialization failed.
Log.e(TAG, "Could not initialize TextToSpeech.");
}
}
});

注意销毁 TextToSpeech

1
2
3
4
5
6
7
8
@Override
protected void onDestroy() {
super.onDestroy();
// 关闭TextToSpeech对象
if (mTts != null) {
mTts.shutdown();
}
}

问题

在使用nubia手机时,发现手机没有这项(TTs)设置,安装了其它TTs却不能开启。
解决:打算用第三方sdk,但是查了一下讯飞的离线文字转语音却发现是收费的,只能说nubia的系统太坑了。

端口

管理数据库,文件服务等端口,关闭了外部无法访问

  • 开启端口
1
firewall-cmd --zone=public --add-port=3306/tcp
  • 关闭端口
1
firewall-cmd --zone=public --remove-port=3306/tcp

系统开机启动项

/etc/rc.local