石乐志, 从16101703中旬, 重新拾起旧物, 总结一下Android必须要掌握的东西.
1. 熟练掌握Java技术,熟悉面向对象思想,熟悉常用设计模式
2. 熟练掌握Android四大组件和Fragment的使用;
3. 熟练掌握Android中的数据存储(文件, 网络, 数据库存储);
4. 熟悉掌握Android中常用的UI元素, 动画, 样式;
动画
android 3.0新增属性动画(Object, Value)
android 5.0新增矢量图动画
通常定义一个AnimatedVectorDrawable需要以下三个xml文件: 1.vector drawable本身:res/drawable/中定义一个有<vector>元素的xml文件,参考上面对VectorDrawable的定义。 2.vector drawable的动画文件(Animated vector drawable):res/drawable/中定义一个有<animated-vector>元素的xml文件。 3.一个或者多个属性动画文件:res/drawable/中定义一个有<objectAnimator>元素的xml文件。
- 完全自定义View
- 继承已有View, 重写部分功能
- 继承ViewGroup
步骤
- 自定义属性的声明和获取
- 测量onMeasure
- 布局onLayout(ViewGroup)
- 绘制onDraw
- onTouchEvent
- onInterceptTouchEvent(ViewGroup) 是否拦截该手势
5. 消息机制和多线程的使用
6. 网络通信机制及常用数据传输协议;
HTTP网络请求原理
HTTP是一种应用层协议, 通过TCP实现了可靠的数据传输, 能够保证可靠的数据传输.
消息的交互流程有如下几步:
- 客户端执行网络请求, 从URL解析出服务器的主机名
- 将服务器的主机名转换为服务器的IP地址;
- 将端口号从URL中解析出来
- 建立一条客户端与Web服务器的TCP连接;
- 客户端通过输出流向服务器发送一条HTTP请求
- 服务器向客户端回送一条HTTP响应报文
- 客户端从输入流获取报文
- 客户端解析报文, 关闭连接
- 客户端将结果显示在UI上
HTTP的请求方式(7种)
get
post
put
delete
trace
options
head
Android中执行网络请求
- 全面支持HTTP协议的HttpClient(在android2.3以前), 在android6.0中该库已被移除
- 最佳选择HttpURLConnection
网络框架的简单实现
7. Android中的屏幕适配
8. Android中的布局优化, 内存优化;
布局优化
- 减少视图层级
- 通过工具分析视图层级, 优先相对布局, 约束布局
- merge标签, 去处理子布局的根视图和父布局是同一类型的情况
- 延迟加载的ViewStub 通过这个不可见的和能在运行期间延迟加载目标视图的, 宽高都为0的View.
内存优化
- 检查自身可以内存 每个app都有heap限制, 可以通过调用getMemory来获取可用heap大小
- 知晓内存的开支情况
- 使用枚举通常会比使用静态常量要消耗两倍以上的内存,在Android开发当中我们应当尽可能地不使用枚举。
- 任何一个Java类,包括内部类、匿名类,都要占用大概500字节的内存空间。
- 任何一个类的实例要消耗12-16字节的内存开支,因此频繁创建实例也是会一定程序上影响内存的。
- 在使用HashMap时,即使你只设置了一个基本数据类型的键,比如说int,但是也会按照对象的大小来分配内存,大概是32字节,而不是4字节。因此最好的办法就是像上面所说的一样,使用优化过的数据集合。
- 注意内存的开销, 使用专门给为android优化过的数据容器SparseArray, SparseBoolArray, LongSparseArray, 比HashMap消耗更少的内存.通常的HashMap的实现方式更加消耗内存,因为它需要一个额外的实例对象来记录Mapping操作。另外,SparseArray更加高效在于他们避免了对key与value的autobox自动装箱,并且避免了装箱后的解箱。 弃用枚举类型而使用加上IntDef, StringDef注解修饰的全局常量
- bitmap的优化
- 千万不要去加载不需要的分辨率, 会占用我们相当多宝贵的内存
- 图片的色彩格式, 来压缩图片质量 ARGB_8888 代表32位ARGB位图
ARGB_4444 代表16位ARGB位图
RGB_565 代表8位RGB位图
- 使用成熟的图片框架Picasso, ImageLoader当内存紧张时释放内存
onTrimMemory()方法还有很多种其它类型的回调,可以在手机内存降低的时候及时通知我们。我们应该根据回调中传入的级别来去决定如何释放应用程序的资源:善用service资源
系统会倾向于将这个Service所依赖的进程进行保留. 因为service的运行代价很高. 例如使用IntentService处理一些单一短时间任务, 这种Service的最大特点就是当后台任务执行结束后会自动停止,从而极大程度上避免了Service内存泄漏的可能性。为序列化的数据使用nano protobufs尽量避免使用依赖注入框架谨慎使用external libraries关注lint工具所提出的建议使用ProGuard来剔除不需要的代码
能够通过移除不需要的代码,重命名类,域与方法等方对代码进行压缩,优化与混淆。使用ProGuard可以是的你的代码更加紧凑,这样能够使用更少mapped代码所需要的RAM。对最终的APK使用zipalign使用多进程
一个典型的例子是创建一个可以长时间后台播放的Music Player。如果整个app运行在一个进程中,当后台播放的时候,前台的那些UI资源也没有办法得到释放。类似这样的app可以切分成2个进程:一个用来操作UI,另外一个用来后台的Service.
你可以通过在manifest文件中声明’android:process’属性来实现某个组件运行在另外一个进程的操作。谨慎使用抽象编程
许多程序员都喜欢各种使用抽象来编程,认为这是一种很好的编程习惯。当然,这一点不可否认,因为的抽象的编程方法更加面向对象,而且在代码的维护和可扩展性方面都会有所提高。但是,在Android上使用抽象会带来额外的内存开支,因为抽象的编程方法需要编写额外的代码,虽然这些代码根本执行不到,但是却也要映射到内存当中,不仅占用了更多的内存,在执行效率方面也会有所降低。当然这里我并不是提倡大家完全不使用抽象编程,而是谨慎使用抽象编程,不要认为这是一种很酷的编程方式而去肆意使用它,只在你认为有必要的情况下才去使用。
9. Android中的单元测试;
优点
- 为代码提供保障
- 优化设计, 编写单元测试从调用者角度观察, 迫使设计者吧程序设计成易于调试和可测试, 并且消除软件中的耦合.
- 文档记录, 是一种展示函数或者类使用的最佳文档
- 具有回归性, 编写完成后可以随时快速测试.
JUnit简介
基于Java语言的单元测试框架.
开发人员一般需要新建一个TestCase的类, 然后在该测试类中添加测试函数.
需要注意的是, 每个测试方法, TestCase之间并没有关联, 它们的执行顺序也不一定是代码中的执行顺序, 因此, 测试方法不要存在依赖性.
测试哪些条件
- 边界条件 是单元测试需要重要测试的地方
- 覆盖执行路径
模拟所需的功能模块
- 手动mock对象
- 使用Mockito库
Android中单元测试
Google在Junit的基础上进行拓展, 使之能在Android上运行测试实例, Android平台下所有的测试类都是InstrumentationTestCase的子类, 它的内部封装了Instrumentation对四大组件进行操作, 而InstrumentationTestCase继承在Junit的TestCase.
- 需要Context的测试用例 AndroidTestCase
- AcitivityUnitTestCase<T> 和 ActivityInstrumentationTestCase2<T>
- 测试Service, 继承自ServiceTestCase<T>
- 测试ContentPrivider, 继承自ContentPrividerTestCase2<T>
10. 网络框架Volley, 图片处理Picasso等;
第一部分Request
第二部分RequestQueue消息队列, 维护了提交我给网络框架的请求队列, 并根据对应规则进行排序, 该队列使用的线程安全的PriorityBlockingQueue, 所以支持并发访问.
第三部分NetWorkExecutor, 也就是网络的执行者, 该Exectuor继承自Thread, 在run方法中循环访问请求队列, 从请求队列中获取网络请求, 请求完成后提交给UI线程
第四部分Response及其投递类, 使用ResponseDelivery来封装Response的投递, 保证Response在UI线程中执行, Response会根据用户的不同需求返回特定的类型.
Picasso
Picasso不仅实现了图片异步加载的功能,还解决了android中加载图片时需要解决的一些常见问题:
1.在adapter中需要取消已经不在视野范围的ImageView图片资源的加载,否则会导致图片错位,Picasso已经解决了这个问题。
2.使用复杂的图片压缩转换来尽可能的减少内存消耗
3.自带内存和硬盘二级缓存功能
Cache,缓存类
Lrucache,主要是get和set方法,存储的结构采用了LinkedHashMap,这种map内部实现了lru算法(Least Recently Used 近期最少使用算法)。
Request,操作封装类
所有对图形的操作都会记录在这里,供之后图形的创建使用
Action
Action代表了一个具体的加载任务,主要用于图片加载后的结果回调,有两个抽象方法,complete和error,也就是当图片解析为bitmap后用户希望做什么。最简单的就是将bitmap设置给imageview,失败了就将错误通过回调通知到上层。
ImageViewAction实现了Action,在complete中将bitmap和imageview组成了一个PicassoDrawable,里面会实现淡出的动画效果。
BitmapHunter
BitmapHunter是一个Runnable,其中有一个decode的抽象方法,用于子类实现不同类型资源的解析。
在bitmaphunter成功得到bitmap后,就是通过dispatcher将结果传递出去的,当然让bitmaphunter执行也要通过Dispatcher。
Dispatcher内有一个HandlerThread,所有的请求都会通过这个thread转换,也就是请求也是异步的,这样应该是为了Ui线程更加流畅,同时保证请求的顺序,因为handler的消息队列。外部调用的是dispatchXXX方法,然后通过handler将请求转换到对应的performXXX方法。例如生成Action以后就会调用dispather的dispatchSubmit()来请求执行,
handler接到消息后转换到performSubmit方法
这里将通过action得到具体的BitmapHunder,然后交给ExecutorService执行。
下面是Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView)的过程,
代码语言:javascript复制public static Picasso with(Context context) {
if (singleton == null) {
singleton = new Builder(context).build();
}
return singleton;
}
public Picasso build() {
Context context = this.context;
if (downloader == null) {
downloader = Utils.createDefaultDownloader(context);
}
if (cache == null) {
cache = new LruCache(context);
}
if (service == null) {
service = new PicassoExecutorService();
}
if (transformer == null) {
transformer = RequestTransformer.IDENTITY;
}
Stats stats = new Stats(cache);
Dispatcher dispatcher = new Dispatcher(context, service, HANDLER,
downloader, cache, stats);
return new Picasso(context, dispatcher, cache, listener,
transformer, stats, debugging);
}
在Picasso.with()的时候会将执行所需的所有必备元素创建出来,如缓存cache、执行executorService、调度dispatch等,在load()时创建Request,在into()中创建action、bitmapHunter,并最终交给dispatcher执行。
11. 目前流行的MVP模式构建应用
全称Model View Presenter
MVP让UI界面和数据分离, 解除View和Model直接的耦合