石乐志, 从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/中定义一个有元素的xml文件,参考上面对VectorDrawable的定义。
2.vector drawable的动画文件(Animated vector drawable):res/drawable/中定义一个有元素的xml文件。
3.一个或者多个属性动画文件:res/drawable/中定义一个有元素的xml文件。

  1. 完全自定义View
  2. 继承已有View, 重写部分功能
  3. 继承ViewGroup

步骤

  1. 自定义属性的声明和获取
  2. 测量onMeasure
  3. 布局onLayout(ViewGroup)
  4. 绘制onDraw
  5. onTouchEvent
  6. onInterceptTouchEvent(ViewGroup)
    是否拦截该手势

5. 消息机制和多线程的使用

6. 网络通信机制及常用数据传输协议;

HTTP网络请求原理

HTTP是一种应用层协议, 通过TCP实现了可靠的数据传输, 能够保证可靠的数据传输.

消息的交互流程有如下几步:

  1. 客户端执行网络请求, 从URL解析出服务器的主机名
  2. 将服务器的主机名转换为服务器的IP地址;
  3. 将端口号从URL中解析出来
  4. 建立一条客户端与Web服务器的TCP连接;
  5. 客户端通过输出流向服务器发送一条HTTP请求
  6. 服务器向客户端回送一条HTTP响应报文
  7. 客户端从输入流获取报文
  8. 客户端解析报文, 关闭连接
  9. 客户端将结果显示在UI上
HTTP的请求方式(7种)

get
post
put
delete

trace
options
head

Android中执行网络请求
  1. 全面支持HTTP协议的HttpClient(在android2.3以前), 在android6.0中该库已被移除
  2. 最佳选择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中的单元测试;

优点

  1. 为代码提供保障
  2. 优化设计, 编写单元测试从调用者角度观察, 迫使设计者吧程序设计成易于调试和可测试, 并且消除软件中的耦合.
  3. 文档记录, 是一种展示函数或者类使用的最佳文档
  4. 具有回归性, 编写完成后可以随时快速测试.

JUnit简介
基于Java语言的单元测试框架.

开发人员一般需要新建一个TestCase的类, 然后在该测试类中添加测试函数.
需要注意的是, 每个测试方法, TestCase之间并没有关联, 它们的执行顺序也不一定是代码中的执行顺序, 因此, 测试方法不要存在依赖性.

测试哪些条件
  1. 边界条件
    是单元测试需要重要测试的地方
  2. 覆盖执行路径
模拟所需的功能模块
  • 手动mock对象
  • 使用Mockito库
Android中单元测试

Google在Junit的基础上进行拓展, 使之能在Android上运行测试实例, Android平台下所有的测试类都是InstrumentationTestCase的子类, 它的内部封装了Instrumentation对四大组件进行操作, 而InstrumentationTestCase继承在Junit的TestCase.

  • 需要Context的测试用例
    AndroidTestCase
  • AcitivityUnitTestCase
    和 ActivityInstrumentationTestCase2
  • 测试Service, 继承自ServiceTestCase
  • 测试ContentPrivider, 继承自ContentPrividerTestCase2

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)的过程,

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直接的耦合

更多相关文章

  1. 箭头函数的基础使用
  2. NPM 和webpack 的基础使用
  3. Python list sort方法的具体使用
  4. 【阿里云镜像】使用阿里巴巴DNS镜像源——DNS配置教程
  5. 你不知道一些神奇Android(安卓)Api-比如文字识别、截屏等
  6. Android之Intent的基本使用
  7. 远程服务使用AIDL通信
  8. 远程服务使用AIDL通信
  9. Android(安卓)Studio一些控件的使用

随机推荐

  1. android XML文件序列化
  2. android 中RecyclerView 嵌套了 GridView
  3. Android jni调用,实现自己的JNI_OnLoad函
  4. adnroid(10)(android下的单元测试)
  5. Android 基础UI编程4
  6. Android 处理 Button 单击事件的三种方法
  7. Bitmap与Drawable,byte[]之间的转化
  8. android 从sdcard 读取图片 剪切 粘贴
  9. android客户端版本检测更新,服务下载,通知
  10. Android使用AsyncTask下载图片并显示进度