(a)String:字符串变量,不适合经常需要改变值的情况下,每次改变相当于产生了一个新的对象。
(b)StringBuffer:属于(线程安全的)字符串变量,带有缓冲区。
(c)StringBuilder:属于(线程不安全的)字符串变量,在单线程下,效率略高于StringBuffer。
三者在执行速度上:StringBuilder > StringBuffer > String (由于String是常量,不可改变,拼接时会重新创建新的对象)
其中,基本数据类型的(==),比较的是值相等;
而类(==),比较的是内存地址,即是否是同一个对象,若在不覆盖equals的情况下,同比较内存地址,原实现也为 (==),若String等重写了equals方法。
hashCode()是Object类的一个方法。返回一个离散的int型整数。在集合类操作中使用,为了提高查询速度。(HashMap, HashSet等比较是否为同一个)
(a)若两个对象相等(equals),Java运行时环境会认为他们的hashCode()一定相等。
(b)若两个对象不相等(equals),它们的hashCode()有可能相等。
(c)若两个对象hashCode()相等,它们不一定equals。
(d)若两个对象hashCode()不相等,它们一定不equals。
int 是基本数据类型,integer 对象是int的封装类。
(a)final:修饰类、成员变量和成员方法,修饰的类不可被继承(如String),成员变量的值不可变,成员方法不可被重写。
(b)finally:异常处理块,与try...catch...共同使用,确保无论是否出现异常都能被执行到。
(c)finalize:类的方法,垃圾回收之前会调用此方法,子类可重写finalize()方法实现对资源的回收。
进程是cpu资源分配的最小单位;
线程是cpu调度的最小单位。
进程之间不能共享cpu资源,而线程可共享其所在进程的地址空间和其他资源。
一个进程可拥有多个线程,进程可启动进程,也可启动线程。
一个线程只属于一个进程,线程可直接使用同进程的资源,线程是依赖于进程而存活的。
(a)Serializable:Java提供的系列化接口,可在硬盘上读写,在读写的过程中会生成大量的临时变量,内部执行大量的I/O流操作,从而导致效率低下。
(b)Parcelable:Android提供的系列化接口,效率高,但是使用相对繁琐,直接在内存中读写,对象不保存在硬盘中。
(可在AS工具中,安装Android Parcelable code generator插件,可快速的一键生成)
(a)List:数据是以线性方式存储,集合中可存放重复的数据对象。
ArrayList:表示长度可改变得数组,可对元素进行随机访问,但往其中插入和删除元素的速度慢。
LinkedList:在实现中采用链表的数据结构,插入和删除元素速度快,但访问速度慢。
(b)Set:集合中的对象不按照特定的方式进行排序,而且没有重复的对象。Set接口实现了2个类:
HashSet:按照哈希算法来存取集合中的对象,存取速度比较快。
TreeSet:实现了SortedSet接口,能够对集合中的对象进行排序。
(c)Map:键值对对象映射的集合,每一个元素都包含一对键值对对象。它没有继承Collection接口,从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。
HashMap:Map基于散列表的实现。插入和查询“键值对”的开销是固定的。可以通过构造器设置容量capacity和负载因 子load factor,以调整容器的性能。
LinkedHashMap:类似于HashMap,但是迭代遍历它时,取得“键值对”的顺序是其插入次序,或者是最近最少使用(LRU)的次序。只比HashMap慢一点。而在迭代访问时发而更快,因为它使用链表维护内部次序。
TreeMap:基于红黑树数据结构的实现。特点在于,得到的结果是经过排序的。
WeakHashMap:弱键(weak key)Map,Map中使用的对象也被允许释放,若没有map之外的引用指向某个“键”,则此“键”可以被垃圾收集器回收。
(a)存储方式不同
(b)添加数据时扩容时的处理不一样
HashMap进行了new操作,重新创建对象,所以开销很大。而ArrayMap用的是copy数据,所以效率相对要高。
(c)ArrayMap提供了数组收缩的功能,在clear或remove后,会重新收缩数组
(d)ArrayMap采用二分法查找
(a)通过继承Thread类
(b)实现Runable接口
(c)使用线程池
进程包含线程,一个进程可拥有多个线程,每条线程并行执行不同的任务。不同的进程使用不同的内存空间,而所有的线程共享一片相同的内存空间。每个线程都拥有单独的栈内存用来存储本地数据。
start()方法被用来开启新创建的线程,而且start()内部调用了run()方法,和直接调用run()方法的效果不一样。
当调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会开启新线程。
(a)添加synchronized关键字
(b)Object方法中的wait(),notify()
(c)ThreadLocal机制来实现的
(a)synchronized关键字修改的方法
(b)synchronized关键字修饰的语句块
(c)使用特殊域变量(volatile)实现线程同步
线程是CPU调度的最小单位。在Android中,主线程是不能够做耗时操作的,子线程是不能够更新UI的。而线程间通信的方式有很多,比如广播,Eventbus,接口回掉,在Android中主要是使用handler。handler通过调用sendMessage方法,将保存消息的Message发送到Messagequeue中,而looper对象不断的调用loop方法,从messagequeue中取出message,交给handler处理,从而完成线程间通信。
(a)FixedThreadPool
此线程池是通过Executors的new FixedThreadPool方法来创建。它的特点是该线程池中的线程数量是固定的。即使线程处于闲置的状态,它们也不会被回收,除非线程池被关闭。当所有的线程都处于活跃状态的时候,新任务就处于队列中等待线程来处理。注意,FixedThreadPool只有核心线程,没有非核心线程。
(b)CachedThreadPool
此线程池是通过Executors的newCachedThreadPool进行创建的。它是一种线程数目不固定的线程池,它没有核心线程,只有非核心线程,当线程池中的线程都处于活跃状态,就会创建新的线程来处理新的任务。否则就会利用闲置的线程来处理新的任务。线程池中的线程都有超时机制,这个超时机制时长是60s,超过这个时间,闲置的线程就会被回收。这种线程池适合处理大量并且耗时较少的任务。这里得说一下,CachedThreadPool的任务队列,基本都是空的。
(c)ScheduledThreadPool
此线程池是通过Executors的newScheduledThreadPool进行创建的,它的核心线程是固定的,但是非核心线程数是不固定的,并且当非核心线程一处于空闲状态,就立即被回收。这种线程适合执行定时任务和具有固定周期的重复任务。
(d)SingleThreadExecutor
此线程池是通过Executors的newSingleThreadExecutor方法来创建的,这类线程池中只有一个核心线程,也没有非核心线程,这就确保了所有任务能够在同一个线程并且按照顺序来执行,这样就不需要考虑线程同步的问题。
AsyncTask是Android提供的一种轻量级的异步任务类,可在线程池中执行后台任务,然后把执行的进度和最终的结果传递给主线程更新UI。实际上,AsyncTask内部是封装了Thread和Handler。虽然AsyncTask很方便的执行后台任务,以及在主线程上更新UI,但是,AsyncTask并不合适进行特别耗时的后台操作,对于特别耗时的任务,个人建议使用线程池。
AsyncTask提供有4个核心方法:
(a)onPreExecute():该方法在主线程中执行,在执行异步任务之前会被调用,一般用于一些准备工作。
(b)doInBackground(String... params):该方法在线程池中执行,用于执行异步任务。通过publishProgress方法来更新任务的进度,publishProgress方法会调用onProgressUpdate方法,另外,任务的结果返回给onPostExecute方法。
(c)onProgressUpdate(Object... values):该方法在主线程中执行,主要用于任务进度更新的时候,该方法会被调用。
(d)onPostExecute(Long aLong):在主线程中执行,在异步任务执行完毕之后,该方法会被调用,该方法的参数及为后台的返回结果。
View的绘制流程:
(a)组合控件的自定义:不需要开发者自己绘制,而是使用原生控件组合成的新控件。如标题栏。
(b)继承原有控件的自定义:自定义控件在原生控件提供的方法外,可自己添加一些方法。如制作圆角,圆形图片。
(c)完全自定义控件:这个View上所展现的内容全部都是开发者自己绘制出来的。比如说制作水波纹进度条。
View的绘制流程三部曲:OnMeasure() → OnLayout() → OnDraw()
第1步:
OnMeasure()测量视图大小。从顶层父View到子View递归调用measure方法,measure方法又回调OnMeasure。
第2步:
OnLayout()确定View位置,进行页面布局。从顶层父View向子View的递归调用view.layout方法的过程,即父View根据 上一步measure子View所得到的布局大小和布局参数,将子View放在合适的位置上。
第3步:
OnDraw()绘制视图。ViewRoot创建一个Canvas对象,然后调用OnDraw()。
六个步骤:①、绘制视图的背景; ②、保存画布的图层(Layer);③、绘制View的内容;④、绘制View子视图,若没有就不用;⑤、还原图层(Layer); ⑥、绘制滚动条。
View、ViewGroup事件分发机制:
(a)Touch事件分发中只有两个主角:ViewGroup和View。
ViewGroup包含onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent三个相关事件。
View包含dispatchTouchEvent、onTouchEvent两个相关事件。
ViewGroup继承于View。
(b)ViewGroup和View组成了一个树状结构,根节点为Activity内部包含的一个ViwGroup。
(c)触摸事件由Action_Down、Action_Move、Aciton_UP组成,其中一次完整的触摸事件中,Down和Up都只有一个,Move有若干个,可以为0个。
(d)当Acitivty接收到用户的Touch事件时,将遍历子View进行Down事件的分发。ViewGroup的遍历可以看成是递归的。分发的目的是为了找到真正要处理本次完整触摸事件的View,这个View会在onTouchuEvent结果返回true。
(e)当某个子View返回true时,会中止Down事件的分发,同时在ViewGroup中记录该子View。接下去的Move和Up事件将由该子View直接进行处理。由于子View是保存在ViewGroup中的,多层ViewGroup的节点结构时,上级ViewGroup保存的会是真实处理事件的View所在的ViewGroup对象:如ViewGroup0 - ViewGroup1 - TextView的结构中,TextView返回了true,它将被保存在ViewGroup1中,而ViewGroup1也会返回true,被保存在ViewGroup0中。当Move和UP事件来时,会先从ViewGroup0传递至ViewGroup1,再由ViewGroup1传递至TextView。
(f)当ViewGroup中所有子View都不捕获Down事件时,将触发ViewGroup自身的onTouch事件。触发的方式是调用super.dispatchTouchEvent函数,即父类View的dispatchTouchEvent方法。在所有子View都不处理的情况下,触发Acitivity的onTouchEvent方法。
(g)onInterceptTouchEvent有两个作用:1、拦截Down事件的分发。2、中止Up和Move事件向目标View传递,使得目标View所在的ViewGroup捕获Up和Move事件。
(a) 布局优化:
通过工具 Hierarchy Viewer 检测 (分析布局) 、TraceView (测试分析耗时的)。
删除无用的空间和层级。
选择性能较低的ViewGroup;如约束布局,Relativelayout,LinearLayout,优先使用LinearLayout,因为相对来说Relativelayout功能较为复杂,会占用更多的CPU资源。
使用标签重用布局,减少层级,进行预加载,使用的时候才加载(如include等)。
(b) 绘制优化:
指View在onDraw()方法中避免大量的耗时操作,由于onDraw()方法可能会被频繁的调用。
onDraw()方法中不要创建新的局部变量,onDraw()方法被频繁的调用,很容易引起GC。
onDraw()方法不要做耗时操作。
(c) 内存泄漏优化:
http://blog.csdn.net/guolin_blog/article/details/42238627
(d) 响应速度优化:
主线程不能做耗时操作,触摸事件5s,广播10s,service 20s。
(e) ListView优化:
getView()方法中避免耗时操作。
View的复用和ViewHolder的使用。
滑动的时候不适合开启异步加载。
数据采用分页的方式加载。
图片使用三级缓存机制。
(f) Bitmap优化:
等比例压缩图片。
不用的图片,及时recycler掉。
(g) 线程优化:
线程优化的思想是使用线程池来管理和复用线程,避免程序中有大量的Thread,同时可控制线程的并发数,避免相互抢占资源而导致线程阻塞。
(h) 图片优化:
①对图片本身进行操作。尽量不要使用setImageBitmap、setImageResource、BitmapFactory.decodeResource来设置一张大图,因为这些方法在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多的内存。
②图片进行缩放的比例,SDK中建议其值是2的指数值,值越大会导致图片不清晰。
③不用的图片记得调用图片的recycle()方法进行清除掉。
(i) App启动优化(针对冷启动):
Application的onCreate(),特别是第三方SDK初始化,首屏Activity的渲染都不要进行耗时操作,若有,就放到子线程或IntentService中。
(j) 其他优化:
少用枚举,枚举占用空间大。
使用Android特有的数据结构,如 SparseArray 来代替 HashMap。
适当的使用软引用和弱引用。
优化网络请求,包括网络连接对用户的影响:流量、电量、用户等待。
API设计(App与Server之间的API设计要考虑网络请求的频次,资源的状态等,以便App以较少的请求来完成业务需求和界面的展示)
定位中使用GPS,请记得及时关闭。
Gzip压缩:使用Gzip来压缩request和response,减少传输数据量,从而减少流量消耗。
图片的Size:可在获取图片时告知服务器需要的图片的宽高,以便服务器给出合适的图片,避免浪费。
网络缓存:适当的缓存,既可让应用看起来更快,也能避免一些不必要的流量消耗。
onCreate() → onStart() → onResume() → onPause() → onStop() → onDetroy()
service 启动方式有两种:(不同的启动方式其生命周期也是不一样的)
(a)startService()
调用startService() → onCreate() → onStartCommand() → onDestroy()
注意:
①通过startService()被调用以后,多次调用startService(),onCreate()方法也只会被调用一次,而onStartCommand()会被多次调用,当调用stopService()的时候,onDestroy()才会被调用,从而销毁服务。
②当通过startService()启动的时候,通过intent传值,在onStartCommand()方法中获取值的时候,一定要先判断intent是否为null。
(b)bindService()
bindService() → onCreate() → onBind() → unBind() → onDestroy()
便利Activity中操作service。
app启动的过程分为两种情况:
(a)从桌面launcher上点击相应的应用图标
(b)在activity中通过调用startActivity来启动一个新的activity
Broadcast广播注册的2种方式:
(a)静态注册(常驻型广播):
直接在Androidmanifest.xml中进行注册,这种方式注册的广播,不受页面生命周期的影响,即使退出了页面,也可以收到广播,这种广播一般用于像开机自启动啊等等,由于这种注册的方式的广播是常驻型广播,所以会占用CPU的资源。
(b)动态注册(非常驻型广播):
在代码中注册的,受到生命周期的影响,退出页面后,就不会收到广播,因此通常运用在更新UI方面。这种注册方式优先级较高。最后需要解绑,否则会造成内存泄露。
广播是分为有序广播和无序广播。还可以进行自定义广播权限。
首先HttpClient和HttpUrlConnection 这两种方式都支持Https协议,都是以流的形式进行上传或者下载数据,也可以说是以流的形式进行数据的传输,还有ipv6,以及连接池等功能。
(a)HttpClient:
拥有非常多的API,若想要进行扩展的话,且在不破坏它的兼容性的情况下,很难进行扩展。
因为这个原因,Google在Android6.0的时候,就直接弃用了这个HttpClient。
(b)HttpUrlConnection:
HttpUrlConnection相对来说就是比较轻量级了,API比较少,容易扩展,且能够满足Android大部分的数据传输。
比较经典的一个框架volley,在2.3版本以前都是使用HttpClient,在2.3以后就使用了HttpUrlConnection。
(a)Java虚拟机:
基于栈,运行的是java字节码(java类会被编译成一个或多个字节码.class文件)。基于栈的机器必须使用指令来载入和操作栈上的数据,所需指令更多更多。
(b)Dalvik虚拟机:
基于寄存器,运行的是自定义的.dex字节码格式(java类被编译成.class文件后,会通过一个dx工具将所有的.class文件转换成一个.dex文件,然后dalvik虚拟机会从其中读取指令和数据);
Context是一个抽象基类。译为上下文,也理解为环境,是提供一些程序的运行环境基础的信息。
Context下有两个子类,ContextWrapper是上下文功能的封装类,而ContextImpl则是上下文功能的实现类。
而ContextWrapper又有三个直接的子类:ContextThemeWrapper、Service和Application。
ContextThemeWrapper是一个带主题的封装类:而它有一个直接子类就是Activity。因此,Activity和Service以及Application的Context是不一样的,只有Activity需要主题,Service不需要主题。
Context一共有三种类型:分别是Application、Activity和Service。这三个类虽然分别各种承担着不同的作用,但它们都属于Context的一种,而它们具体Context的功能则是由ContextImpl类去实现的,因此在绝大多数场景下,Activity、Service和Application这三种类型的Context都是可以通用的。
特殊情况,如:启动Activity,弹出Dialog。出于安全原因的考虑,Android是不允许Activity或Dialog凭空出现的,一个Activity的启动必须要建立在另一个Activity的基础之上,也就是以此形成的返回栈。而Dialog则必须在一个Activity上面弹出(除非是System Alert类型的Dialog),因此在这种场景下,我们只能使用Activity类型的Context,否则将会出错。
getApplicationContext()和getApplication()方法得到的对象都是同一个application对象,只是对象的类型不一样。
Context数量 = Activity数量 + Service数量 + 1(1为Application)
Activity构造的时候会初始化一个Window,准确的说是PhoneWindow。
PhoneWindow有一个"ViewRoot",这个"ViewRoot"是一个View或者说ViewGroup,是最初始的根视图。
"ViewRoot"通过addView方法来一个个的添加View。比如TextView,Button等。
View的事件监听,是由WindowManagerService来接受消息,并且回调Activity函数。比如onClickListener,onKeyDown等。
栈与队列的区别:栈是先进后出(压栈和出栈),队列是先进先出。
对插入和删除操作的"限定":栈是限定只能在表的一端进行插入和删除操作的线性表。队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。
(a) standard 模式
默认模式,每次激活Activity的时候,都会创建该Activity的实例,并且放入到任务栈当中去。
使用场景:大多数Activity的情况。
(b) singleTop 模式
分为2种情况:①若在栈中已存在该Activity实例,就会复用该实例,此时会调用onNewIntent()。
②若不存在就会去创建该Activity实例,并且将该实例放入到栈顶中去,即使栈中已经存在该Activity的实 例,只要不在栈顶,都会创建新的实例。
例子说明:A → B,若B设置了singleTop模式,再startActivity()启动B的话,就会复用B实例。(处于栈顶的实例才有用)
A → B,再B → A,若A设置了singleTop模式,A的实例依然会重新创建,所以这里是不能复用的。
使用场景:新闻类、阅读类App的内容页面
(c) singleTask 模式
分为2种情况:①若在栈中已有该Activity实例,就会复用该实例,此时会调用onNewIntent()。复用时,会让该实例回到栈顶,因此在它上面的实例将会被移出栈。
②若栈中不存在该Activity实例,将会创建新的实例放入任务栈中。
例子说明:A → B → C,若A设置了singleTask模式,再C → A,此时A会将存在于它之上的所有Activity都销毁掉,
此时任务栈中就只剩下A了。
使用场景:浏览器的主界面
(d) singleInstance 模式
在一个新栈中创建该Activity实例,并让多个应用共享该栈中的该Activity实例。因此它是全局单一性实例。
它具备所有singleTask的特点,唯一不同的是,它是存在于另一个任务栈中。上面的三种模式都存在于同一个任务栈中。
例子说明:若Android系统比如是宇宙的话,上面的三种模式都只存在地球上,而singleInstance则是存在于土星上。
①A → B → C,若B设置为singleInstance模式,当C退出后,去到的是A,而不是B,因为B是存在于另外一个任务栈中,只有当A也退出后,才去到的是B。
②A → B,若B设置为singleInstance模式,当按下home键,应用退到后台时,再点击图标进入,此时打开的是A,因为B存在另外栈中,而在主栈中(即LAUNCHER的activity所处在的栈)查找,查找是否有存在的activity,没有的话则会重新启动LAUNCHER。
使用场景:闹铃提醒、拨打电话界面
onSaveInstanceState(Bundle)会在activity转入后台状态之前被调用,也就是onStop()方法之前,onPause方法之后被调用;
(a)帧动画:
指通过指定每一帧的图片和播放时间,有序的进行播放而形成动画效果。
(b)补间动画:
指通过指定View的初始状态、变化时间、方式,通过一系列的算法去进行图形变换,从而形成动画效果,主要有Alpha、Scale、Translate、Rotate四种效果。注意:只是在视图层实现了动画效果,并没有真正改变View的属性,比如滑动列表,改变标题栏的透明度。
(c)属性动画:
在Android3.0的时候才支持,通过不断的改变View的属性,不断的重绘而形成动画效果。相比于视图动画,View的属性是真正改变了。比如view的旋转,放大,缩小。
Android 跨进程通信,像intent,contentProvider,广播,service都可以跨进程通信。
intent:这种跨进程方式并不是访问内存的形式,它需要传递一个uri,比如说打电话。
contentProvider:这种形式,是使用数据共享的形式进行数据共享。
service:远程服务,aidl
广播:
Android中,主线程是不能进行耗时操作的,子线程是不能进行更新UI的。于是就有了handler,它的作用就是实现线程之间的通信。
handler整个流程中,主要有四个对象,handler、Message、MessageQueue、Looper。当应用创建的时候,就会在主线程中创建handler对象,
通过要传送的消息保存到Message中,handler通过调用sendMessage方法将Message发送到MessageQueue中,Looper对象就会不断的调用loop()方法
不断的从MessageQueue中取出Message交给handler的回调函数handleMessage()方法进行处理。从而实现了线程之间的通信。
https://blog.csdn.net/csdn_lqr/article/details/78534065
https://www.cnblogs.com/popfisher/p/8543973.html
(a)内存溢出 out of memory
指程序在申请使用内存时,没有足够的内存空间供其使用,出现out of memory(即内存不够用);
如:申请了一个integer,但给它存了long才能存下的数,那就会内存溢出了。
(b)内存泄露 memory leak
指程序在申请使用内存后,无法释放已申请的内存空间,一次内存泄露危害可忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。理解为败家子(挥霍无度,多少财富都会被耗光。)
(a) Handler 引起的内存泄漏
解决:将Handler声明为静态内部类,就不会持有外部类的引用,其生命周期就和外部类无关。若Handler里面需要context的话,可以通过弱引用方式引用外部类的成员变量或方法。
(b) 单例模式引起的内存泄漏
解决:Context是ApplicationContext,由于ApplicationContext的生命周期是和app一致的,不会导致内存泄漏。
(c) 非静态内部类创建静态实例引起的内存泄漏
解决:把内部类修改为静态的就可避免内存泄漏了。
(d) 非静态匿名内部类引起的内存泄漏
解决:将匿名内部类设置为静态的。
(e) 注册/反注册未成对使用引起的内存泄漏
解决:注册广播接受器、EventBus等,一定得解绑。
(f) 资源对象没有关闭引起的内存泄漏
解决:在资源不使用的时,记得调用相应的类似close()、destroy()、recycler()、release()等方法释放。
(a) 集合对象没有及时清理引起的内存泄漏
解决:通常会把一些对象装入到集合中,当不使用的时候一定要记得及时清理集合,让相关对象不再被引用。
LeakCanary
(a) 直接在一个Fragment中调用另外一个Fragment中的方法。
(b) 使用接口回调。
(c) 使用广播。
(d) 使用EventBus。
(e) Fragment直接调用Activity中的public方法。
(f) 在Activity中,可直接通过在Adapter中new出Fragment的实例进行调用Fragment中的public方法。
字体使用sp,长度宽度间距使用dp,多使用match_parent,wrap_content,weight
图片资源,不同图片的的分辨率,放在相应的文件夹下,可使用百分比布局代替。
https://blog.csdn.net/carson_ho/article/details/64904691/
ANR全名Application Not Responding,也就是"应用无响应"。
当操作在一段时间内系统无法处理时, 系统层面会弹出上图那样的ANR对话框.
产生原因:
(a) 5s内无法响应用户输入事件(例如键盘输入,触摸屏幕等)。
(b) BroadcastReceiver在10s内无法结束。
(c) Service 20s内无法结束(低概率)。
解决方法:
①不要在主线程中做耗时的操作,而应放在子线程中来实现。如onCreate()和onResume()里尽可能少的去做创建操作。
②应用程序应该避免在BroadcastReceiver里做耗时的操作或计算。
③避免在Intent Receiver里启动一个Activity,因它会创建一个新的画面,并从当前用户正在运行的程序上抢夺焦点。
④service是运行在主线程的,所以在service中做耗时操作,必须要放在子线程中。
(a) MVC(如图)
说明:模型(Model),视图(View)和控制Controller)
优点:
①各施其职,互不干涉;
②有利于开发中的分工;
③有利于组件的重用。
缺点:
①增加了系统结构和实现的复杂性;
②视图与控制器间的过于紧密的连接;
③视图对模型数据的低效率访问;
④改造以适应MVC需要和建立分离的部件的代价很高。
(b) MVP(如图)
说明:
Model:负责存储、检索、操纵数据;
View:负责绘制UI元素、与用户进行交互(Activity或Fragment);
Presenter:作为View与Model交互的中间纽带,处理与用户交互的逻辑负责。
优点:
①降低耦合度,实现了Model和View真正的完全分离,两者互不影响;
②模块职责分工明显,层次结构清晰明了;
③数据隐藏容易;
④Presenter可复用;
⑤利于测试驱动开发;
⑥View可进行组件化;
⑦代码更加灵活性了。
缺点:
①Presenter中,除了应用程序的逻辑外,还有大量的View和Model的手动同步逻辑,造成Presenter臃肿,维护起来相对困难;
②由于对View的渲染放在了Presenter中,因此View和Presenter的交互会过于频繁;
③若Presenter过多的渲染View,会使得它与特点的View联系过于紧密。一旦View变更,Presenter也需要变。
(c) MVVM
https://www.jianshu.com/p/fc814a20c452
RecyclerView可完成ListView、GridView的效果,还可完成瀑布流的效果。同时还可设置列表的滚动方向(垂直或者水平);
RecyclerView中view的复用不需要开发者自己写代码,系统已经帮封装完成了。
RecyclerView可进行局部刷新。
RecyclerView提供了API来实现item的动画效果。
在性能上:
若需要频繁的刷新数据,需要添加动画,则RecyclerView有较大的优势。
若只是作为列表展示,则两者区别并不是很大。
https://www.cnblogs.com/dasusu/p/7746946.html
https://www.cnblogs.com/ganchuanpu/p/6104920.html
https://blog.csdn.net/qq_35114086/article/details/56664007
建立Socket连接至少需要一对套接字,其中一个运行在客户端ClientSocket,一个运行在服务端ServiceSocket。
(a)服务器监听:
服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。
(b)客户端请求:
指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。注意:客户端的套接字必须描述他要连接的服务器 的套接字,指出服务器套接字的地址和端口号,然后就像服务器端套接字提出连接请求。
(c)连接确认:
当服务器端套接字监听到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接 字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务端套接字则继续处于监听状态,继续接收其他客户端套接字的连接请求。
Http连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。
从建立连接到关闭连接的过程称为"一次连接"。
(a)https协议需要ca申请证书,一般需要一定费用。
(b)http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
(c)http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
(d)http的连接很简单,是无状态的;https协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
(a)客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接。
(b)Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。
(c)客户端的浏览器与Web服务器开始协商SSL连接的安全等级,也就是信息加密的等级。
(d)客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站。
(e)Web服务器利用自己的私钥解密出会话密钥。
(f)Web服务器利用会话密钥加密与客户端之间的通信。
(a)重载:一个类中可有多个相同方法名的,但参数类型和个数都不一样。
(b)重写:子类继承父类,则子类可通过实现父类中的方法,从而新的方法把父类旧的方法覆盖。
final:
(a)final变量即为常量,只能赋值一次。
(b)final方法不能被子类重写。
(c)final类不能被继承。
static:
(a)static变量
对于静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存,在加载类的过程中,完成静态变量的内存分配,可用类名直接访问(方便),当然也可通过对象来访问(但是这是不推荐的)。
(b)static代码块
是类加载时,初始化自动执行的。
(c)static方法
可直接通过类名调用,任何的实例也都可调用,因此static方法中不能用this和super关键字,不能直接访问所属类的实例变量和实例方法(就是不带static的成员变量和成员成员方法),只能访问所属类的静态成员变量和成员方法。
https://blog.csdn.net/WHB20081815/article/details/68943545
https://www.jianshu.com/p/17a5102e0222