0%

  • 平移动画

TranslateAnimation animation=new TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)
fromXDelta 起点x
fromYDelta 起点y
toXDelta 终点x
toYDelta 终点y
以控件的中心为原点坐标,起点终点都是在原点坐标为基准

animation.setDuration(2000); 设置动画时间
animation.setFillAfter(false); 设置动画结束是否停留显示(false不显示),如果为true,不能通过隐藏控件让他消失
rb_anmia.setAnimationListener() 设置动画的监听(onAnimationStart,onAnimationEnd,onAnimationRepeat
view.startAnimation(animation); 启动动画

自定义控件的基本使用

  • 创建一个控件类继承ViewGroup
  • 复写onlayout
  • 复写测量onMeasure
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
public class ArcMenu extends ViewGroup {
public ArcMenu(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int cent_x = getWidth() / 2; //viewgroup中心坐标
int cent_y = getHeight() / 2; //viewgroup中心坐标
for (int i = 0; i < getChildCount(); i++) {

View childView = getChildAt(i); //遍历子控件
int childWidth = childView.getMeasuredWidth(); //获得子控件的宽度,需要先测量
int childHeight = childView.getMeasuredHeight();

int cl = 0, ct = 0, cr = 0, cb = 0;
}

childView.layout(cl, ct, cr, cb); //见下图
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//测量所有子View的宽高
measureChildren(widthMeasureSpec, heightMeasureSpec);
}
}

childView.layout(cl, ct, cr, cb)
62o7O1.png

  • 在xml里面引用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<com.xuan.hifusion.customcontrols.ArcMenu
android:id="@+id/car_arcmenu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center">

<ImageView
android:id="@+id/car_cent_line_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
app:srcCompat="@drawable/car_cent_line" />

<ImageView
android:id="@+id/car_light_off_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tag="右下"
android:visibility="invisible"
app:srcCompat="@drawable/car_light_off" />
</com.xuan.hifusion.customcontrols.ArcMenu>

定时心跳

场景描述:
  1. 一个发送数据出口
  2. 定时循环发送一个数据
  3. 当需要发送一个数据临时插入一个数据从出口发送
需要用到的操作符

repat 重复发送
delay 延时发送
just 快速创建被观察者,插入心跳数据
mergeDelayError 合并发送,错误延时

流程

主要是创建两个被观察者,一个负责心跳的发送,另外一个负责数据的发送

实现代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Observable alive=Observable.just(temp_send).delay(4000,TimeUnit.MILLISECONDS).repeat(); //心跳数据(每隔4s重复发一次)
Observable send= Observable.create(new Observable.OnSubscribe<byte[]>() {
@Override
public void call(Subscriber<? super byte[]> subscriber) {
subscriberSend=subscriber; //负责数据的发送
}
});
//合并,订阅
send_subscribe= Observable.mergeDelayError(alive,send).subscribe(new Action1<byte[]>() {
@Override
public void call(byte[] bs) {
send(bs); //数据出口
}
});

重复执行某个动作直到成功,或失败,或超时

场景描述:
  1. 重复执行某个动作
  2. 成功后中断继续执行操作
  3. 错误继续执行
  4. 未响应发出超时错误,并继续执行
  5. 达到超时次数,终止执行
需要用到的操作符

distinct 过滤
timeout 超时发出错误
retryWhen 错误重试
zipWith 合并(用于统计错误重试次数)
delay 延时(用于发送错误后等待一段时间继续发送)

流程

发出动作请求,等待结果,过滤结果。

  1. 结果为onError立马重新发出动作请求
  2. 等待指定时间没有结果,发出超时onError然后重新发出动作请求
  3. 结果为成功结果终止动作请求
  4. 直到成功为止,或者超过重试的指定次数
实现代码
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
public Observable<String> xuanSend(final String str){
return Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
Log.d("TASK_SHOW","任务:"+str+",状态:开始执行,发送数据:空");
strTask=str;
subscriber.onNext(str+"中......");
subscriberTask=subscriber; //执行结果的入口

}
}).distinct().timeout(5000,TimeUnit.MILLISECONDS).retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() {
@Override
public Observable<?> call(final Observable<? extends Throwable> observable) {
return observable.zipWith(Observable.range(1, 5), new Func2<Throwable, Integer, Object>() {
@Override
public Object call(Throwable throwable, Integer integer) {
if(throwable.getMessage()==null)
Log.d("TASK_SHOW","任务:"+str+",状态:异常结束,异常:"+"第"+integer+"次,执行超时");
else
Log.d("TASK_SHOW","任务:"+str+",状态:异常结束,异常:"+throwable.getMessage());
return 0;
}
}).delay(10000,TimeUnit.MILLISECONDS);
}
});
}

任务流(循环)

场景描述
  1. 一个动作完成后才执行下一个动作
  2. 所有动作完成后重复继续执行
需要用到的操作符

concat 连接操作符(只能连接9个,但是可以嵌套)
repat 循环

流程

使用flatmap创建一个基本异步任务,用concat实现连接,用reapt实现循环

实现代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//任务流
Observable<String> task=Observable.concat(mBle.connet(bleDevicesList.getmBleDevicesList_test()),mBle.enableRX(),mBle.xuanSend(sendData.setStart(false),Ble.START),mBle.xuanSend(sendData.setsafe(false,false),Ble.CANCELSAFE),mBle.disConnet());

task.repeat().subscribeOn(Schedulers.computation()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<String>() {
@Override
public void onCompleted() {
//所有任务完成,但是如果reapt(),始终是不会完成的
}
@Override
public void onError(Throwable e) {
//发生错误时
}
@Override
public void onNext(String result) {
//任务完成
}

});

时间复杂度

概念: 时间复杂度是用来衡量算法的执行时间上的效果。
计算方式:
1. 找出算法的基本语句

算法中执行次数最多的那条语句就是基本语句,通常是最内层循环的循环体。
eg: i++; //时间复杂度为O(1)

2. 计算语句执行的数量级

只需计算基本语句执行次数的数量级,这就意味着只要保证基本语句执行次数的函数中的最高次幂正确即可,可以忽略所有低次幂和最高次幂的系数。这样能够简化算法分析,并且使注意力集中在最重要的一点上:增长率。
eg:

1
2
3
4
int sum=0;                //(一次)
for(int i=1;i<=n;i++) //(n+1次)
for(int j=1;j<=n;j++) //(n²次)
sum++; //(n²次)

因为
$\Theta(2n^2 +n+1)=n^2$($\Theta$即:去低阶项,去掉常数项,去掉高阶项的常参得到),所以$T(n)=O(n^2)$。

3. 时间复杂度表示格式
  • $O(1)$
  • $O(log(n))$
  • $O(n)$
  • $O(nlog(n))$
  • $O(n^2)$
  • $O(n^3)$
  • $O(2^n)$
  • $O(n!)$
  • $O(n^n)$

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();
    }