面向对象:
封装:隐藏实现细节,提高程序的复用性和维护性
继承:子类继承父类,表明子类拥有父类的属性和方法(注意是public protected修饰符的)
多态:父类引用指向子类对象
Android四大组件:
Activity、Service、ContentProvider、BroadcastReceiver。
Activity生命周期:
onCreate、onStart、onResume、onPause、onStop、onDestroy、onRestart
在Service的生命周期里,常用的有:
手动调用方法作用
startService()启动服务
stopService()关闭服务
bindService()绑定服务
unbindService()解绑服务
内部自动调用的方法作用
onCreat()创建服务
onStartCommand()开始服务
onDestroy()销毁服务
onBind()绑定服务
onUnbind()解绑服务
ContentProvider 是如何实现数据共享的
我们可以定义⼀个类继承 ContentProvider,然后覆写该类的insert、delete、update 等⽅法,在 这些⽅法⾥访问数据库等资源。同时将我们 ContentProvider 注册在 AndroidManifest ⽂件中,其他应 ⽤需要使⽤的时候只需获取 ContentResolver,然后通过 ContentResolver进行对数据库的增删改查
BroadCastReceiver的理解
BroadCastReceiver为广播接收器,它用于接收广播intent。
广播是一种广泛运用在应用程序之间传输信息的机制。而 BroadcastReceiver 是对发送出来的广播进行过滤接收并响应的一类组件;BroadcastReceiver 自身并不实现图形用户界面,但是当它收到某个通知后,BroadcastReceiver可以启动Activity作为响应, 或者通过 NotificationMananger提醒用户,或者启动 Service 等等。
Android五大布局:
线性、相对、绝对、帧、网格
LinearLayout、RelativeLayout、FrameLayout、AbsoluteLayout、TableLayout
Android 的数据存储⽅式
SharedPreference、XML、SQLite、⽂件存储
Android动画:
属性动画:
Android 3.0(API 11)后才提供的一种全新动画模式
其出现原因为作用对象局限于View,没有改变View的属性,只是改变视觉效果,动画效果单一
{下载进度条}使用了属性动画
补间动画:
补间动画由Animation类来实现具体效果,包括平移(TranslateAnimation)、缩放(ScaleAnimation)、旋转(RotateAnimation)、透明度(AlphaAnimation)四个子类,四种变化。
帧动画:
下拉刷新时头布局里我们使用了帧动画
自定义View
自定义控件的实现有三种方式,分别是:组合控件、自绘控件和继承控件
自定义View的流程
1.自定义View的属性(非必需)
2.在View的构造方法中获得我们自定义的属性(非必需)
3.重写onMesure
4.重写onDraw
APP基本性能优化:
快、稳、省、小。
快:使用时避免出现卡顿,响应速度快,减少用户等待的时间,满足用户期望。
稳:减低 crash 率和 ANR 率,不要在用户使用过程中崩溃和无响应。
省:节省流量和耗电,减少用户使用成本,避免使用时导致手机发烫。
小:安装包小可以降低用户的安装成本。
卡顿优化
UI 绘制、应用启动、页面跳转、事件响应
优化建议
布局优化:
减少层级。合理使用 RelativeLayout 和 LinerLayout,合理使用Merge。
提高显示速度。使用 ViewStub,它是一个看不见的、不占布局位置、占用资源非常小的视图对象。
布局复用。可以通过 标签来提高复用。
尽可能少用wrap_content。wrap_content 会增加布局 measure 时计算成本,在已知宽高为固定值时,不用wrap_content 。
删除控件中无用的属性。
避免过度绘制:
布局上的优化。移除 XML 中非必须的背景,移除 Window 默认的背景、按需显示占位背景图片
自定义View优化。使用 canvas.clipRect()来帮助系统识别那些可见的区域,只有在这个区域内才会被绘制。
启动优化:
UI 布局。应用一般都有闪屏页,优化闪屏页的 UI 布局,可以通过 Profile GPU Rendering 检测丢帧情况。
启动加载逻辑优化。可以采用分布加载、异步加载、延期加载策略来提高应用启动速度。
数据准备。数据初始化分析,加载数据可以考虑用线程初始化等策略。
合理的刷新机制:
尽量减少刷新次数。
尽量避免后台有高的 CPU 线程运行。
缩小刷新区域。
内存优化:
在 Android 系统中有个垃圾内存回收机制,在虚拟机层自动分配和释放内存,因此不需要在代码中分配和释放某一块内存,从应用层面上不容易出现内存泄漏和内存溢出等问题,但是需要内存管理。Android 系统在内存管理上有一个 Generational Heap Memory 模型,内存回收的大部分压力不需要应用层关心, Generational Heap Memory 有自己一套管理机制,当内存达到一个阈值时,系统会根据不同的规则自动释放系统认为可以释放的内存,也正是因为 Android 程序把内存控制的权力交给了 Generational Heap Memory,一旦出现内存泄漏和溢出方面的问题,排查错误将会成为一项异常艰难的工作。除此之外,部分 Android 应用开发人员在开发过程中并没有特别关注内存的合理使用,也没有在内存方面做太多的优化,当应用程序同时运行越来越多的任务,加上越来越复杂的业务需求时,完全依赖 Android 的内存管理机制就会导致一系列性能问题逐渐呈现,对应用的稳定性和性能带来不可忽视的影响,因此,解决内存问题和合理优化内存是非常有必要的。
内存分配
在 Android 系统中,内存分配实际上是对堆的分配和释放。当一个 Android 程序启动,应用进程都是从一个叫做 Zygote 的进程衍生出来,系统启动 Zygote 进程后,为了启动一个新的应用程序进程,系统会衍生 Zygote 进程生成一个新的进程,然后在新的进程中加载并运行应用程序的代码。其中,大多数的 RAM pages 被用来分配给Framework 代码,同时促使 RAM 资源能够在应用所有进程之间共享。
但是为了整个系统的内存控制需要,Android 系统会为每一个应用程序都设置一个硬性的 Dalvik Heap Size 最大限制阈值,整个阈值在不同设备上会因为 RAM 大小不同而有所差异。如果应用占用内存空间已经接近整个阈值时,再尝试分配内存的话,就很容易引起内存溢出的错误。
内存回收机制
我们需要知道的是,在 Java 中内存被分为三个区域:Young Generation(年轻代)、Old Generation(年老代)、Permanent Generation(持久代)。最近分配的对象会存放在 Young Generation 区域。对象在某个时机触发 GC 回收垃圾,而没有回收的就根据不同规则,有可能被移动到 Old Generation,最后累积一定时间在移动到 Permanent Generation 区域。系统会根据内存中不同的内存数据类型分别执行不同的 GC 操作。GC 通过确定对象是否被活动对象引用来确定是否收集对象,进而动态回收无任何引用的对象占据的内存空间。但需要注意的是频繁的 GC 会增加应用的卡顿情况,影响应用的流畅性,因此需要尽量减少系统 GC 行为,以便提高应用的流畅度,减小卡顿发生的概率。
常见内存泄漏场景
如果在内存泄漏发生后再去找原因并修复会增加开发的成本,最好在编写代码时就能够很好地考虑内存问题,写出更高质量的代码,这里列出一些常见的内存泄漏场景,在以后的开发过程中需要避免这类问题。
资源性对象未关闭。比如Cursor、File文件等,往往都用了一些缓冲,在不使用时,应该及时关闭它们。
注册对象未注销。比如事件注册后未注销,会导致观察者列表中维持着对象的引用。
类的静态变量持有大数据对象。
非静态内部类的静态实例。
Handler临时性内存泄漏。如果Handler是非静态的,容易导致 Activity 或 Service 不会被回收。
容器中的对象没清理造成的内存泄漏。
WebView。WebView 存在着内存泄漏的问题,在应用中只要使用一次 WebView,内存就不会被释放掉。
优化内存空间
没有内存泄漏,并不意味着内存就不需要优化,在移动设备上,由于物理设备的存储空间有限,Android 系统对每个应用进程也都分配了有限的堆内存,因此使用最小内存对象或者资源可以减小内存开销,同时让GC 能更高效地回收不再需要使用的对象,让应用堆内存保持充足的可用内存,使应用更稳定高效地运行。常见做法如下:
对象引用。强引用、软引用、弱引用、虚引用四种引用类型,根据业务需求合理使用不同,选择不同的引用类型。
减少不必要的内存开销。注意自动装箱,增加内存复用,比如有效利用系统自带的资源、视图复用、对象池、Bitmap对象的复用。
使用最优的数据类型。比如针对数据类容器结构,可以使用ArrayMap数据结构,避免使用枚举类型,使用缓存Lrucache等等。
图片内存优化。可以设置位图规格,根据采样因子做压缩,用一些图片缓存方式对图片进行管理等等。
稳定性优化
Android 应用的稳定性定义很宽泛,影响稳定性的原因很多,比如内存使用不合理、代码异常场景考虑不周全、代码逻辑不合理等,都会对应用的稳定性造成影响。其中最常见的两个场景是:Crash 和 ANR,这两个错误将会使得程序无法使用,比较常用的解决方式如下:
提高代码质量。比如开发期间的代码审核,看些代码设计逻辑,业务合理性等。
代码静态扫描工具。常见工具有Android Lint、Findbugs、Checkstyle、PMD等等。
Crash监控。把一些崩溃的信息,异常信息及时地记录下来,以便后续分析解决。
Crash上传机制。在Crash后,尽量先保存日志到本地,然后等下一次网络正常时再上传日志信息。
ListView优化:
ListView 的优化有多种多样的策略。在我们的项⽬中主要做了如下优化。
1、重⽤ ConvertView,2、给 ConvertView 绑定ViewHolder,3、分页加载数据,4、使⽤缓存。前两个是通⽤的解决⽅案,后两个是针对我们业务的个性化解决⽅案。我们的数据来⾃服务端,如果服务端有 1000 条数据 的话,我们客户端不可能傻⽠式的⼀次性⽤ ListView 把这些数据全部加载进来,因此我们就⽤分页加载 数据,每次加载 20 页,当⽤户请求更多的时候再获取更多数据,⽹络的访问就算⽹速再快也多多少少会有 ⼀定的延迟,因此我们的⽹络请求是异步处理的,同时从⽹络加载来的数据使⽤了 2 级缓存来处理,第⼀级 是内存级别的缓存,第⼆级是本地⽂件的缓存。当 ListView 加载数据的时候⾸先从内存中找,如果找不 到再去本地⽂件中找,只有都找不到的情况下才去请求⽹络。
MVP模式
MVP 模式将Activity 中的业务逻辑全部分离出来,让Activity 只做 UI 逻辑的处理,所有跟Android API无关的业务逻辑由 Presenter 层来完成。
将业务处理分离出来后最明显的好处就是管理方便,但是缺点就是增加了代码量。
在MVP 架构中跟MVC类似的是同样也分为三层。
Activity 和Fragment 视为View层,负责处理 UI。
Presenter 为业务处理层,既能调用UI逻辑,又能请求数据,该层为纯Java类,不涉及任何Android API。
Model 层中包含着具体的数据请求,数据源。
三层之间调用顺序为view->presenter->model,为了调用安全着想不可反向调用!不可跨级调用!
Android多线程:
1. Handler+Thread
2. AsyncTask
3. ThreadPoolExecutor
4. IntentService
Handler+Thread
Android主线程包含一个消息队列(MessageQueue),该消息队列里面可以存入一系列的Message或Runnable对象。通过一个Handler你可以往这个消息队列发送Message或者Runnable对象,并且处理这些对象。每次你新创建一个Handle对象,它会绑定于创建它的线程(也就是UI线程)以及该线程的消息队列,从这时起,这个handler就会开始把Message或Runnable对象传递到消息队列中,并在它们出队列的时候执行它们。
Handler可以把一个Message对象或者Runnable对象压入到消息队列中,进而在UI线程中获取Message或者执行Runnable对象,Handler把压入消息队列有两类方式,Post和sendMessage:
Post方式:
Post允许把一个Runnable对象入队到消息队列中。它的方法有:
post(Runnable)/postAtTime(Runnable,long)/postDelayed(Runnable,long)
对于Handler的Post方式来说,它会传递一个Runnable对象到消息队列中,在这个Runnable对象中,重写run()方法。一般在这个run()方法中写入需要在UI线程上的操作。
sendMessage:
sendMessage允许把一个包含消息数据的Message对象压入到消息队列中。它的方法有:sendEmptyMessage(int)/sendMessage(Message)/sendMessageAtTime(Message,long)/sendMessageDelayed(Message,long)
Handler如果使用sendMessage的方式把消息入队到消息队列中,需要传递一个Message对象,而在Handler中,需要重写handleMessage()方法,用于获取工作线程传递过来的消息,此方法运行在UI线程上。Message是一个final类,所以不可被继承。
优缺点:
1. Handler用法简单明了,可以将多个异步任务更新UI的代码放在一起,清晰明了
2. 处理单个异步任务代码略显多
适用范围:
1. 多个异步任务的更新UI
AsyncTask
AsyncTask是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程。
AsyncTask通过一个阻塞队列BlockingQuery
IntentService
IntentService继承自Service,是一个经过包装的轻量级的Service,用来接收并处理通过Intent传递的异步请求。客户端通过调用startService(Intent)启动一个IntentService,利用一个work线程依次处理顺序过来的请求,处理完成后自动结束Service。
特点
1. 一个可以处理异步任务的简单Service