Android面试题

1.Service启动方式

  • startService
    ①.定义一个类继承service
    ②.在manifest.xml文件中配置该service
    ③.使用context的startService(intent)启动该service
    ④.不再使用时,调用stopService(Intent)停止该服务
  • bindService
    ①.创建bindService服务段,继承自service并在类中,创建一个实现binder接口的实例对象并提供公共方法给客户端调用
    ②.从onbind()回调方法返回此binder实例
    ③.在客户端中,从onserviceconnected()回调方法接收binder,并使用提供的方法调用绑定服务

2.Activity的启动方式

①.standard模式
a.Activity的默认启动模式
b.每启动一个Activity就会在栈顶创建一个新的实例。例如:闹钟程序
缺点:当Activity已经位于栈顶时,而再次启动Activity时还需要在创建一个新的实例,不能直接复用。
②.singleTop模式
特点:该模式会判断要启动的Activity实例是否位于栈顶,如果位于栈顶直接复用,否则创建新的实例。 例如:浏览器的书签
缺点:如果Activity并未处于栈顶位置,则可能还会创建多个实例。
③.singleTask模式
特点:使Activity在整个应用程序中只有一个实例。每次启动Activity时系统首先检查栈中是否存在当前Activity实例,如果存在
          则直接复用,并把当前Activity之上所有实例全部出栈。例如:浏览器主界面
④.singleInstance模式
特点:该模式的Activity会启动一个新的任务栈来管理Activity实例,并且该势力在整个系统中只有一个。无论从那个任务栈中    启动该Activity,都会是该Activity所在的任务栈转移到前台,从而使Activity显示。主要作用是为了在不同程序中共享一个Activity

3.Touch事件传递机制

在我们点击屏幕时,会有下列事件发生:
Activity调用dispathTouchEvent()方法,把事件传递给Window;
Window再将事件交给DecorView(DecorView是View的根布局);
DecorView再传递给ViewGroup;
Activity ——> Window ——> DecorView ——> ViewGroup——> View
事件分发的主要有三个关键方法
dispatchTouchEvent() 分发
onInterceptTouchEvent() 拦截 ,只有ViewGroup独有此方法
onTouchEvent() 处理触摸事件
Activity首先调用dispathTouchEvent()进行分发,接着调用super向下传递
ViewGroup首先调用dispathTouchEvent()进行分发,接着会调用onInterceptTouchEvent()(拦截事件)。若拦截事件返回为true,表示拦截,事件不会向下层的ViewGroup或者View传递;false,表示不拦截,继续分发事件。默认是false,需要提醒一下,View是没有onInterceptTouchEvent()方法的
事件在ViewGroup和ViewGroup、ViewGroup和View之间进行传递,最终到达View;

View调用dispathTouchEvent()方法,然后在OnTouchEvent()进行处理事件;OnTouchEvent() 返回true,表示消耗此事件,不再向下传递;返回false,表示不消耗事件,交回上层处理。

4.介绍下实现一个自定义View的基本流程

①.自定义View的属性 编写attr.xml文件
②.在layout布局文件中引用,同时引用命名空间
③.在View的构造方法中获得我们自定义的属性 ,在自定义控件中进行读取(构造方法拿到attr.xml文件值)
④.重写onMesure
⑥.重写onDraw
原理:
View为所有图形控件的基类,View的绘制由3个函数完成
measure,计算视图的大小
layout,提供视图要显示的位置
draw,绘制

5.ANR是什么?怎样避免和解决ANR

Application Not Responding,即应用无响应
出现的原因有三种:
a)KeyDispatchTimeout(5 seconds)主要类型按键或触摸事件在特定时间内无响应
b)BroadcastTimeout(10 seconds)BoradcastReceiver在特定的时间内无法处理
c)ServiceTimeout(20 seconds)小概率类型Service在特定的时间内无法处理完成

避免ANR最核心的一点就是在主线程减少耗时操作。通常需要从那个以下几个方案下手:
a)使用子线程处理耗时IO操作
b)降低子线程优先级,使用Thread或者HandlerThread时,调用Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)设置优先级,否则仍然会降低程序响应,因为默认Thread的优先级和主线程相同
c)使用Handler处理子线程结果,而不是使用Thread.wait()或者Thread.sleep()来阻塞主线程
d)Activity的onCreate和onResume回调中尽量避免耗时的代码
e)BroadcastReceiver中onReceiver代码也要尽量减少耗时操作,建议使用intentService处理。intentService是一个异步的,会自动停止的服务,很好解决了传统的Service中处理完耗时操作忘记停止并销毁Service的问题

6.设备横竖屏切换的时候,生面周期的变化

不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次
设置Activity的android:configChanges=”orientation”时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次
设置Activity的android:configChanges=”orientation|keyboardHidden”时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法

7.RecyclerView和ListView的区别

RecyclerView可以完成ListView,GridView的效果,还可以完成瀑布流的效果。同时还可以设置列表的滚动方向(垂直或者水平);
RecyclerView中view的复用不需要开发者自己写代码,系统已经帮封装完成了。
RecyclerView可以进行局部刷新。
RecyclerView提供了API来实现item的动画效果。

在性能上:
如果需要频繁的刷新数据,需要添加动画,则RecyclerView有较大的优势。
如果只是作为列表展示,则两者区别并不是很大。

8.Android异步消息处理机制

异步消息处理机制主要是用来解决子线程更新UI的问题

主要有四个部分:
①. Message (消息)
在线程之间传递,可在内部携带少量信息,用于不同线程之间交换数据
可以使用what、arg1、arg2字段携带整型数据
obj字段携带Object对象
②. Handler (处理者)
主要用于发送和处理消息,sendMessage()用来发送消息,最终会回到handleMessage()进行处理
③. MessageQueue (消息队列)
主要存放所有通过Handler发送的消息,它们会一直存在于队列中等待被处理
每个线程只有一个MessageQueue
④. Looper (循环器)
调用loop()方法后,会不断从MessageQueue 取出待处理的消息,然后传递到handleMessage进行处理

9.内存泄漏和内存溢出是什么?一般怎么处理内存泄漏?

(1)内存溢出(OOM)和内存泄露(对象无法被回收)的区别。
(2)引起内存泄露的原因
(3)内存泄露检测工具 ------>LeakCanary

内存溢出 out of memory:是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。内存溢出通俗的讲就是内存不够用。

内存泄露 memory leak:是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光

内存泄露原因以及解决:

  • Handler 引起的内存泄漏。
    解决:将Handler声明为静态内部类,就不会持有外部类SecondActivity的引用,其生命周期就和外部类无关,
    如果Handler里面需要context的话,可以通过弱引用方式引用外部类
  • 单例模式引起的内存泄漏。
    解决:Context是ApplicationContext,由于ApplicationContext的生命周期是和app一致的,不会导致内存泄漏
  • 非静态内部类创建静态实例引起的内存泄漏。
    解决:把内部类修改为静态的就可以避免内存泄漏了
  • 非静态匿名内部类引起的内存泄漏。
    解决:将匿名内部类设置为静态的。
  • 注册/反注册未成对使用引起的内存泄漏。
    注册广播接受器、EventBus等,记得解绑。
  • 资源对象没有关闭引起的内存泄漏。
    在这些资源不使用的时候,记得调用相应的类似close()、destroy()、recycler()、release()等方法释放。
  • 集合对象没有及时清理引起的内存泄漏。
    通常会把一些对象装入到集合中,当不使用的时候一定要记得及时清理集合,让相关对象不再被引用。

10.图片加载框架有哪些?他们之间的区别是什么?

  • ImageLoader :

    • 优点:
      ① 支持下载进度监听;
      ② 可以在 View 滚动中暂停图片加载;
      ③ 默认实现多种内存缓存算法这几个图片缓存都可以配置缓存算法,不过 ImageLoader 默认实现了较多缓存算法,如 Size 最大先删除、使用最少先删除、最近最少使用、先进先删除、时间最长先删除等;
      ④ 支持本地缓存文件名规则定义;
    • 缺点:
      缺点在于不支持GIF图片加载, 缓存机制没有和http的缓存很好的结合, 完全是自己的一套缓存机制
  • Picasso:

    • 优点:
      ① 自带统计监控功能,支持图片缓存使用的监控,包括缓存命中率、已使用内存大小、节省的流量等。
      ② 支持优先级处理
      ③ 支持延迟到图片尺寸计算完成加载
      ④ 支持飞行模式、并发线程数根据网络类型而变,手机切换到飞行模式或网络类型变换时会自动调整线程池最大并发数。
      ⑤ “无”本地缓存。Picasso 自己没有实现本地缓存,而由okhttp 去实现,这样的好处是可以通过请求 Response Header 中的 Cache-Control 及 Expired 控制图片的过期时间。
    • 缺点:
      于不支持GIF,默认使用ARGB_8888格式缓存图片,缓存体积大。
  • Glide:Glide.with(myFragment).load(url).centerCrop().placeholder(R.drawable.loading_spinner).crossFade().into(myImageView);

    • 优点:
      ① 图片缓存->媒体缓存 ,支持 Gif、WebP、缩略图。甚至是 Video。
      ② 支持优先级处理
      ③ 与 Activity/Fragment 生命周期一致,支持 trimMemory
      ④ 支持 okhttp、Volley。Glide 默认通过 UrlConnection 获取数据,可以配合 okhttp 或是 Volley 使用。实际 ImageLoader、Picasso 也都支持 okhttp、Volley。
      ⑤ 内存友好,内存缓存更小图片,图片默认使用默认 RGB565 而不是 ARGB888
    • 缺点:
      清晰度差,但可以设置
      https://www.jianshu.com/p/791ee473a89b
  • Fresco:

    • 优点:
      ① 图片存储在安卓系统的匿名共享内存, 而不是虚拟机的堆内存中,所以不会因为图片加载而导致oom, 同时也减少垃圾回收器频繁调用回收Bitmap导致的界面卡顿,性能更高.
      ② 渐进式加载JPEG图片, 支持图片从模糊到清晰加载
      ③ 图片可以以任意的中心点显示在ImageView, 而不仅仅是图片的中心.
      ④ JPEG图片改变大小也是在native进行的, 不是在虚拟机的堆内存, 同样减少OOM
      ⑤ 很好的支持GIF图片的显示
    • 缺点:
      框架较大, 影响Apk体积,使用较繁琐

11.网络框架有哪些?他们之间的区别是什么?

  • Xutils
    这个框架非常全面,可以进行网络请求,可以进行图片加载处理,可以数据储存,还可以对view进行注解,使用这个框架非常方便,但是缺点也是非常明显的,使用这个项目,会导致项目对这个框架依赖非常的严重,一旦这个框架出现问题,那么对项目来说影响非常大的

  • OKhttp
    Android开发中是可以直接使用现成的api进行网络请求的。就是使用HttpClient,HttpUrlConnection进行操作。okhttp针对Java和Android程序,封装的一个高性能的http请求库,支持同步,异步,而且okhttp又封装了线程池,封装了数据转换,封装了参数的使用,错误处理等。API使用起来更加的方便。但是我们在项目中使用的时候仍然需要自己在做一层封装,这样才能使用的更加的顺手。

  • Volley
    Volley是Google官方出的一套小而巧的异步请求库,该框架封装的扩展性很强,支持HttpClient、HttpUrlConnection, 甚至支持OkHttp,而且Volley里面也封装了ImageLoader,所以如果你愿意你甚至不需要使用图片加载框架,不过这块功能没有一些专门的图片加载框架强大,对于简单的需求可以使用,稍复杂点的需求还是需要用到专门的图片加载框架。Volley也有缺陷,比如不支持post大数据,所以不适合上传文件。不过Volley设计的初衷本身也就是为频繁的、数据量小的网络请求而生。

  • Retrofit
    Retrofit是Square公司出品的默认基于OkHttp封装的一套RESTful网络请求框架,RESTful是目前流行的一套api设计的风格, 并不是标准。Retrofit的封装可以说是很强大,里面涉及到一堆的设计模式,可以通过注解直接配置请求,可以使用不同的http客户端,虽然默认是用http ,可以使用不同Json Converter 来序列化数据,同时提供对RxJava的支持,使用Retrofit + OkHttp + RxJava + Dagger2 可以说是目前比较潮的一套框架,但是需要有比较高的门槛。

  • Volley VS OkHttp
    Volley的优势在于封装的更好,而使用OkHttp你需要有足够的能力再进行一次封装。而OkHttp的优势在于性能更高,因为 OkHttp基于NIO和Okio ,所以性能上要比 Volley更快。IO 和 NIO这两个都是Java中的概念,如果我从硬盘读取数据,第一种方式就是程序一直等,数据读完后才能继续操作这种是最简单的也叫阻塞式IO,还有一种是你读你的,程序接着往下执行,等数据处理完你再来通知我,然后再处理回调。而第二种就是 NIO 的方式,非阻塞式, 所以NIO当然要比IO的性能要好了,而 Okio是 Square 公司基于IO和NIO基础上做的一个更简单、高效处理数据流的一个库。理论上如果Volley和OkHttp对比的话,更倾向于使用 Volley,因为Volley内部同样支持使用OkHttp,这点OkHttp的性能优势就没了, 而且 Volley 本身封装的也更易用,扩展性更好些。

  • OkHttp VS Retrofit
    毫无疑问,Retrofit 默认是基于 OkHttp 而做的封装,这点来说没有可比性,肯定首选 Retrofit。

  • Volley VS Retrofit
    这两个库都做了不错的封装,但Retrofit解耦的更彻底,尤其Retrofit2.0出来,Jake对之前1.0设计不合理的地方做了大量重构, 职责更细分,而且Retrofit默认使用OkHttp,性能上也要比Volley占优势,再有如果你的项目如果采用了RxJava ,那更该使用 Retrofit 。所以这两个库相比,Retrofit更有优势,在能掌握两个框架的前提下该优先使用 Retrofit。但是Retrofit门槛要比Volley稍高些,要理解他的原理,各种用法,想彻底搞明白还是需要花些功夫的,如果你对它一知半解,那还是建议在商业项目使用Volley吧。

12.Android与服务器交互的方式中的对称加密和非对称加密是什么?

  • 对称加密,就是加密和解密数据都是使用同一个key,这方面的算法有DES。
  • 非对称加密,加密和解密是使用不同的key。发送数据之前要先和服务端约定生成公钥和私钥,使用公钥加密的数据可以用私钥解密,反之。这方面的算法有RSA。ssh 和 ssl都是典型的非对称加密。

13.简述TCP,UDP,Socket?

  • TCP是经过3次握手,4次挥手完成一串数据的传送
  • UDP是无连接的,知道IP地址和端口号,向其发送数据即可,不管数据是否发送成功
  • Socket是一种不同计算机,实时连接,比如说传送文件,即时通讯‘’

15.安卓六大布局?

1、线性布局(LinearLayout):按照垂直或者水平方向布局的组件
2、帧布局(FrameLayout):组件从屏幕左上方布局组件
3、表格布局(TableLayout):按照行列方式布局组件
4、绝对布局(AbsoluteLayout):按照绝对坐标来布局组件
5、相对布局(RelativeLayout):相对其它组件的布局方式
6、约束布局 (ConstraintLayout):按照约束布局组件

16.XML和JSON解析?

android一共提供了三种XMl解析的方式,分别为:SAX解析,Pull解析,DOM解析。https://blog.csdn.net/u013209460/article/details/53506330

  • 第一种:SAX解析:
    SAX是驱动型的xml解析,对文档进行顺序扫描,当扫描到document开始,元素的开始与结束,文档结束等地方通知相关处理事件处理函数,处理完函数之后继续进行扫描直到文档结束
    实现步骤:通过SAXParserFactory得到一个SAXParser解析器,将文件流和处理类传递给SAXParser进行xml解析

  • 第二种方式Pull解析
    它的解析原理和SAX是一样的,不同的是它需要我们自己根据产生事件做出相应的操作。pull解析小巧灵便,解析速度快,简单易用,是android推荐的方式
    代码实现步骤:通过Xml获取一个XmlPullParser解析器,根据当前的eventType的不同类型进行相应的数据存取操作

  • 第三种方式:Dom解析
    对象文档模型,将整个Xml文档载入内存中,把每个节点当做一个对象 不推荐使用
    代码实现步骤:通过DocumentBuilderFactory获取一个DocumentBuilder解析器得到一个Document 按照顺序解析这个xml树

Android项目之JSON解析(3种解析技术详解)
  • 用Android原生技术解析JSON:
    特点:很麻烦,对于复杂的json数据解析很容易出错!(不推荐使用)
    1、解析JSON对象的API:JsonObject
    JSONObject(String json);将Json字符串解析成Json对象;
    XxxgetXxx(String name) ;根据name在json对象中得到相应的value。
    2、解析Json数组的API:JSONArray
    JSONArray(String json);将json字符串解析成json数组;
    int length();得到json数组中元素的个数;
    XxxgetXxx(int s) ;根据下标得到json数组中对应的元素数据。

  • 用Gson框架技术解析JSON:
    特点:解析没那么麻烦,代码量简洁,可以很方便地解析复杂的Json数据,而且谷歌官方也推荐使用。
    先放出jar包的下载地址:https://mvnrepository.com/artifact/com.google.code.gson/gson

    • 用Gson解析JSON对象:
      • 1)将gson的jar包导入到项目libs目录下,或者直接通过Gradle添加依赖:
        compile group: ‘com.google.code.gson’, name: ‘gson’, version: ‘2.8.0’
      • 2)创建Gson对象:
        [java] view plain copy
        Gson gson = new Gson();
      • 3)通过创建的Gson对象调用fromJson()方法,返回该json数据对象的Java对象;
        [java] view plain copy
        ShopInfo shopInfo = gson.fromJson(json, ShopInfo.class);

注意要记得创建对象的JavaBean类;要求json对象中的key的名称与Java对象的JavaBean类中的属性名要相同,否则解析不成功!

  • 用Gson解析JSON数组:
    (1)(2)与上面相同,要用Gson就要先添加依赖,然后创建Gson对象;
    (3)通过创建的Gson对象调用fromJson()方法,返回该json数据对应的Java集合。

这里但强调一下:要记得创建对象的JavaBean类;要求json对象中的key的名称与Java对象的JavaBean类中的属性名要相同,否则解析不成功!

  • 用Fastjson框架技术解析JSON:
    特点:Fastjson是用Java语言编写的高性能功能完善的JSON库。它采用了一种“假定有序、快速匹配”的算法,
    把JSON Parse的性能提升到极致,是目前Java语言中最快的JSON库。
    Fastjson是阿里巴巴开源框架,已经开源到github上了,地址为:https://github.com/alibaba/fastjson
    1、用Fastjson解析JSON对象:
    利用Fastjson的JSON调用parseObject()方法,获取转换后的Java对象。
    注意要记得创建对象的JavaBean类;要求json对象中的key的名称与Java对象的JavaBean类中的属性名要相同,否则解析不成功!

  • .用Fastjson解析JSON数组:
    利用Fastjson的JSON调用parseArray()方法,获取转换后的Java集合。

这里但强调一下:要记得创建对象的JavaBean类;要求json对象中的key的名称与Java对象的JavaBean类中的属性名要相同,否则解析不成功!

17.Android APK打包流程?

https://www.cnblogs.com/xunbu7/p/7345912.html

  1. 打包资源文件,生成R.java文件
  2. 处理aidl文件,生成相应的Java文件
  3. 编译项目源代码,生成class文件
  4. 转换所有的class文件,生成classes.dex文件
  5. 打包生成APK文件
  6. 对APK文件进行签名
  7. 对签名后的APK文件进行对齐处理

18.APP 启动流程。

App启动5步走
借用GITYUAN大神的一张图结合启动App逻辑讲一下App启动的整个流程,不过这是一张Launcher App启动的图,和我们要说的有点不一样,我们根据老罗所说的将App启动分为5步

  • Launcher通过Binder进程间通信机制通知ActivityManagerService,
    它要启动一个Activity;
  • ActivityManagerService通过Binder进程间通信机制通知Launcher进入Paused状态;
  • Launcher通过Binder进程间通信机制通知ActivityManagerService,它已经准备就绪进入Paused状态, 于是ActivityManagerServicey利用Zygote.fork()创建一个新的进程,用来启动一个ActivityThread实例, 即将要启动的Activity就是在这个ActivityThread实例中运行;
  • ActivityThread通过Binder进程间通信机制将一个ApplicationThread类型的Binder对象传递给ActivityManagerService,
    以便以后ActivityManagerService能够通过这个Binder对象和它进行通信;
  • ActivityManagerService通过Binder进程间通信机制通知ActivityThread,
    现在一切准备就绪,它可以真正执行Activity的启动操作了。
    原文链接:https://blog.csdn.net/oheg2010/article/details/82826415

19.如何检测卡顿,卡顿原理是什么,怎么判断是页面响应卡顿还是逻辑处理造成的卡顿?

  • 关于卡顿的分析方案,已经有以下两种:
    1.分析 trace 文件。通过分析系统的/data/anr/traces.txt,来找到导致 UI 线程阻塞的源头,这种方案比较适合开发过程中使用,而不适合线上环境;
    2使用 BlockCanary 开源方案。其原理是利用 Looper 中的 loop 输出的>>>>> Dispatching to 和<<<<< Finished to 这样的 log,这种方案适合开发过程和上线的时候使用,但也有个弊端,就是如果系统移除了前面两个 log,检测可能会面临失效。
    下面就开始说本文要提及的卡顿检测实现方案,原理简单,代码量也不多,只有 BlockLooper 和 BlockError 两个类。
    原文链接:https://blog.csdn.net/byeweiyang/article/details/80129808

20.如何让android的service一直在后台运行

  1. 把service和activity分开,让service开机启动。设置一个broadcast receiver接受开机信号, 使用RECEIVE_BOOT_COMPLETED的permission, 然后启动service。activity启动后绑定到service上,通过ipc机制通信,acitivity结束后松绑。注意安装后要手动启动service,不会自动启动,之后重启手机后才会随开机启动。
  2. 在内存低的时候系统会自动清理进程,这时候后台service可能会被杀掉。可以在onStartCommand中返回START_STICKY,这样系统有足够多资源的时候,就会重新开启service。
    原文链接:https://blog.csdn.net/it_51888_liang/article/details/51018354

21.属性动画、补间动画、帧动画的区别和使用场景

  • 补间动画和属性动画主要区别:
    作用对象不同,补间动画只能作用在view上,属性动画可以作用在所有对象上。
    属性变化不同,补间动画只是改变显示效果,不会改变view的属性,比如位置、宽高等,而属性动画实际改变对象的属性。
    动画效果不同,补间动画只能实现位移、缩放、旋转和透明度四种动画操作,而属性动画还能实现补间动画所有效果及其他更多动画效果。

  • 帧动画的特性:
    用于生成连续的Gif效果图。
    b. DrawableAnimation也是指此动画
    帧动画的优缺点:
    缺点:效果单一,逐帧播放需要很多图片,占用控件较大
    优点:制作简单
    使用场景:

  • 补间动画: 适用于对单一静态图片做旋转,平移以及缩放和透明度设置等等操作。

  • 帧动画: 适用于构造一个类似gif动图场景,须由多张不同形态的照片来实现。有一点需要注意的是,帧动画在停止之后不能继续从停止帧继续向后执行,而是从头执行。(即没有所谓的暂停)。这也是帧动画的缺点。 因为有些场景我们需要将动画停止,然后继续从停止处执行。详情参考博文:https://blog.csdn.net/lly347705530/article/details/78671696

22.Mqtt 长连接

https://www.jianshu.com/p/51c8c9b05a9c

  • MQTT协议有以下特点:
    1.使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序之间的耦合。
    2.对负载内容屏蔽的消息传输。
    3.使用 TCP/IP 提供基础网络连接。
    4.小型传输,开销很小(固定长度的是头部是2个字节),协议交换最小化,以降低网络流量
    整体上协议可拆分为:固定头部+可变头部+消息体,这就是为什么在介绍里说它非常适合"在物联网领域,传感器与服务器的通信,信息的收集"。
    5.提供一种机制,使得客户端异常中断时,能够使用LastWill和Testament特性通知有关各方
    Last Will:即遗言机制,用于通知同一主题下的其他设备发送遗言的设备已经断开了连接。
    Testament:遗嘱机制,功能类似于Last Will。
  • 有三种级别消息发布服务质量:
    1.qos为0:“至多一次”,消息发布完全依赖底层 TCP/IP 网络。会发生消息丢失或重复。这一级别可用于如下情况,环境传感器数据,丢失一次读记录无所谓,因为不久后还会有第二次发送。
    2.qos为1:“至少一次”,确保消息到达,但消息重复可能会发生。这一级别可用于如下情况,你需要获得每一条消息,并且消息重复发送对你的使用场景无影响。
    3.qos为2:“只有一次”,确保消息到达一次。这一级别可用于如下情况,在计费系统中,消息重复或丢失会导致不正确的结果。
    小型传输,开销很小(固定长度的头部是 2 字节),协议交换最小化,以降低网络流量。
    使用 Last Will 和 Testament 特性通知有关各方客户端异常中断的机制。

23.Android组件化开发

https://www.jianshu.com/p/3ed9f4c87990

  • 什么是组件化:
    组件化就是将工程按照不同的属性拆分成各个独立的子工程的过程。
    组件是组件化的输出产物,不同的组件最终进行组装就是完整的工程。
    组件化的优点和缺点:
    优点:
      单独编译,便于开发,提升编译速度。
      组件分离,便于维护,提高重用效率。
      单独发布,便于测试,提升测试准度。
    缺点:
      对开发管理的要求更高
  • 组件交互:
    因为组件与组件之间不能相互引用,所以组件与组件的交互需要一个中间件Router,组件进行交互之前需要通过Router进行寻址中转传递彼此的接口。
    Router使用
    https://www.jianshu.com/p/aa17cf4b2dca
    https://www.jianshu.com/p/6021f3f61fa6

24.App性能优化

https://www.jianshu.com/p/d71b51a0e29f

  • 有如下几点:

    • APP使用起来不卡顿,要流畅;
    • 要省电,省流量;
    • 要稳定,不闪退(减少闪退,ANR率);
    • APP包尽量要小;
  • 卡顿原因
    Android 应用启动慢,使用时经常卡顿,是非常影响用户体验的,应该尽量避免出现。总的来说造成卡顿的原因有如下几种:

    • UI的绘制。主要原因是绘制的层级深、页面复杂、刷新不合理,由于这些原因导致卡顿的场景更多出现在 UI 和启动后的初始界面以及跳转到页面的绘制上。
    • 数据处理上。导致这种卡顿场景的原因是数据处理量太大,一般分为三种情况,一是数据在主线程处理,这个是初级工程师会犯的错误,二是数据处理占用 CPU 高,导致主线程拿不到时间片,三是内存增加导致 GC 频繁,从而引起卡顿。引起卡顿的原因很多,但不管怎么样的原因和场景,最终都是通过设备屏幕上显示来达到用户,归根到底就是显示有问题,所以,要解决卡顿,就要先了解 Android 系统的渲染机制。
      UI的过度绘制,绘制的页面有几层View,底层View都是隐藏的,这种的还绘制的话就会造成过度绘制
      andriod卡顿优化方案
    • 不要在主线程进行网络访问/大文件的IO操作
    • 绘制UI时,尽量减少绘制UI层次;减少不必要的view嵌套,可以用Hierarchy Viewer工具来检测,后面会详细讲;
    • 当我们的布局是用的FrameLayout的时候,我们可以把它改成merge,可以避免自己的帧布局和系统的ContentFrameLayout帧布局重叠造成重复计算(measure和layout)
    • 提高显示速度,使用ViewStub:当加载的时候才会占用。不加载的时候就是隐藏的,仅仅占用位置。
    • 在view层级相同的情况下,尽量使用 LinerLayout而不是RelativeLayout;因为RelativeLayout在测量的时候会测量二次,而LinerLayout测量一次,可以看下它们的源码;
    • 删除控件中无用的属性;
    • 布局复用.比如listView 布局复用
    • 尽量避免过度绘制(overdraw),比如:背景经常容易造成过度绘制。由于我们布局设置了背景,同时用到的MaterialDesign的主题会默认给一个背景。这时应该把主题添加的背景去掉;还有移除 XML 中非必须的背景
    • 自定义View优化。使用 canvas.clipRect()来帮助系统识别那些可见的区域,只有在这个区域内才会被绘制。也是避免过度绘制.
    • 启动优化,启动速度的监控,发现影响启动速度的问题所在,优化启动逻辑,提高应用的启动速度。比如闪屏页面,合理优化布局,加载逻辑优化,数据准备,这里后面我会单独写一篇文章讲如何优化程序的启动速度及Splash页面设计,这里还会讲到热启动和冷启动.
    • 合理的刷新机制,尽量减少刷新次数,尽量避免后台有高的 CPU 线程运行,缩小刷新区域。
      andriod卡顿优化所用到的工具
      性能问题并不容易复现,也不好定位,但是真的碰到问题就需要借助相应的的调试工具,下面介绍比较常用的调试工具。
      1.Profile GPU Rendering
      2.Debug GPU overDraw过度绘制检测
  • 耗电优化
    在移动设备中,电池的重要性不言而喻,没有电什么都干不成。对于操作系统和设备开发商来说,耗电优化一致没有停止,去追求更长的待机时间,而对于一款应用来说,并不是可以忽略电量使用问题,特别是那些被归为“电池杀手”的应用,最终的结果是被卸载。因此,应用开发者在实现需求的同时,需要尽量减少电量的消耗。

    • 耗电的原因其实很多,这里我就讲一下几种优化方案,优化方案的反面就是他的原因了,几种优化方案如下:
      • A.合理的使用wack_lock锁,wake_lock锁主要是相对系统的休眠(这里就是为了省电,才做休)而言的,意思就是我的程序给CPU加了这个锁那系统就不会休眠了,这样做的目的是为了全力配合我们程序的运行。有的情况如果不这么做就会出现一些问题,比如微信等及时通讯的心跳包会在熄屏不久后停止网络访问等问题。所以微信里面是有大量使用到了wake_lock锁。这里有一篇关于wake_lock的使用,请查阅;
      • B.使用jobScheduler2,集中处理一些网络请求,有些不用很及时的处理可以放在充电的时候处理,比如,图片的处理,APP下载更新等等,这里有一篇关于jobScheduler的使用,请查阅;
      • C.计算优化,避开浮点运算等。
      • D.数据在网络上传输时,尽量压缩数据后再传输,建议用FlatBuffer序列化技术,这个比json效率高很多倍,不了解FlatBuffer,建议找资料学习一下,后面有时间的话,也会专门写关于FlatBuffer的文章.
        andriod耗电分析所用到的工具
        在 Android5.0 以前,在应用中测试电量消耗比较麻烦,也不准确,5.0 之后专门引入了一个获取设备上电量消耗信息的 API:Battery Historian。Battery Historian 是一款由 Google 提供的 Android 系统电量分析工具,是一款图形化数据分析工具,直观地展示出手机的电量消耗过程,通过输入电量分析文件,显示消耗情况,最后提供一些可供参考电量优化的方法。
  • 安装包大小优化
    随着功能不断增加,APP的包肯定不会断的变大,但应用的安装包越大,用户下载的门槛越高,特别是在移动网络情况下,用户在下载应用时,对安装包大小的要求更高,因此,减小安装包大小可以让更多用户愿意下载和体验产品。所以,我们还是要想办法去如何去优化,尽量减小app的安排包.

    • APP包优化方案
      • res资源优化
        (1)只使用一套图片,使用高分辨率的图片。
        (2)UI设计在ps安装TinyPNG插件,对图片进行无损压缩。
        (3)svg图片:一些图片的描述,牺牲CPU的计算能力的,节省空间。使用的原则:简单的图标。
        (4)图片使用WebP(https://developers.google.com/speed/webp/)的格式(Facebook、腾讯、淘宝在用。)缺点:加载相比于PNG要慢很多。 但是配置比较高。工具:http://isparta.github.io/
        (5)使用tintcolor(android - Change drawable color programmatically)实现按钮反选效果。
      • 代码优化
        (1)实现功能模块的逻辑简化
        (2)Lint工具检查无用文件将无用的资源列在“UnusedResources: Unused resources”,删除。
        (3)移除无用的依赖库。
        lib资源优化
        (1)动态下载的资源。
        (2)一些模块的插件化动态添加。
        (3)so文件的剪裁和压缩。
      • assets资源优化
        (1)音频文件最好使用有损压缩的格式,比如采用opus、mp3等格式,但是最好不要使用无损压缩的音乐格式
        (2)对ttf字体文件压缩,可以采用FontCreator工具只提取出你需要的文字。比如在做日期显示时,其实只需要数字字体,但是使用原有的字体库可能需要10MB大小,如果只是把你需要的字体提取出来生成的字体文件只有10KB
      • 代码混淆。
        使用proGuard 代码混淆器工具,它包括压缩、优化、混淆等功能。
      • 7z极限压缩
        具体请参考微信的安接包压缩,实现实现原理,有时间再分析;
  • 内存优化
    在 Android 系统中有个垃圾内存回收机制,在虚拟机层自动分配和释放内存,因此不需要在代码中分配和释放某一块内存,从应用层面上不容易出现内存泄漏和内存溢出等问题,但是需要内存管理。Android 系统在内存管理上有一个 Generational Heap Memory 模型,内存回收的大部分压力不需要应用层关心, Generational Heap Memory 有自己一套管理机制,当内存达到一个阈值时,系统会根据不同的规则自动释放系统认为可以释放的内存,也正是因为 Android 程序把内存控制的权力交给了 Generational Heap Memory,一旦出现内存泄漏和溢出方面的问题,排查错误将会成为一项异常艰难的工作。除此之外,部分 Android 应用开发人员在开发过程中并没有特别关注内存的合理使用,也没有在内存方面做太多的优化,当应用程序同时运行越来越多的任务,加上越来越复杂的业务需求时,完全依赖 Android 的内存管理机制就会导致一系列性能问题逐渐呈现,对应用的稳定性和性能带来不可忽视的影响,因此,解决内存问题和合理优化内存是非常有必要的。
    在开发的过程,如果方法不当的话,很容易造成内存泄漏,接下来,来说一下哪些情景容易出现内存泄漏。

    • 内存泄漏出现的情景
      • 单例中引用的上下文Context,引用了Activity中的Context, 这样会造成内存泄漏,要引用Application中的Context;
      • 资源性对象未关闭。比如Cursor、File文件等,往往都用了一些缓冲,在不使用时,应该及时关闭它们。
      • 注册对象未注销。比如事件注册后未注销,会导致观察者列表中维持着对象的引用。
        类的静态变量持有大数据对象。
      • 非静态内部类的静态实例。
      • Handler临时性内存泄漏。如果Handler是非静态的,容易导致 Activity 或 Service 不会被回收。
      • 容器中的对象没清理造成的内存泄漏。
      • WebView。WebView 存在着内存泄漏的问题,在应用中只要使用一次 WebView,内存就不会被释放掉。
        内存优化的方案
      • 对象引用。强引用、软引用、弱引用、虚引用四种引用类型,根据业务需求合理使用不同,选择不同的引用类型。
      • 减少不必要的内存开销。注意自动装箱,增加内存复用,比如有效利用系统自带的资源、视图复用、对象池、Bitmap对象的复用。
      • 使用最优的数据类型。比如针对数据类容器结构,可以使用ArrayMap数据结构,避免使用枚举类型,使用缓存Lrucache等等。
      • 图片内存优化。可以设置位图规格,根据采样因子做压缩,用一些图片缓存方式对图片进行管理等等。图片的压缩几种方案;
  • 内存分析工具
    做内存优化前,需要了解当前应用的内存使用现状,通过现状去分析哪些数据类型有问题,各种类型的分布情况如何,以及在发现问题后如何发现是哪些具体对象导致的,这就需要相关工具来帮助我们。以下介绍几种内存分析工具

    • Memory Monitor
      Memory Monitor 是一款使用非常简单的图形化工具,可以很好地监控系统或应用的内存使用情况.

      • 主要有以下功能:
        (1).显示可用和已用内存,并且以时间为维度实时反应内存分配和回收情况。
        (2).快速判断应用程序的运行缓慢是否由于过度的内存回收导致。
        (3).快速判断应用是否由于内存不足导致程序崩溃。
    • Heap Viewer
      Heap Viewer 的主要功能是查看不同数据类型在内存中的使用情况,可以看到当前进程中的 Heap Size 的情况,分别有哪些类型的数据,以及各种类型数据占比情况。通过分析这些数据来找到大的内存对象,再进一步分析这些大对象,进而通过优化减少内存开销,也可以通过数据的变化发现内存泄漏。

      • 主要有以下功能:
        (1)实时查看App分配的内存大小和空闲内存大小
        (2)发现Memory Leaks
        Heap Viewer不光可以用来检测是否有内存泄漏,对于内存抖动,我们也可以用该工具检测,因为内存抖动的时候,会频繁发生GC,这个时候我们只需要开启Heap Viewer,观察数据的变化,如果发生内存抖动,会观察到数据在段时间内频繁更新。
    • Allocation Tracker
      Memory Monitor 和 Heap Viewer 都可以很直观且实时地监控内存使用情况,还能发现内存问题,但发现内存问题后不能再进一步找到原因,或者发现一块异常内存,但不能区别是否正常,同时在发现问题后,也不能定位到具体的类和方法。这时就需要使用另一个内存分析工具 Allocation Tracker,进行更详细的分析, Allocation Tracker 可以分配跟踪记录应用程序的内存分配,并列出了它们的调用堆栈,可以查看所有对象内存分配的周期。

    • Memory Analyzer Tool(MAT)
      MAT 是一个快速,功能丰富的 Java Heap 分析工具,通过分析 Java 进程的内存快照 HPROF 分析,从众多的对象中分析,快速计算出在内存中对象占用的大小,查看哪些对象不能被垃圾收集器回收,并可以通过视图直观地查看可能造成这种结果的对象。

  • 稳定性优化
    Android 应用的稳定性定义很宽泛,影响稳定性的原因很多,比如内存使用不合理、代码异常场景考虑不周全、代码逻辑不合理等,都会对应用的稳定性造成影响。其中最常见的两个场景是:Crash 和 ANR,这两个错误将会使得程序无法使用,比较常用的解决方式如下:
    A.提高代码质量。比如开发期间的代码审核,看些代码设计逻辑,业务合理性等。
    B.代码静态扫描工具。常见工具有Android Lint、Findbugs、Checkstyle、PMD等等。
    C.Crash监控。把一些崩溃的信息,异常信息及时地记录下来,以便后续分析解决。
    D.Crash上传机制。在Crash后,尽量先保存日志到本地,然后等下一次网络正常时再上传日志信息。

你可能感兴趣的:(Android基础)