Neil's blog

Let's start from here


  • 首页

  • 归档

  • 标签

  • 关于

多的是,你不知道的事

发表于 2017-09-03 |

多的是,你不知道的事


Android系统源码学习

  • Binder机制和AIDL
  • Activity的启动过程
  • 进程的优先级
  • ServiceManager
  • Window和WindowManager

开源框架学习

  • OKHTTP
  • Retrofit
  • Glide
  • Gson
  • fastjson
  • Jackson
  • Realm
  • Ormlite
  • ButterKnief
  • GreenDao
  • RePlugin
  • Leakcanary
  • EventBus
  • otto
  • MPAndroidChart
  • ZXing
  • PhotoView
  • dragger
  • DisLruCache

多线程处理

  • Handler原理
  • AsyncTask
  • HandlerThread
  • IntentService
  • RxJava

自定义控件

  • measure
  • layout
  • draw
  • 事件分发
  • 自定义动画

性能优化

  • ANR处理
  • OOM处理
  • 布局优化
  • 线程优化

Java高级知识

  • 反射
  • 动态代理
  • NIO
  • 垃圾回收
  • 多线程(并发锁)
  • 网络协议

APP架构

  • MVC
  • MVP
  • MVVM

插件化技术

  • class和dex学习
  • ClassLoader原理
  • 插件化原理
  • 插件化框架学习

NDK开发

  • 调用JNI方法
  • 回调JAVA方法
  • CMAKE语法
  • NDK MakeFile语法

音视频处理

  • 音频编解码
  • AudioTrack播放
  • 视频解码
  • OpenGL绘制
  • 视频编辑转码
  • 视频滤镜

工具

  • AndroidStudio
  • Gradle脚本
  • Git

自定义View(一)View简介

发表于 2017-08-26 |

一、常见View继承关系

  • 如下图

    view

可以看到所有的控件都是最终继承自View。布局控件都是直接或间接继承自ViewGroup.

二、自定义控件

  • 大致可分为两大类:

    • 组合或继承基本控件TextView、ImageView等,加上自定义的内容。
    • 继承自View
  1. 组合控件或继承基本控件

    像这种自定义的控件,很好理解,就是在原有的基础上,自定义的进行组合或者添加新的功能属性等。自定义ViewGroup一般是利用现有的组件根据特定的布局方式来组成新的组件,大多继承自ViewGroup或Layout,包含子View

    举个简单的例子:ToolBar

    在Android 5.0推出的一个新的导航控件用于取代之前的ActionBar。如果去看ToolBar的源码,就可以发现,其实就是将几种基本控件组合在一起,实现开发者的更好的可定制性。

    看源码:

    toolbar

    可以看出来ToolBar组合了ActionMenuView、TextView、ImageButton、ImageView等。相当于一个布局文件里面加了自己自定义的控件组合而成达到自己想要的效果。

  1. 自定义View

    自定义View一般是没有需要的View,需要自己实现,继承自View、surfaceView或者其他的View,不包含子View

    • (1)屏幕坐标系

      zuobiaoxi

      手机屏幕的坐标系如图所示,是以手机屏幕左上顶角为坐标原点。

    • (2)View坐标系

    viewzuobiao

    View坐标系都是相对父控件而言来确定位置的。

    • getTop():view顶部相对于父控件顶部距离
    • getBottom():view底部相对于父控件顶部距离
    • getLeft():view左边相对于父控件距离
    • getRight():view右边相对于父控件距离
  1. View绘制流程

viewhuizhi

RxJava2.0(三)操作符简介

发表于 2017-08-12 |

了解了线程控制的基本使用,接下来就来看看RxJava厉害的地方–变换操作。

RxJava提供对事件序列进行变换操作。就是将事件序列中的对象或整个序列进行加工处理,转换成不同的事件或事件序列。

变换操作

一、map

返回一个Observable,它将指定的函数应用于源ObservableSource发出的每个项目,并发出这些函数应用程序的结果。

一对一的变换,如下图(来源:官方文档)

map

@Test
public void testMap() throws Exception {
    Observable.create(new ObservableOnSubscribe<String>() {
        @Override
        public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
            e.onNext("map");
        }
    }).map(new Function<String, Integer>() {
        @Override
        public Integer apply(@NonNull String s) throws Exception {
            return getValue(s);
        }
    }).subscribe(new Observer<Integer>() {
        @Override
        public void onSubscribe(@NonNull Disposable d) {

        }

        @Override
        public void onNext(@NonNull Integer s) {
            System.out.println("testMap:" + s);
        }

        @Override
        public void onError(@NonNull Throwable e) {

        }

        @Override
        public void onComplete() {

        }
    });
}

从上面的例子可以看到,map() 方法将参数中的 String 对象转换成一个 Bitmap 对象后返回,而在经过 map() 方法后,事件的参数类型也由 String 转为了 Bitmap。这种直接变换对象并返回的,是最常见的也最容易理解的变换。

  • 对上游发送的每一个事件应用一个函数, 使得每一个事件都按照指定的函数去变化

  • map是一对一的, 可以将上游发来的事件转换为任意的类型, 可以是一个Object, 也可以是一个集合

二、flatmap

更加高级的变换。如图(来源:官方文档)

flatmap

  • 一个Observable它发射一个数据序列,这些数据本身也可以发射Observable。RxJava的flatMap()函数提供一种铺平序列的方式,然后合并这些Observables发射的数据,最后将合并后的结果作为最终的Observable。

  • flatMap()不能够保证在最终生成的Observable中源Observables确切的发射顺序。

For Example:

 @Test
public void testRxFlatMap() throws Exception {
    Observable.create(new ObservableOnSubscribe<Integer>() {
        @Override
        public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
            e.onNext(99);
            e.onNext(66);
            e.onComplete();
        }
    }).flatMap(new Function<Integer, ObservableSource<String>>() {
        @Override
        public ObservableSource<String> apply(@NonNull Integer s) throws Exception {
            if (s>80){
                return Observable.just("A");
            }
            return Observable.just("B");
        }
    }).subscribe(new Observer<String>() {
        @Override
        public void onSubscribe(@NonNull Disposable d) {

        }

        @Override
        public void onNext(@NonNull String s) {
            System.out.println("成绩为:"+s);
        }

        @Override
        public void onError(@NonNull Throwable e) {

        }

        @Override
        public void onComplete() {

        }
    });
}

从上面的代码很容易看出FlatMap将int变换为String对象,操作简单。一个操作符搞定,这样就方便多了。

三、concatMap

  • 官方文档解释:返回一个新的Observable,它会发送由应用源ObservableSource发出的每个项目提供的函数产生的项目,该函数返回一个ObservableSource,然后发出连接那些由此产生的ObservableSource产生的项目。

通俗一点,就是和flatmap相比,concatMap是有序的。

concatmap

四、zip

返回一个Observable,它发出指定的组合器函数的结果,该结果应用于依次发送的其他ObservableSource的迭代项的组合。

zip以严格的顺序应用此功能,因此新的ObservableSource发出的第一个项目将是应用于每个源ObservableSources发出的第一个项目的函数的结果; 新的ObservableSource发出的第二个项目将是应用于每个ObservableSource发出的第二个项目的函数的结果; 等等。

来看一个简单的例子,加深理解。

/**
 * RxJava zip变换
 * @throws Exception
 */
@Test
public void testZip() throws Exception {
    Observable<String> observableHello = Observable.create(new ObservableOnSubscribe<String>() {
        @Override
        public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
            e.onNext("Hello");
        }
    });
    Observable<String> observableWorld = Observable.create(new ObservableOnSubscribe<String>() {
        @Override
        public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
            e.onNext("World");
        }
    });
    Observable.zip(observableHello, observableWorld, new BiFunction<String, String, String>() {
        @Override
        public String apply(@NonNull String s, @NonNull String s2) throws Exception {
            return s+s2;
        }
    }).subscribe(new Observer<String>() {
        @Override
        public void onSubscribe(@NonNull Disposable d) {

        }

        @Override
        public void onNext(@NonNull String s) {
            System.out.println("Final:"+s);
        }

        @Override
        public void onError(@NonNull Throwable e) {

        }

        @Override
        public void onComplete() {

        }
    });
}

从上面的例子就可以看出zip将获取的不同两个String重新组装得到一个新的组装后的String,达到zip类似打包的效果,应该很好理解吧。

五、concat

Concatenates elements of each ObservableSource provided via an Iterable sequence into a single sequence of elements without interleaving them.

简单来说就是将多个数据源按序发射。

concat

举个很简单的例子,获取一包卫龙辣条包装的信息,可能需要制造商信息、价格、材料信息。

获取辣条制造商信息

@Test
public void testConcat() throws Exception {
    final Observable<String> factory = Observable.create(new ObservableOnSubscribe<String>() {
        @Override
        public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
            e.onNext("卫龙");
            e.onComplete();
        }
    });

    Observable<String> price = Observable.create(new ObservableOnSubscribe<String>() {
        @Override
        public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
            e.onNext("5");
            e.onComplete();
        }
    });
    Observable<String> material = Observable.create(new ObservableOnSubscribe<String>() {
        @Override
        public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
            e.onNext("chili");
            e.onComplete();
        }
    });

    Observable.concat(factory, price,material).subscribe(new Observer<String>() {
        @Override
        public void onSubscribe(@NonNull Disposable d) {

        }

        @Override
        public void onNext(@NonNull String s) {
            System.out.println("result"+s);
        }

        @Override
        public void onError(@NonNull Throwable e) {

        }

        @Override
        public void onComplete() {

        }
    });
}

结果为:

result:卫龙
result:5
result:chili

就拿到了辣条的所有信息了。

过滤操作

一、buffer

可以理解为缓存。它定期从Observable收集数据到一个集合,然后把这些数据打包发射,而不是一次发一个。

buffer

二、filter

简单的说,就是按照自定义条件过滤。官方解释:Filters items emitted by an ObservableSource by only emitting those that satisfy a specified predicate.

filter

举一个简单的例子:

@Test
public void testFilter() throws Exception {
    Observable.create(new ObservableOnSubscribe<Integer>() {
        @Override
        public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
            e.onNext(1);
            e.onNext(666);
            e.onNext(6);
            e.onComplete();
        }
    }).filter(new Predicate<Integer>() {
        @Override
        public boolean test(@NonNull Integer integer) throws Exception {
            return integer>100;
        }
    }).subscribe(new Observer<Integer>() {
        @Override
        public void onSubscribe(@NonNull Disposable d) {

        }

        @Override
        public void onNext(@NonNull Integer integer) {
            System.out.println("result:"+integer);
        }

        @Override
        public void onError(@NonNull Throwable e) {

        }

        @Override
        public void onComplete() {

        }
    });

从上面的例子,很明显的看出filter按照自己的定义,过滤掉了小于100的数字,然后输出自己想要得到的数字。很容易理解。

RxJava2.0(二)线程控制

发表于 2017-08-11 |

已经知道了基本使用,那就继续进阶更高级的操作-线程切换。

以Android为例,一个Activity的所有动作默认都是在主线程中运行的, 比如:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Log.d(TAG, Thread.currentThread().getName());
}

结果:main.

那么在使用RxJava情况下,在主线程创建Observable发射数据,那么发射源就会在主线程发射数据,在主线程创建Observer接收数据,那么接收源就会在主线程接收数据。
比如:

@Override                                                                                       
protected void onCreate(Bundle savedInstanceState) {                                            
    super.onCreate(savedInstanceState);                                                         
    setContentView(R.layout.activity_main);                                                     

Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() {   
    @Override                                                                               
    public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {            
        Log.d(TAG, "Observable thread is : " + Thread.currentThread().getName());           
        Log.d(TAG, "emit on main thread");                                                               
        emitter.onNext(1);                                                                  
    }                                                                                       
});                                                                                         

Consumer<Integer> consumer = new Consumer<Integer>() {                                      
    @Override                                                                               
    public void accept(Integer integer) throws Exception {                                  
        Log.d(TAG, "Observer thread is :" + Thread.currentThread().getName());              
        Log.d(TAG, "onNext: " + integer);                                                   
    }                                                                                       
};                                                                                          

observable.subscribe(consumer);                                                             
}

即在主线程中创建Observable和Obsever,通过订阅关联后,打印结果显示:

D/TAG: Observable thread is : main
D/TAG: emit on main thread                    
D/TAG: Observer thread is :main   
D/TAG: onNext: 1

发射源和接收源都在主线程工作。

然而,我们工作的实际情况是,耗时的操作我们会在子线程处理,处理完再到主线程更新UI。

那么,为了达到这样的效果,首先就需要改变上游发送数据的线程,然后下游在主线程接收数据,更新UI。

@Override                                                                                       
protected void onCreate(Bundle savedInstanceState) {                                            
    super.onCreate(savedInstanceState);                                                         
    setContentView(R.layout.activity_main);                                                     

Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() {   
    @Override                                                                               
    public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {            
        Log.d(TAG, "Observable thread is : " + Thread.currentThread().getName());           
        Log.d(TAG, "emit on new Thread");                                                               
        emitter.onNext(1);                                                                  
    }                                                                                       
});                                                                                         

Consumer<Integer> consumer = new Consumer<Integer>() {                                      
    @Override                                                                               
    public void accept(Integer integer) throws Exception {                                  
        Log.d(TAG, "Observer thread is :" + Thread.currentThread().getName());              
        Log.d(TAG, "onNext: " + integer);                                                   
    }                                                                                       
};                                                                                          

observable.subscribeOn(Schedulers.newThread())                                              
        .observeOn(AndroidSchedulers.mainThread())                                          
        .subscribe(consumer);                                                               
}

结果:

D/TAG: Observable thread is : RxNewThreadScheduler-2  
D/TAG: emit on new thread                                         
D/TAG: Observer thread is :main                       
D/TAG: onNext: 1

从结果就可以看出,上游发射源是在一个新的子线程进行数据的相关处理的。处理后,下游的接收源在主线程接收数据。实现主线程更新UI,子线程处理耗时操作的场景。

仔细观察下,在订阅的时候多了两个操作:

  • subscribeOn
  • observeOn

下面解释下这两个操作。

  • subscribeOn:上游发射源切换发射线程,多次切换的情况仅第一次有效。
  • observeOn:下游接收事件线程,可多次指定,没指定一次,就切换一次。
  • 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 主线程运行,Android专用。

RxJava2.0(一)基本使用

发表于 2017-08-10 |

RxJava2.0(一)

–

一、基本概念

官方介绍:
RxJava是Reactive Extensions的Java VM实现:用于通过使用observable序列来组合异步和基于事件的程序的库。

简单来说,就是异步,观察者模式。

  • 首先需要了解几个概念
    • Observable 被观察者,即数据发射源
    • Observer 观察者,即数据接收源
    • subscribe 订阅,即将数据发射源和接收源相关联

二、基本使用

了解了基本概念,开始基本使用。

写一个测试用例:

/**
 * RxJava基本使用
 */
@Test
public void testRxJava() throws Exception {
    Observable<String> observable = new Observable<String>() {
        @Override
        protected void subscribeActual(Observer<? super String> observer) {
            observer.onNext("1");
        }
    };
    Observer<String> observer = new Observer<String>() {
        @Override
        public void onSubscribe(@NonNull Disposable d) {

        }

        @Override
        public void onNext(@NonNull String s) {
            System.out.println("Observer:"+s);

        }

        @Override
        public void onError(@NonNull Throwable e) {

        }

        @Override
        public void onComplete() {

        }
    };
    observable.subscribe(observer);
}

从上面的例子可以看到很简单的,发射源Observable发射数据,接收源Observer接收数据,通过subscribe将发射源和接收源相关联。订阅后才会开始发射数据。

简化上述操作,就是RxJava比较好的链式操作。

  /**
 * RxJava链式基本操作
 *
 * @throws Exception
 */
@Test
public void testObservable1() throws Exception {
    Observable.create(new ObservableOnSubscribe<String>() {
        @Override
        public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception {
            e.onNext("hello");
            e.onComplete();
        }
    }).subscribe(new Observer<String>() {
        @Override
        public void onSubscribe(@NonNull Disposable d) {

        }

        @Override
        public void onNext(@NonNull String s) {
            System.out.println("Observer Receive:" + s);
        }

        @Override
        public void onError(@NonNull Throwable e) {

        }

        @Override
        public void onComplete() {

        }
    });
}

三、简单介绍用法

  • 发射源,通过ObservableEmitter发射数据。Emitter的意思是发射器,这个就是用来发出事件的,它可以发出三种类型的事件,通过调用emitter的onNext(T value)、onComplete()和onError(Throwable error)就可以分别发出next事件、complete事件和error事件。
  • 上游可以发射无数个onNext事件,当发射onComplete()事件后,下游不再接收上游发送的数据,但是上游还是可以继续发送数据的。
  • onComplete和onError必须唯一并且互斥, 即不能发多个onComplete, 也不能发多个onError, 也不能先发一个onComplete, 然后再发一个onError。这一点很重要。
1…8910…14
Neil Liu

Neil Liu

优秀不够,你是否无可替代

68 日志
25 标签
GitHub
© 2019 Neil Liu
由 Hexo 强力驱动
主题 - NexT.Muse