支付流程(面试题07)

1.屏幕适配:
为了让我们开发的程序能够比较美观的显示在不同尺寸、分辨率、像素密度的设备上。
1.使用约束布局或者相对布局
就可以根据各组件之间的特殊关系指定布局
2.适配不同尺寸避免写死的尺寸值;wrap_content,match_parent,weight,利用dpi换算dp和px的值。
3.图片考虑使用可以拉伸的,xml自定义shape图片,矢量图,自动拉伸.9图
4.限定符;最小宽度限定符,屏幕方向限定符,布局别名。(要注意限定符的优先级)
2.内存溢出和内存泄漏的区别,产生原因以及解决方案
概念与区别
内存溢出:没有足够的内存空间可以使用, 那就是内存溢出。
内存泄露:内存泄漏时一个对象已经不需要再使用了,但是其他的对象还持有该对象的引用,导致内存不能被垃圾回收器回收。比如在内部类持有外部类的引用时。静态变量,非静态内部类:持有外部类引用(handler)。内存泄漏会导致OOM.
内存泄露的解决方案:
1.不要在匿名内部类中进行异步操作
2.使用Context时,尽量使用Application 的 Context
3.尽量避免使用static 成员变量。

将Handler声明为静态类。静态类不持有外部类的对象,所以你的Activity可以随意被回收。需要在Handler中增加一个对Activity的弱引用(WeakReference)。因为handler不在持有外部对象的引用
内存溢出
1.内存中加载的数据量过于庞大
2.集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
3.代码中存在死循环或循环产生过多重复的对象实体;
内存溢出的解决方案:
动态回收内存
优化Dalvik虚拟机的堆内存分配
在内存引用上做处理,比如软引用、弱引用等
3.事件分发
事件分发,如果有多层嵌套的时候,让那个控件消费这个点击事件
事件分发三个主要的方法分别是:dispatchTouchEvent(分发) onTouchEvent(消费)
onInterceptTouchEvent(拦截),只有容器才有onInterceptTouchEvent(拦截方法)
从Activity开始,进入事件分发,Activity无论返回true或false都自己消费,因为他自己就是顶层,被系统消费,返回super向下分发,交给子viewgroup,如果viewgroup的dispatchTouchEvent(分发)返回true就消费,返回false交给上一层消费,返回super交给 自身拦截事件,拦截事件返回true的话自己消费,其他则继续想下分发,子view的分发事件为true自己消费,返回false交给上一层
4.Handler机制
Handler 的主要作用是线程间通信,实现子线程与主线程的切换,通过 Handler 来异步更新UI,避免线程操作不安全的问题
总体流程:Handler向MessageQueue发送一条Message,MessageQueue通过next方法把消息传给Looper,Looper收到消息后开始处理,然后最终交给Handler自己去处理。
Message Queue(消息队列):负责存储消息对象,按照先进先出原则执行,是由Message组成的一个队列;
Message:消息类,包含了消息处理对象以及处理的数据等。
Looper:负责消息队列的创建,从消息队列中获取消息执行,一个MessageQueue需要一个Looper;
Handler :是Message的主要处理者,负责管理消息的发送和收到消息后的逻辑处理

在子线程创建handler:(因为handler必须要调用looper. Prepare()方法,所以必须要在子线程中获取looper对象。)
方法一:在run方法创建一个handler对象,获取主线程的looper来实现。
方法二:在run方法通过looper.prepare()获取looper对象,在发送消息完调用Looper.loop方法,不断遍历MessageQueue方法

主线程的Looper.loop为什么不可以造成死循环
android所有的UI处理都是通过handler消息机制处理的,每次处理都发送到消息队列,从消息队列取出来才进行执行,如果消息队列没有就不执行,所以不会造成死循环。
5.性能优化:
卡顿优化
1、布局优化
一个页面的显示测量和绘制过程都是通过递归来完成的,如果层级太深,每增加一层则会增加更多的页面显示时间,所以布局的合理性就显得很重要。
1.减少层级。合理使用 RelativeLayout 和 LinerLayout,ConstraintLayout
2.Merge合并,减少层级,从而减少绘制时间。
3.使用 ViewStub来提高显示速度。是看不见,占用资源非常小的视图对象,仅在需要时才加载布局,
4.布局复用。可以通过include标签来提高复用。
5.尽可能少用wrap_content。在已知宽高为固定值时,不用wrap_content 。wrap_content会增加布局计算成本
2、避免过度绘制
过度绘制是指在屏幕上的同一块地方在一时间被绘制了多次。从而浪费了多余的 CPU 以及 GPU 资源。解决:移除 XML 中非必须的背景,移除 Window 默认的背景、按需要显示占位背景图片
3、合理的刷新机制
在应用开发过程中,因为数据的变化,需要刷新页面来展示新的数据,但频繁刷新会增加资源开销,并且可能导致卡顿发生,因此,需要一个合理的刷新机制来提高整体的 UI 流畅度。合理的刷新需要注意以下几点:
1.尽量减少刷新次数。
2.尽量避免后台有高的 CPU 线程运行。
3.缩小刷新区域。
内存优化
1、优化内存空间
Android 系统对每个应用进程也都分配了有限的内存, GC 能更高效地回收不再需要使用的对象,让应用存保持充足的可用内存,使应用更稳定高效地运行。常见做法如下:
1.对象引用。强引用、软引用、弱引用、虚引用四种引用类型
2.减少不必要的内存开销。注意自动装箱,增加内存复用,比如有效利用系统自带的资源、视图复用、对象池、Bitmap对象的复用。
3.使用最优的数据类型。比如针对数据类容器结构,可以使用ArrayMap数据结构,避免使用枚举类型,使用缓存Lrucache等等。
4.图片内存优化。可以设置位图规格,根据采样因子做压缩,用一些图片缓存方式对图片进行管理等等。
2、稳定性优化
Android 应用的稳定性定义很宽泛,影响稳定性的原因很多,比如内存使用不合理、代码异常场景考虑不周全、代码逻辑不合理等,都会对应用的稳定性造成影响。其中最常见的两个场景是:Crash 和 ANR,这两个错误将会使得程序无法使用,比较常用的解决方式如下:
1.提高代码质量。比如开发期间的代码审核,看些代码设计逻辑,业务合理性等。
3、耗电优化
5.0 之后专门引入了一个获取设备上电量消耗信息的 API:Battery Historian。Battery Historian 是一款由 Google 提供的 Android 系统电量分析工具,和Systrace 一样,是一款图形化数据分析工具,直观地展示出手机的电量消耗过程,通过输入电量分析文件,显示消耗情况,最后提供一些可供参考电量优化的方法。除此之外,还有一些常用方案可提供:
1.计算优化,避开浮点运算等。
2.避免 WaleLock 使用不当。
3.使用 Job Scheduler。
4、安装包大小优化
减少安装包大小的常用方案
1.代码混淆。使用proGuard 代码混淆器工具,它包括压缩、优化、混淆等功能。
2.资源优化。比如使用 Android Lint 删除剩余资源,资源文件最少化等。
3.图片优化。比如利用 AAPT 工具对 PNG 格式的图片做压缩处理,降低图片色彩位数等。
4.避免重复功能的库,使用 WebP图片格式等。
5.插件化。比如功能模块放在服务器上,按需下载,可以减少安装包大小。

6.OKhttp使用、有哪些操作,原理和源码详解
网络请求的框架用于代替HttpurlConnection和httpclient。可以用来文件上传,下载,加载图片,网络请求,是根据build模式(将一个复杂对象的构建与它的表示分离),链式调用,每一个方法的返回值类型都是当前类的对象
优点是:
1.支持同步、异步。
2.缓存响应数据(减少了重复的网络请求)
3.自动重连(底层是Socket,有自动维护的socket连接池,减少了握手次数)
使用:
先用一个构造好的OkHttpClient和Request获取到一个Call,然后执行call的异步或者同步方法取得Response或者处理异常。
五大拦截器:
一、RetryAndFollowUpInterceptor (重定向拦截器)
1.创建 StreamAllocation对socket进行管理,比如连接复用,选择连接自动重连等
2.根据响应码做重定向和重试,重定向时如果地址不一致会释放连接,多重定向为20次,超出抛异常
二、BridgeInterceptor (桥接拦截器)
用来连接用户请求信息 和 HTTP 请求
BridgeInterceptor 在请求阶段,补全http header,
在响应阶段保存
Cookie
三、CacheInterceptor (缓存拦截器)
在缓存可用的情况下,读取本地的缓存的数据,如果没有直接去服务器读取数据,如果有,首先先判断是否有缓存策略,然后判断是否过期,如果没有过期,直接从缓存中读,如果过期了,你需要添加一些之前的头部信息
注意事项:
只支持GET方式,并且需要服务器配合,通过header相关的头来控制缓存
创建OkhttpClient时候需要配置Cache
四、ConnectInterceptor (连接拦截器)
主要作用是打开了与服务器的链接,正式开启了网络请求。对socket封装,判断连接是否可以重用,除了比较连接当前的host,也可以比较路由信息。最多空闲连接为5,最长空闲时间为五分钟
五、CallServerInterceptor(读写拦截器)
给服务器写数据和读取数据;
写头部信息,写body表单信息等等;
它负责实现网络 IO,所有拦截器都要依赖它才能拿到响应数据。

7.Retrofit使用,常用注解、动态代理以及原理
什么是Retrofit?
Retrofit 是一个Square开发的安卓客户端请求库。其中内部封装了okhttp库。Retrofit使用注解,能够极大的简化网络请求数据的代码。
Retrofit常用注解:
@Query,@QueryMap,@Field,@FieldMap, @FormUrlEncoded,@Path,@Url

@Query,@QueryMap
@Query主要用于Get请求数据,用于拼接在Url路径后面的查询参数,多个参数中间用,隔开。
@QueryMap:主要的效果等同于多个@Query参数拼接,主要也用于Get请求网络数据。
@Field,@FieldMap
@Field的用法类似于@Query,主要不同的是@Field主要用于Post请求数据。@FieldMap的用法类似于@QueryMap。
两者主要区别是:如果请求为post实现,那么最好传递参数时使用@Field、@FieldMap和@FormUrlEncoded。因为@Query和或QueryMap都是将参数拼接在url后面的,而@Field或@FieldMap传递的参数时放在请求体的。
@FormUrlEncoded
如果是Post请求的话,必须加@FromUrlEncoded注解。
@Path
@Path主要用于Get请求,用于替换Url路径中的变量字符
@Url
@Url是动态的Url请求数据的注解。
retrofit有几个关键的地方.(原理)
1.用户自定义的接口和接口方法.由动态代理创建对象.
2.converter转换器.把response转换为一个具体的对象
3.注解的使用.
Retrofit中的动态代理 :
也就是一个网络调用,你只需要在你创建的接口里面通过注解进行设置,然后通过retrofit创建一个api然后调用,就可以自动完成一个Okhttp的Call的创建。
8.RxJava使用,可以实现哪些操作以及常用操作符
RxJava将链式编程和异步结合在一起,采用观察者模式,和响应式编程来实现。RxJava 的异步可以随着程序逻辑变得越来越复杂,它依然能够保持简洁。
RxJava 有四个基本概念:Observable (被观察者)、 Observer (观察者)、 subscribe (订阅)、事件。
Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer。RxJava 的事件回调方法除了普通事件 onNext() 之外,还定义了两个特殊的事件:onCompleted() 和 onError()。
总结:

  1. 只有当Observable被订阅了subscriber)方法才会被执行
  2. onCompleted方法里会把Subscription取消订阅(unsubscribe)
  3. 如果调用了void onError(Throwable e)方法,那么onNext和onCompleted都不会执行。会在onError调用之前,把Subscription取消注册。
  4. 整个事件流不管是正常结束(onComplete)还是出现了异常(onError),Subscription都会被取消注册(unsubscribe)。
    但是,由于我们可能执行一些耗时操作,界面又被关闭了,所以还需要把subscription取消注册
    创建操作
    用于创建Observable(被观察者)的操作符
    Create(创建) — 通过调用观察者(observer)的方法从头开始创建一个Observable
    Just(仅仅) — 将一个对象或者一组对象转换为一个会发出该对象或那些对象的Observable
    Start(开始) — 创建一个发出函数的返回值的Observable
    Timer(定时器) — 创建在一个指定的延迟之后发出单个数据项的Observable
    变换操作
    用于对Observable发出的数据进行变换的操作符
    FlatMap(扁平映射) — 将Observable发出的数据变换为Observables集合,然后将这些 Observable发出的数据平坦化的放进一个单独的Observable,可以认为是一个将嵌套的数据结构展开的过程
    Map(映射) — 通过对序列的每一项都应用一个函数变换Observable发出的数据,实质是对序列中的每一项执行一个函数,函数的参数就是这个数据项
    过滤操作
    用于从Observable发射的数据中选择性的过滤一些数据的操作符
    Distinct(去重) — 抑制Observable发出的重复数据
    First(首选) — 只从Observable发出第一个数据项满足条件的第一个数据项
    Last(末项) — 只发出Observable发出最后一条数据
    组合操作
    用于将多个Observable组合成一个单一的Observable的操作符
    Join - 当在根据由另一Observable发射的项目定义的时间窗期间发出来自一个Observable的项目时,就将两个Observable发射的数据组合成一个并发射
    Merge(合并) - 将多个Observable发射的数据组合并成一个
    Zip - 通过指定的函数将多个Observable的发射组合在一起,并根据此函数的结果为每个组合发出单个数据项
    错误处理操作
    有助于从Observable的错误通知中恢复的操作符
    Catch(捕获) — 继续序列操作,将错误替换为正常的数据,从onError通知中恢复
    Retry(重试) — 如果Observable发射了一个onError通知,重新订阅它,希望它将完成并没有错误
    辅助操作
    用于处理Observable的操作符
    Delay — 延迟一段时间发射结果数据
    ObserveOn(观察在) — 指定Observer观察Observable的调度器(Scheduler)(工作线程)
    Serialize(序列化) — 强制Observable按次序发射数据并且功能是有效的
    Subscribe(订阅) — 收到Observable发射的数据和通知后执行的操作
    SubscribeOn(订阅在) — 指定Observable应该在哪个调度器上执行
    Timeout(超时) — 如果过了指定的一段时间没有发射数据,则发射错误通知
    背压操作
    backpressure operators - 为了应对观察者消费事件比被观察者生产事件更快,所以需要背压
    31、自定义View
    通常自定义view分为
    1.继承现有控件,对其控件的功能进行拓展。
    2.将现有控件进行组合,实现功能更加强大控件。
    3.重写View实现全新的控件
    一般当我们遇到了原生控件无法满足我们现有的需求的时候,我们就可以创建一个全新的View来实现我们所需要的功能。创建一个全新View实现自定义控件,无非分成这么几步:
    1.在OnMeasure()方法中,测量自定义控件的大小,使自定义控件能够自适应布局各种各样的需求。
    将 MeasureSpec 经过自身处理后, 分发到下层子 View
    View 测量流程是父 View 先测量子 View,等子 View 测量完了,再来测量自己。在ViewGroup 测量子 View 的入口就是 measureChildWithMargins
    子 View 确定了大小之后, 再回到父容器中
    父容器结合子 View 大小和 自身布局特性 来确定自己的大小, 一直回到顶层
    2.draw过程
    3.1,背景绘制
    4.2,对View的内容进行绘制
    5.3,对当前View的所有子View进行绘制
    6.4,对View的滚动条进行绘制

7.在OnDraw()方法中,利用Canvas(画布)与Paint(画笔)来绘制要显示的内容。
8.在OnLayout()方法中来确定控件显示位置。
measure() 方法中我们已经测量出View的大小,根据这些大小,我们接下来就需要确定 View 在父 View 的位置进行排版布局,这就是layout 作用。
对 View 进行排版布局,还是要看父 View,也就是 ViewGroup。

10.在OnTouchEvent()方法处理控件的触摸事件。
进程间通信:
一、使用 Intent
1.Activity,Service,Receiver 都支持在 Intent 中传递 Bundle 数据,而 Bundle 实现了 Parcelable 接口,可以在不同的进程间进行传输。
2.在一个进程中启动了另一个进程的 Activity,Service 和 Receiver ,可以在 Bundle 中附加要传递的数据通过 Intent 发送出去。
二、使用文件共享
1.Windows 上,一个文件如果被加了排斥锁会导致其他线程无法对其进行访问,包括读和写;而 Android 系统基于 Linux ,使得其并发读取文件没有限制地进行,甚至允许两个线程同时对一个文件进行读写操作,尽管这样可能会出问题。
2.可以在一个进程中序列化一个对象到文件系统中,在另一个进程中反序列化恢复这个对象(注意:并不是同一个对象,只是内容相同。)。
3.SharedPreferences 是个特例,系统对它的读 / 写有一定的缓存策略,即内存中会有一份 ShardPreferences 文件的缓存,系统对他的读 / 写就变得不可靠,当面对高并发的读写访问,SharedPreferences 有很多大的几率丢失数据。因此,IPC 不建议采用 SharedPreferences。
三、使用 Messenger
Messenger 是一种轻量级的 IPC 方案,它的底层实现是 AIDL ,可以在不同进程中传递 Message 对象,它一次只处理一个请求,在服务端不需要考虑线程同步的问题,服务端不存在并发执行的情形
服务端进程:服务端创建一个 Service 来处理客户端请求,同时通过一个 Handler 对象来实例化一个 Messenger 对象,然后在 Service 的 onBind 中返回这个 Messenger 对象底层的 Binder 即可。
客户端进程:首先绑定服务端 Service ,绑定成功之后用服务端的 IBinder 对象创建一个 Messenger ,通过这个 Messenger 就可以向服务端发送消息了,消息类型是 Message 。如果需要服务端响应,则需要创建一个 Handler 并通过它来创建一个 Messenger(和服务端一样),并通过 Message 的 replyTo 参数传递给服务端。服务端通过 Message 的 replyTo 参数就可以回应客户端了。
四、使用 AIDL
Messenger 是以串行的方式处理客户端发来的消息,如果大量消息同时发送到服务端,服务端只能一个一个处理,所以大量并发请求就不适合用 Messenger ,而且 Messenger 只适合传递消息,不能跨进程调用服务端的方法。AIDL 可以解决并发和跨进程调用方法的问题,要知道 Messenger 本质上也是 AIDL ,只不过系统做了封装方便上层的调用而已。
五、使用 ContentProvider
用于不同应用间数据共享,和 Messenger 底层实现同样是 Binder 和 AIDL,系统做了封装,使用简单。 系统预置了许多 ContentProvider ,如通讯录、日程表,需要跨进程访问。 使用方法:继承 ContentProvider 类实现 6 个抽象方法,这六个方法均运行在 ContentProvider 进程中,除 onCreate 运行在主线程里,其他五个方法均由外界回调运行在 Binder 线程池中。
ContentProvider 的底层数据,可以是 SQLite 数据库,可以是文件,也可以是内存中的数据。
六、使用 Socket
Socket起源于 Unix,而 Unix 基本哲学之一就是“一切皆文件”,都可以用“打开 open –读写 write/read –关闭 close ”模式来操作。Socket 就是该模式的一个实现,网络的 Socket 数据传输是一种特殊的 I/O,Socket 也是一种文件描述符。Socket 也具有一个类似于打开文件的函数调用: Socket(),该函数返回一个整型的Socket 描述符,随后的连接建立、数据传输等操作都是通过该 Socket 实现的。
常用的 Socket 类型有两种:流式 Socket(SOCK_STREAM)和数据报式 Socket(SOCK_DGRAM)。流式是一种面向连接的 Socket,针对于面向连接的 TCP 服务应用;数据报式 Socket 是一种无连接的 Socket ,对应于无连接的 UDP 服务应用。
Srvice:
Service是四大组件之一,它可以在后台执行长时间运行操作而没有用户界面的应用组件
两种启动方式和特点:
startService特点:
1.使用这种start方式启动的Service的生命周期如下:onCreate()--->onStartCommand()---> onDestroy()
2.如果服务已经开启,不会重复的执行onCreate(), 而是会调用onStart()和onStartCommand()
3.一旦服务开启跟调用者(开启者)就没有任何关系了。
4.开启者退出了,开启者挂了,服务还在后台长期的运行。
5.开启者不能调用服务里面的方法。
bindService特点:
1.使用这种start方式启动的Service的生命周期如下:onCreate() --->onBind()--->onUnbind()--->onDestroy()
2.绑定服务不会调用onStart()或者onStartCommand()方法
3.bind的方式开启服务,绑定服务。调用者调用unbindService解除绑定,服务也会跟着销毁。
4.绑定者可以调用服务里面的方法
IntentService是什么。。通常用来离线下载
重点(本质上也是为了节省资源)
IntentService是继承自Service并处理异步请求的一个类,其内部采用HandlerThread和Handler实现的,在IntentService内有一个工作线程来处理耗时操作,其优先级比普通Service高
当任务完成后,IntentService会自动停止,而不需要手动调用stopSelf()
可以多次启动IntentService,每个耗时操作都会以工作队列的方式在IntentService中onHandlerIntent()回调方法中执行,并且每次只会执行一个工作线程

  1. IntentService使用方法
    1.创建Service继承自IntentService
    2.覆写构造方法和onHandlerIntent()方法
    3.在onHandlerIntent()中执行耗时操作
    3.IntentService工作原理
    1.IntentService继承自Service,内部有一个HandlerThread对象
    2.在onCreate的时候会创建一个HandlerThread对象,并启动线程
    3.紧接着创建ServiceHandler对象,ServiceHandler继承自Handler,用来处理消息。ServiceHandler将获取HandlerThread的Looper就可以开始正常工作了
    Service保活
    1 onStartCommand方法,返回START_STICKY
    在运行onStartCommand后service进程被杀死后,那将保留在开始状态,但不会保留那些传入的intent。不久后service就会再次尝试重新创建,因为保留在开始状态,在创建 service后将保证调用onstartCommand。如果没有传递任何开始命令给service,那获取到的Intent为null。手动返回START_STICKY,亲测当service因内存不足被kill,当内存又有的时候,service又被重新创建,但是不能保证任何情况下都被重建,比如进程被干掉了….
    2 提升Service优先级
    在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = “1000”这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。
    3 提升Service进程优先级
    Android中将进程分成6个等级,由高到低分别是:前台进程、可视进程、次要服务进程、后台进程、内容供应节点以及空进程。当系统进程空间紧张时,会按照优先级自动进行进程回收。可以使用startForeground()将服务设置为前台进程
    4 在onDestory中重启Service
    直接在onDestroy()里startService或service +broadcast 方式,就是当service走ondestory的时候,发送一个自定义的广播,当收到广播的时候,重新启动service。
    5 监听系统广播判断Service状态
    通过系统的一些广播,比如:手机重启、界面唤醒、应用状态改变等等监听并捕获到,然后判断我们的Service是否还存活,但要记得加权限。
    9.Glide
    glide默认使用httpurlcolltion加载图片,还可以修改为okhttp3或Volley来进行加载图片
    1、glide怎么获取图片宽高,获取屏幕宽高的几种方案:
    1.可以直接获取到尺寸,当xml文件里写固定值,可以直接获取。还有就是布局已经绘制完成,通过view可以获取,如果是wrap_content就通过 override() 指定其他固定尺寸,并使用屏幕尺寸为该请求尺寸
    2.布局没有绘制完成,通过调用onPreDrawListener监听实现获取宽高
    2.绑定生命周期分为五种类型1、content2、Activity3、FragmentActivity4、Fragment5、View
    原理:通过获取 Activity 的FragmentManager,绑定一个空RequestManagerFragment,用来绑定空的Fragment然后在RequestManagerFragment 中初始化RequestManager,并注册至LifecycleListener
    当Activity 触发生命周期时,回调 Fragment,并传至LifecycleListener,LifecycleListener会回调所有向其注册过的RequestManager
    Glide和Picasso比较:
    1.Picasso和Glide的withi后面的参数不同
    Picasso.with(这里只能传入上下文) .
    Glide.with,后面可以传入上下文,activity实例,FragmentActivity实例,Fragement.传入的对象要比前者多.
    2.加载后图片质量不同
    Picasso采用的ARGB-8888,
    Glide采用的是RGB-565 相对而言,
    Picasso加载的是全图,图片质量和清晰对要比Glide的要高
    但是,因为加载的采样率过高,导致,出现OOM异常的概率要比Glide要大很多.
    3.加载Gif图片(备注:Gif图片消耗太对内存,尽量谨慎使用):
    Picasso不能加载git图片
    Glide可以加载缓存图片
    4.缓存策略和加载速度.
    Picasso缓存的是全尺寸
    Glide的缓存的跟ImageView的尺寸相同.
    讲ImageView调整为不同的大小,不管大小如何设置,
    Glide则不同,他会为每种大小不一致的ImageView都缓存一次.Glide的这个特点,让加载显得特别的快,
    Picasso只缓存一个全尺寸的,Picasso则因为需要在显示之前重新调整大小而导致一些延迟,(即便是添加了noFade)
    5.总结:
    Glide比Picasso加载速度要快,其实他是在Picasso的基础上进行了第二次封装,
    Glide比Picasso需要更多的空间来缓存;
    Glide加载图像以及磁盘缓存的方式,都优于Picasso,且Glide更有利于减少OutOfMemoryError的发生;
    Gif动画,是Glide的杀手锏.
    3.Glide线程池
    1.磁盘缓存线程池
    2.核心处理线程池
    3.动画线程池
    10、MVC,MVP,MVVM 的区别
    MVC:
    moduel对数据进行处理,将数据给view展示
    View用户界面,给controller传送要显示的页面
    Controller:控制器,对逻辑做处理,让moduel改变状态
    特点:因为view可以访问moduel,所以要做一些逻辑,导致更改view比较困难,
    Controller代码过多臃肿,职责不清晰,测试不方便(必须手动点击,使用自动化的测试工具)所有的通信都是单向的
    MVP:
    View :是指显示数据并且和用户交互的层。
    Model :是数据源层。用来保存数据,以及请求数据等。
    Presenter:是从Model中获取数据并提供给View的层,Presenter还负责处理所有的逻辑
    优点:测试方便,m与v完全脱离,各部分通信都是双向的,降低了耦合性,
    缺点,接口过于频繁,维护不方便
    MVVM:
    对MVP的改进
    1将Presenter改名为ViewModuel
    并通过双向的数据绑定来实现视图和数据的交互。也就是说只需要将数据和视图绑定一次之后,那么之后当数据发生改变时就会自动的在UI上刷新而不需要我们自己进行手动刷新。在MVVM中,他尽可能的会简化数据流的走向,使其变得更加简洁明了。
    优点:可以使得数据流的走向更加的清晰明了,同时也简化了开发,数据和视图只需要进行一次绑定即可。
    11、AsyncTask
    基本概念及原理:
    异步任务,它本质上就是一个封装了线程池和Handler的异步框架。可以实现UI线程和后台线程进行通讯,后台线程执行异步任务,并把结果返回给UI线程。
    利用AsyncTask,可以方便的实现异步任务处理,可以在子线程更新UI,封装简化了异步操作,使用线程,线程池处理异步任务,AsyncTask执行任务时,内部会创建一个进程作用域的线程池来管理要运行的任务,也就是说当你调用了AsyncTa sk.execute()后,AsyncTask会把任务交给线程池,由线程池来管理创建Thread和运行Thread。
    为什么要做异步任务:
    因为android中只有主线程才可以对ui进行操作,但是不可以做耗时操作,如果主线程做耗时操作,可能就会导致ANR,将耗时操作放到子线程去做,此时就可以用AsyncTask,既避免了Android中单线程,又避免了ANR.
    使用方法:
    构建AsyncTask子类的泛型参数:
    Params:启动任务时输入的参数类型.
    Progress:后台任务执行中返回进度值的类型.
    Result:后台任务执行完成后返回结果的类型.
    构建AsyncTask子类的回调方法:
    doInBackground:必须重写,异步执行后台线程要完成的任务,耗时操作将在此方法中完成.
    onPreExecute:执行后台耗时操作前被调用,通常用于进行初始化操作.
    onPostExecute:当doInBackground方法完成后,系统将自动调用此方法,并将doInBackground方法返回的值传入此方法.通过此方法进行UI的更新.
    onProgressUpdate:当在doInBackground方法中调用publishProgress方法更新任务执行进度后,将调用此方法.通过此方法我们可以知晓任务的完成进度.
    使用AsyncTask的注意事项
    ① 必须在UI线程中创建AsyncTask的实例.
    ② 只能在UI线程中调用AsyncTask的execute方法.
    ③ AsyncTask被重写的四个方法是系统自动调用的,不应手动调用.
    ④ 每个AsyncTask只能被执行(execute方法)一次,多次执行将会引发异常.
    ⑤ AsyncTask的四个方法,只有doInBackground方法是运行在其他线程中,其他三个方法都运行在UI线程中,也就说其他三个方法都可以进行UI的更新操作.
    12、Android 6.0、7.0、8.0、9.0各个版本的版本特性主要讲解关于开发方面
    6.0
    运行时权限,首次使用要申请获得权限
    低电耗模式和应用待机模式,一段时间不用,会处于休眠状态或待机模式
    取消支持http客户端的支持,用HttpURLConnection,减少透明压缩和响应缓存等
    文本操作,选中之后可以对其操作
    WLAN和网络连接变更
    对相机的服务有些改变
    USB连接,仅充电模式,要做其他操作,要获取权限
    7.0
    多窗口支持,分屏功能
    增强通知功能,模板更新,消息传递样式自定义,捆绑通知,快速通知等,
    配置文件指导的JIT/AOT编译,对代码进行分析,让它可以在应用运行时持续提升 Android 应用的性能,提高应用安装和系统更新的速度,
    低电耗模式,即设备处于空闲状态时,通过推迟应用的 CPU 和网络活动以实现省电目的的系统模式
    流量节省模式,
    夜间模式
    多语言区域支持,更多语言
    秘钥认证
    VR支持,可以让用户打造高质量移动VR体验
    新增FrameMetricsListener API 允许应用检测他的UI渲染性能
    8.0
    自动填充框架
    Android 8.0 通过引入自动填充框架,简化了登录和信用卡表单之类表单的填写工作。在用户选择接受自动填充之后,新老应用都可使用自动填充框架。
    画中画模式
    Android 8.0 允许以画中画 (PIP) 模式启动操作组件。PIP 是一种特殊的多窗口模式,最常用于视频播放。而 Android 8.0 则让该功能可进一步用于其他 Android 设备。
    字体
    1提供从程序应用请求字体,不不需要让Apk去下载字体,减少APK大小
    2 XML 中的字体,允许您使用字体作为资源。
    自动调整Textview的大小
    根据 TextView 的大小自动设置文本展开或收缩的大小。更容易屏幕适配
    可以自适应应用图标
    提高WebView API增强应用稳定性和安全性
    统一的布局外边距和内边距
    指针捕获,例如游戏,远程桌面都收益与指针控制
    新的 StrictMode 检测程序,帮助识别应用可能出现的错误
    自定义数据存储
    WLAN 感知
    在具有相应 WLAN 感知硬件的设备上,应用和附近设备可以通过 WLAN 进行搜索和通信,无需依赖互联网接入点
    无障碍功能
    支持开发者使用以下无障碍功能创建自己的无障碍服务。
    新增与电话相关的权限

9.0:
1.所有应用都使用HTTPS,对所有应用信息安全
2.多摄像头支持,您可以通过两个或更多物理摄像头来同时访问多个视频流。
3.显示屏缺口支持
Android 9 支持最新的全面屏,其中包含为摄像头和扬声器预留空间的屏幕缺口。 通过 DisplayCutout 类可确定非功能区域的位置和形状,这些区域不应显示内容。 要确定这些屏幕缺口区域是否存在及其位置,请使用 getDisplayCutout() 函数。
4.动画,用来绘制GIF和WebP动画图像
5.HDR VP9视频,HEIF图像压缩和MediaApi
6.对流量费用敏感,如果网络阻塞时,会延迟较大的网络请求
13、EventBus
EventBus简化了Android组件间的通信。有效的分离事件发送方和接收方(也就是解耦的意思),能避免复杂和容易出错的依赖性和生命周期问题 。
三要素:
Event 事件。它可以是任意类型
Subscriber 事件订阅者。3.0之后需要加上注解@subscribe(),并且指定线程模型,默认是POSTING。3.0以前必须定义onEvent固定的那几个方法
Publisher 事件的发布者。可以在任意线程发布事件,使用EventBus.getDefault()就可以得到一个EventBus对象,然后再调用post(Object)方法即可。

四种线程模式:
 POSTING (默认) 事件处理的线程跟发布事件的线程在同一个线程。
 MAIN 表示事件处理函数的线程在主线程(UI)线程,因此在这里不能进行耗时操作。
 BACKGROUND 表示事件处理函数的线程在后台线程,因此不能进行UI操作。
 ASYNC 表示无论事件发布的线程是哪一个,事件处理函数始终会新建一个子线程运行,同样不能进行UI操作。

粘性事件:黏性事件,就是指发送了该事件之后再订阅者依然能够接收到的事件。使用黏性事件的时候有两个地方需要做些修改。一个是订阅事件的地方,一个是发布事件的地方,即调用EventBus的postSticky方法来发布事件:
优先级:
priority它用来指定订阅方法的优先级,是一个整数类型的值,默认是0,值越大表示优先级越大。在某个事件被发布出来的时候,优先级较高的订阅方法会首先接受到事件。
14、GreenDao
一对一
@ToOne
就是一个主键对应一个值
一对多
@ToMany(referencedJoinProperty = "parentId")类似于约束外键。
比如一个老师有多个学生,要有一个主键,一个外键,根据外键去查看另外一张表,反过来就是多对一
多对多
@JoinEntity(entity = TeacherJoinStudentBean.class,sourceProperty = "tId",targetProperty ="sId")
比如多个老师有多个学生,这种情况需要另外一张表,用来存放老师和学生的id和自己的主键,直接查看这张表就可以。

实体注解:
@Entity 用于标识这是一个需要Greendao帮我们生成代码的bean
@Id 标明主键,可以设置为是否自增,如果原来字段里就有id,那么就不需要设置 Long类型的Id,将Id改为不可自增就可以
@Transient表示这个字段不会再数据库里面插入
@Index 通过这个字段建立索引
@Convert对不是基本类型进行转换

关键的几个类:
DaoMaster:用于创建数据库以及获取DaoSession
DaoSession:用于获取各个表对应的Dao对象
各个表对应的Dao:提供了对表进行增删改查的方法
对于每一个实体类,greenDao生成一个DAO,持有很多持久性的方法,例如 count, loadAll以及insertInTx。

greendao加密:
添加依赖,加密的方法是用了getEncryptedWritableDb,在得到DB并getSession时需要输入密钥。
在取数据时使用的session必须也是使用相同的密钥new出来的,否则只能看到空数据。并且把加密后的本地文件拿出来,也是看不到内容的。

GreenDao升级:greendao不支持数据迁移
第一步:新建一个类,继承DaoMaster.DevOpenHelper,重写onUpgrade(Database db, int oldVersion, int newVersion)方法,在该方法中使用MigrationHelper进行数据库升级以及数据迁移。
然后使用MyOpenHelper替代DaoMaster.DevOpenHelper来进行创建数据库等操作
第二步:新增或者修改字段,新增的字段都会被赋予空值,将原来的getset方法删除,重新build,最后修改版本号
29、热修复
版本发布之后发现严重BUG,需要紧急动态修复
小功能即时上线、下线,比如节日活动

而热修复的开发流程显得更加灵活,优势很多:
无需重新发版,实时高效热修复
用户无感知修复(甚至无需重启应用),无需下载新的应用,代价小
修复成功率高,把损失降到最低

而热修复的开发流程显得更加灵活,优势很多:
无需重新发版,实时高效热修复
用户无感知修复(甚至无需重启应用),无需下载新的应用,代价小
修复成功率高,把损失降到最低

主流框架:
腾讯,生成dex文件,因为dex文件是以数组的形式出错,他通过改变dex文件的顺序,实现热更新
2.阿里云,添加so库,利用C语言进行一些算法,改变执行顺序

15、视频上传,下载,缓存,压缩
视频的压缩上传采用集成七牛短视频,
16、描述Java中断点续传和多线程断点续传的详细流程
多线程断点续传流程:
1、 HttpUrlConnection去请求服务器 获得文件的长度con.getContentLength()
2、 创建一个空的RandomAcessFile来接收,并且指定刚刚获取的长度setLength
3、开启N个线程 计算每个线程需要下载的长度
4、获取之前先去看看下载的进度保存文件是否存在如果存在就从文件里获取已经下载的进度
5、开始文件下载
6、临时文件的删除 资源的关闭
单线程断点续传流程:
1)通过远程url和本地保存目录开始运行
2)通过远程url获取文件大小
3)通过本地临时文件info和远程文件比较大小判断是否有本地文件下载完毕
4)未下载完成的开始断点下载
5)完成后删除临时文件
30、js与Android交互
Android开发过程中,我们或多或少都会用到webview,使用webview来展示一些经常变动的界面更加方便简单,
也已于维护。另一方面hybrid App开发现在用的也越来越多了。其中native和h5之间的交互更是必不可少的。
常用的有web.load Url(“”);
Webview可以对html页面通过指定的几个方法做本地缓存,减少用户流量,
要注意的问题:
在WebView加载页面的时候,会自动开启线程去加载,如果不很好的关闭这些线程,就会导致电量消耗加大,可以采用暴力的方法,直接在onDestroy方法中System.exit(0)结束当前正在运行中的java虚拟机

17、单例模式、工厂模式、观察者、适配器;
Builder模式
意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
何时使用:一些基本部件不会变,而其组合经常变化的时候。
关键代码:建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。

观察者模式
发布订阅模式,发布者发布信息,订阅者获取信息,订阅了就能收到信息,没订阅就收不到信息
意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。
如何解决:使用面向对象技术,可以将这种依赖关系弱化。
工厂模式
意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
主要解决:主要解决接口选择的问题。
何时使用:我们明确地计划不同条件下创建不同实例时。
关键代码:创建过程在其子类执行。

19.Activity一共有以下四种启动模式:
1.Standard(默认的启动模式):每次启动一个Activity都会创建一个新的实例入栈,不管这个实例是否存在。
2.SingleTop(栈顶复用模式):当一个singleTop模式的Activity已经位于任务栈的栈顶,再去启动它时,不会再创建新的实例,如果不位于栈顶,就会创建新的实例
3.SingTask(有弹栈的效果):在同一个Task中只有一个实例,如果在栈顶,系统不会创建新的Activity实例,如果不在栈顶,系统就把这个Activity移到栈顶,把他上面的Activity移出去

  1. SingleInstance(单例模式)SingTask是任务栈内单例,SingleInstance则是Activity单例,会创建一个新的任务栈,这个任务栈只有一个Activity
    20、简述什么是泛型,泛型如何使用和项目中如何使用
    泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
    泛型如何使用
    泛型可以用到容器,方法,接口,内部类,抽象类
    泛型的好处:
    增强程序的可读性和稳点性,在实际使用之前类型就已经确定了,不需要强制类型转换
    21.Java中线程的实现的几种方式、和常用的方法、以及多线程安全问题
    线程的三种方式:
    1)继承Thread类创建线程
    2)实现Runnable接口创建线程
    3)使用Callable和Future创建线程
    常用方法:
    start() :启动线程,进入就绪状态
    run():都用来定义线程对象被调度之后所执行的操作,都是系统自动调用而用户程序不得引用的方法。
    sleep(int millsecond): 优先级高的线程可以在它的run()方法中调用sleep方法来使自己休眠一段时间。
    wait:调用该方法的线程进入等待状态,需要注意的是调用wait()方法后,会释放对象的锁。
    多线程安全问题:
    什么情况下会产生线程安全问题?
    1,多个线程在操作共享的数据。 ​ 2,操作共享数据的线程代码有多条。
    解决思路:
    将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程不可以参与运算。
    当前线程把这些代码都执行完毕后,其他线程才可以参与运算。
    22.Java中线程池的实现的几种方式和各自特点与使用场景
    实现方式
    线程池的实现方式是通过Executors类创建几种不同类型的线程池
    四种线程池:
    newCacheThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
    newFixedpool创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待 newScheduledpool创建一个定长线程池,支持定时和周期性任务执行 ​ newSingeThreadExecutor创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO,LIFO,优先级)执行
    使用场景:
    单个任务处理时间短 ​ 将需处理的任务数量大
    23、Java中数组、集合、链 表、队列的数据结构和优缺点和他们之间的区别
    数组:
    长度固定 ​ 可以存储基本类型,也可以存储引用类型,存储元素类型一致 ​ 数组可以在内存中连续存储多个元素的构造,在内存中的分配也是连续的
    优点:有下标,查询方便,增删快
    缺点: 数组的大小固定后就不能扩容了 ​ 数组只能存储一种类型的数据 ​ 添加,删除的操作慢,因为要移动其他的元素
    集合:
    长度可变 ​ 只可以存储引用类型 ​ 可以存储多种类型
    List有序可重复 ​
    ArrayList: 底层:数组(存储空间连续) 增删慢,查询快 线程不安全,(不同步) 效率高 ​
    Vector: 底层:数组(存储空间连续) 增删慢,查询快 线程安全,(同步) 效率低 ​
    LinkedList: 底层:链表(两部分:值域,地址域) 增删快,查询慢 线程不安全,效率高
    Set无序不可重复 ​
    HashSet 底层:哈希表(hashcode,equals) 线程不安全,效率高 ​ LinkedHashSet 底层: 链表(保证有序) 哈希表(hashcode,equals) ​ TreeSet 底层:红黑树 (有序:1.自然排序 2.比较器排序)
    ​ Hashtable:现在被HashSet取代,特点,不能存null 线程安全,效率低
    Map 双列集合 只针对键有效 Key,Value ​
    HashMap 底层:哈希表(hashcode,equals) 线程不安全,效率高(针对key) ​
    LinkedHashMap 底层: 链表(保证有序) 哈希表(hashcode,equals) ​ TreeMap 底层:红黑树 (有序:1.自然排序 2.比较器排序)
    链表:
    通过一个链子把多个结点(元素)连接起来,由数据和地址组成的一个元素, ​ 节点本身必须有一个地址值(就是下一个元素的地址值)
    优点:
    查找不方便,增删快
    队列:
    是一种先进先出的数据构造,也是运算受限制的线性表,只可以在对头删除元素,在队尾插入元素 ​ 线性表是同一类型数据的一个有限序列 ​ 元素之间的先后排列次序蕴涵着其线性关系。
    24.简述Java中注解,并自定义注解。说一下注解处理机制和使用场景
    什么是注解?
    Java注解也叫元数据,是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会影响代码的实际逻辑,仅仅起到辅助性的作用。
    它主要的作用有以下四方面:
    1,生成文档,通过代码里标识的元数据生成javadoc文档。
    2,编译检查,让编译器在编译期间进行检查验证。
    3,编译时动态处理,例如动态生成代码。
    4,运行时动态处理,例如使用反射注入实例。
    自定义注解:
    自定义注解类编写的一些规则:
  2. 参数成员只能用public或default这两个访问权修饰
  3. 参数成员只能用八种基本数据类型和String、Enum、Class、annotations等数据类型,以及这一些类型的数组.
  4. 要获取类方法和字段的注解信息,必须通过Java的反射技术来获取
    25、描述Socket、Tcp和Udp,http、https区别,和使用方式和原理
    socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),
    通过Socket,我们才能使用TCP/IP协议。
    TCP与UDP区别总结:
    1、TCP面向连接
    UDP是无连接的,即发送数据之前不需要建立连接
    2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不 重复,且按序到达;
    3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;
    UDP是面向报文的
    UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低
    4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
    5、TCP首部开销20字节;UDP的首部开销小,只有8个字节
    6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
    HTTP与HTTPS的区别
    1、HTTPS协议需要到CA申请证书,一般免费证书很少,需要交费。
    2、HTTP是超文本传输协议信息是明文传输,HTTPS则是具有安全性的ssl加密传输协议。
    3、HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
    4、HTTP的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比HTTP协议安全。
    26、描述java中的垃圾回收机制以及内部算法
    垃圾回收机制是Java提供的自动释放内存空间的机制。 垃圾回收器(Garbage Collection,GC)是JVM自带的一个线程,用于回收没有被引用的对象,垃圾回收重点关注的是堆和方法区部分的内存。
    java中常用的垃圾收集算法
    (1).标记-清除算法:
    最基础的垃圾收集算法,算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成之后统一回收掉所有被标记的对象。
    (2).复制算法:
    将可用内存按容量分成大小相等的两块,每次只使用其中一块,当这块内存使用完了,就将还存活的对象复制到另一块内存上去,然后把使用过的内存空间一次清理掉。
    复制算法的缺点显而易见,可使用的内存降为原来一半。
    (3).标记-整理算法:
    标记-整理算法在标记-清除算法基础上做了改进,标记阶段是相同的标记出所有需要回收的对象,在标记完成之后不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,在移动过程中清理掉可回收的对象,这个过程叫做整理。
    (4).分代收集算法:
    根据内存中对象的存活周期不同,将内存划分为几块,java的虚拟机中一般把内存划分为新生代和年老代,当新创建对象时一般在新生代中分配内存空间,当新生代垃圾收集器回收几次之后仍然存活的对象会被移动到年老代内存中,当大对象在新生代中无法找到足够的连续内存时也直接在年老代中创建。
    现在的Java虚拟机就联合使用了分代复制、标记-清除和标记-整理算法,

27、简述什么是ANR、如何产生和解决
ANR定义:应用程序无响应,会显示一个对话框,这个对话框称作应用程序无响应(ANR:Application Not Responding)对话框。用户可以选择“等待”而让程序继续运行,也可以选择“强制关闭”。
ANR产生原因
在多线程中做了非常耗时的操作,比如说是下载,io异常等
潜在的耗时操作,例如网络或数据库操作,或者高耗时的计算如改变位图尺寸,应该在子线程里或者通过异步请求的方式来完成。
如何解决ANR
不在主线程做耗时操作,放在子线程中来实现,采用Handler+mesage的方式,或者是有时候需要做一些和网络相互交互的耗时操作就采用asyntask异步任务的方式等,在主线程中更新UI。
28、Android页面恢复
32、图片的三级缓存
当App需要加载某一张图片时,先去手机内存中去找该图片,如果有,那么直接显示,如果无,则去手机sd卡或者手机外部存储中找该图片,如果有,那么直接显示,如果无,那么此时才去网络下载该图片。这种机制常称为三级缓存策略。

内存缓存以花费宝贵的程序内存为前提来快速访问位图。
LruCache类(在API Level 4的Support Library中也可以找到)特别适合用来缓存Bitmaps,
它使用一个强引用(strong referenced)的LinkedHashMap保存最近引用的对象,并且在缓存超出设置大小的时候剔除(evict)最近最少使用到的对象。

  1. 即时通讯
    主流的框架就是环信。
    环信:流程:
    在线状态:客户端A发送消息到环信服务器,环信服务器推送消息到客户端B。
    离线状态:客户端A发送消息到环信服务器,环信服务器检测到客户端B不在线,会添加到离线缓存中,当客户端B登录后服务器会把离线消息推送给客户端B。
    聊天记录保存
    客户端A发送消息到环信服务器的同时,SDK 会保存这条消息到本地数据库(SDK 内部创建数据库,不允许直接操作),环信服务器在推送消息到客户端B的同时也会在服务器记录下来(消息历史记录免费存储3天),客户端B收到消息后,SDK 会将这条消息存储到本地数据库。
    自动连接:
    如果网络不通过,用户应该自动连接到服务器,以及时接收消息
    此功能无需程序员自己做,环信框架已实现,环信SDK会调用自动连接的代理方法来通知应用程序
    MChatManagerBuddyDelegate:
    上面的协议的实现了对用户的基本操作,如
    (1)添加好友
    (2)从本地获取好友列表
    (3)从服务器获取最新好友列表
    (4)接收好友添加请求
    (5)删除好友
    (6)被好友从名单上删除
    是否使用过环信,简单的说下环信的实现原理:
    环信是一个即时通信的服务提供商
    环信使用的是XMPP协议,它是再XMPP的基础上进行二次开发,对服务器Openfire和客户端进行功能模型的添加和客户端SDK的封装,环信的本质还是使用XMPP,基本于Socket的网络通信
    环信内部实现了数据缓存,会把聊天记录添加到数据库,把附件(如音频文件,图片文件)下载到本地,使程序员更多时间是花到用户即时体验上
    环信内部已经实现了视频,音频,图片,其它附件发送功能
    环信使用公司可以节约时间成本
    不需要公司内部搭建服务器
    客户端的开发,使用环信SDK比使用XMPPFramework更简洁方便
    35.支付流程
    支付宝支付流程:
    1.app携带支付信息调用支付接口请求支付宝客户端调起支付界面;
    2.用户操作,输入密码支付,支付成功;直接返回取消支付;出现错误,支付失败;进入支付界面,但输入密码支付,支付待确认;
    3.支付宝客户端将支付结果告诉app客户端,商户服务器通知app服务器支付结果;
    4.app客户端处理支付结果;
    5.app服务器处理支付结果。
    微信支付:
    流程解释:
  2. 客户端请求订单
    2.认证商户,获取access_token
    3、组装生成预定单所需参数并签名
    4、调用微信统一下单接口并传递参数,得到预订单号
    5、对得到的预定单参数再次签名
    6、调起微信支付并验证参数有效性
    7、验证通过,提示用户输入支付密码
    8、提交支付,异步返回支付结果和订单详情
    9、客户端同步跳转页面。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,504评论 4 365
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,898评论 1 300
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,218评论 0 248
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,322评论 0 214
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,693评论 3 290
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,812评论 1 223
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,010评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,747评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,476评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,700评论 2 251
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,190评论 1 262
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,541评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,206评论 3 240
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,129评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,903评论 0 199
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,894评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,748评论 2 274

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,039评论 1 32
  • 所有知识点已整理成app app下载地址 J2EE 部分: 1.Switch能否用string做参数? 在 Jav...
    侯蛋蛋_阅读 2,358评论 1 4
  • 1.设计模式是什么? 你知道哪些设计模式,并简要叙述?设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型...
    龍飝阅读 2,064评论 0 12
  • To 毒舌姐: 都说“女人心,海底针”,但我怎么觉得男人心思也那么难猜呢? 家里准备换个新鞋柜,我们就为买什么风格...
    毒舌姐姐阅读 454评论 0 3
  • 当你说钱时,一些朋友就走远了。当你缺钱时,真正的朋友都来了。 2018下半年,再次来故事群。讲我自己的故事给你们听...
    虚度老太婆阅读 484评论 0 0