1.Android四大组件
1.1Activity
-
一个Activity通常就是一个单独的屏幕(窗口)。
-
Activity之间通过Intent进行通信。
-
android应用中每一个Activity都必须要在AndroidManifest.xml配置文件中声明,否则系统将不识别也不执行该Activity。
1.1.1 Activity生命周期
1.1.2 Activity启动流程
-
系统进程 SystemServer (负责管理整个framework,是Zygote孵化的第一个进程)
-
App进程(App进程是用户点击桌面icon时,通过Launcher进程请求SystemServer,再调用Zygote孵化的)
-
Zygote进程(所有进程孵化都由Zygote完成,而Zygote是init进程的子进程,也由init进程孵化)
-
如果点击桌面icon启动还会涉及到 Launcher进程(Zygote孵化的第一个应用进程)
AMS(ActivityManagerService)是Android中最核心的服务,主要负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作,其职责与操作系统中的进程管理和调度模块相类似。AMS服务运行在system_server进程中,AMS由SystemServer的ServerThread线程创建。activity启动或停止通知AmS,Ams决定是否执行动作,activity的数量>20时,最早入栈的activity会被AmS给忘记,新加进来了activity入栈。
-
我们以
点击Launcher的一个icon
为开始,整体扯一下Activity的启动过程,桌面其实就是LauncherApp的一个Activity -
当点击Launcher的icon开始,Launcher进程会像AMS发送点击icon的启动信息(这些信息就是在AndroidMainifest.xml中标签定义的启动信息,数据由PackageManagerService解析出来)
-
AMS收到信息后会先后经过ActivityTaskManagerService->ActivityStartController->ActivityStarter内部类Request,然后把信息存到Request中,并通知Launcher进程让Activity休眠(补充个小知识点,这个过程会检测Activity在AndroidMainifest.xml的注册,如果没有注册就报错了)
-
Launcher进程的ApplicationThread对象收到消息后调用handlePauseActivity()进行暂停,并通知AMS已经暂停。 实现细节:ActivityThread.sendMessage()通过ActivityThread的H类发送Handler消息,然后触发 mTransactionExecutor.execute(transaction), 执行过程中依赖ActivityClientRecord.mLifecycleState数值并通过ClientTransactionHandler抽象类的实现(ActivityThread)进行分发。注 :ActivityClientRecord.mLifecycleState(-1 ~ 7分别代表UNDEFINED,PRE_ON_CREATE,ON_CREATE,ON_START,ON_RESUME,ON_PAUSE,ON_STOP,ON_DESTROY,ON_RESTART)AMS收到Launcher的已暂停消息后,会检查要启动的Activity所在的进程是否已经启动了,如果已经启动了就打开,如果未启动则通过Process.start(android.app.ActivityThread)来启动一个新的进程。
-
进程创建好以后,会调用ActivityThread.main(),初始化MainLooper,并创建Application对象。然后Instrumentation.newApplication()反射创建Application,创建ContextImpl通过Application的attach方法与Application进行绑定,最终会调用Instrumentation.callApplicationOnCreate执行Application的onCreate函数进行一些初始化的工作。完成后会通知AMS进程已经启动好了。
通知过程:通过IActivityManager.attachApplication(IApplicationThread thread, long startSeq),将Application对象传入AMS
-
AMS收到app进程启动成功的消息后,从ActivityTaskManagerService中取出对应的Activity启动信息, 并通过ApplicationThreadProxy对象,调用其scheduleTransaction(ClientTransaction transaction)方法,具体要启动的Activity都在ClientTransaction对象中。
-
app进程的ApplicationThread收到消息后会调用ActiivtyThread.sendMessage(),通过H发送Handler消息,在handleMessage方法的内部又会调用 mTransactionExecutor.execute(transaction);具体参考第3步 最终调用performLaunchActivity方法创建activity和context并将其做关联,然后通过mInstrumentation.callActivityOnCreate()->Activity.performCreate()->Activity.onCreate()回调到了Activity的生命周期。
1.2 Service
1.2.1 Service
是一种可在后台执行长时间运行操作而不提供界面的应用组件。
服务可由其他应用组件启动,而且即使用户切换到其他应用,服务仍将在后台继续运行。此外,组件可通过绑定到服务与之进行交互,甚至是执行进程间通信 (IPC)。例如,服务可在后台处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序进行交互。
管理服务的生命周期
服务的生命周期比 Activity 的生命周期要简单得多。但是,密切关注如何创建和销毁服务反而更加重要,因为服务可以在用户未意识到的情况下运行于后台。
服务生命周期(从创建到销毁)可遵循以下任一路径:
-
启动服务
该服务在其他组件调用
startService()
时创建,然后无限期运行,且必须通过调用stopSelf()
来自行停止运行。此外,其他组件也可通过调用stopService()
来停止此服务。服务停止后,系统会将其销毁。 -
绑定服务
该服务在其他组件(客户端)调用
bindService()
时创建。然后,客户端通过IBinder
接口与服务进行通信。客户端可通过调用unbindService()
关闭连接。多个客户端可以绑定到相同服务,而且当所有绑定全部取消后,系统即会销毁该服务。(服务不必自行停止运行。)
这两条路径并非完全独立。您可以绑定到已使用 startService()
启动的服务。例如,您可以使用 Intent
(标识要播放的音乐)来调用 startService()
,从而启动后台音乐服务。随后,当用户需稍加控制播放器或获取有关当前所播放歌曲的信息时,Activity 可通过调用 bindService()
绑定到服务。此类情况下,在所有客户端取消绑定之前,stopService()
或 stopSelf()
实际不会停止服务。
1.3 Android 广播接收器(Broadcast Receivers)
Android 应用与 Android 系统和其他 Android 应用之间可以相互收发广播消息,这与发布-订阅设计模式相似。这些广播会在所关注的事件发生时发送。举例来说,Android 系统会在发生各种系统事件时发送广播,例如系统启动或设备开始充电时。再比如,应用可以发送自定义广播来通知其他应用它们可能感兴趣的事件(例如,一些新数据已下载)。
应用可以注册接收特定的广播。广播发出后,系统会自动将广播传送给同意接收这种广播的应用。
1.3.1 Android 为应用提供三种方式来发送广播:
-
sendOrderedBroadcast(Intent, String)
方法一次向一个接收器发送广播。当接收器逐个顺序执行时,接收器可以向下传递结果,也可以完全中止广播,使其不再传递给其他接收器。接收器的运行顺序可以通过匹配的 intent-filter 的 android:priority 属性来控制;具有相同优先级的接收器将按随机顺序运行。 -
sendBroadcast(Intent)
方法会按随机的顺序向所有接收器发送广播。这称为常规广播。这种方法效率更高,但也意味着接收器无法从其他接收器读取结果,无法传递从广播中收到的数据,也无法中止广播。 -
LocalBroadcastManager.sendBroadcast
方法会将广播发送给与发送器位于同一应用中的接收器。如果您不需要跨应用发送广播,请使用本地广播。这种实现方法的效率更高(无需进行进程间通信),而且您无需担心其他应用在收发您的广播时带来的任何安全问题。
要在清单中声明广播接收器,请执行以下步骤:
-
在应用清单中指定 `` 元素。
<receiver android:name=".MyBroadcastReceiver" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"/> <action android:name="android.intent.action.INPUT_METHOD_CHANGED" /> </intent-filter> </receiver>
Intent 过滤器指定您的接收器所订阅的广播操作。
-
创建
BroadcastReceiver
子类并实现onReceive(Context, Intent)
。以下示例中的广播接收器会记录并显示广播的内容:private const val TAG = "MyBroadcastReceiver" class MyBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { StringBuilder().apply { append("Action: ${intent.action}\n") append("URI: ${intent.toUri(Intent.URI_INTENT_SCHEME)}\n") toString().also { log -> Log.d(TAG, log) Toast.makeText(context, log, Toast.LENGTH_LONG).show() } } } }
系统软件包管理器会在应用安装时注册接收器。然后,该接收器会成为应用的一个独立入口点,这意味着如果应用当前未运行,系统可以启动应用并发送广播。
系统会创建新的 BroadcastReceiver
组件对象来处理它接收到的每个广播。此对象仅在调用 onReceive(Context, Intent)
期间有效。一旦从此方法返回代码,系统便会认为该组件不再活跃。
1.3.2上下文注册的接收器
要使用上下文注册接收器,请执行以下步骤:
-
创建
BroadcastReceiver
的实例。val br: BroadcastReceiver = MyBroadcastReceiver()
-
创建
IntentFilter
并调用registerReceiver(BroadcastReceiver, IntentFilter)
来注册接收器:val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION).apply { addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED) } registerReceiver(br, filter)
注意:要注册本地广播,请调用
LocalBroadcastManager.registerReceiver(BroadcastReceiver, IntentFilter)
。只要注册上下文有效,上下文注册的接收器就会接收广播。例如,如果您在
Activity
上下文中注册,只要 Activity 没有被销毁,您就会收到广播。如果您在应用上下文中注册,只要应用在运行,您就会收到广播。 -
要停止接收广播,请调用
unregisterReceiver(android.content.BroadcastReceiver)
。当您不再需要接收器或上下文不再有效时,请务必注销接收器。请注意注册和注销接收器的位置,比方说,如果您使用 Activity 上下文在
onCreate(Bundle)
中注册接收器,则应在onDestroy()
中注销,以防接收器从 Activity 上下文中泄露出去。如果您在onResume()
中注册接收器,则应在onPause()
中注销,以防多次注册接收器(如果您不想在暂停时接收广播,这样可以减少不必要的系统开销)。请勿在onSaveInstanceState(Bundle)
中注销,因为如果用户在历史记录堆栈中后退,则不会调用此方法。
1.4 Binder/Socket用于进程间通信
Binder IPC 属于 C/S 结构,Client 部分是用户代码,用户代码最终会调用 Binder Driver 的 transact 接口,Binder Driver 会调用 Server,这里的 Server 与 service 不同,可以理解为 Service 中 onBind 返回的 Binder 对象,请注意区分下。
-
Client:用户需要实现的代码,如 AIDL 自动生成的接口类
-
Binder Driver:在内核层实现的 Driver
-
Server:这个 Server 就是 Service 中 onBind 返回的 IBinder 对象
需要注意的是,上面绿色的色块部分都是属于用户需要实现的部分,而蓝色部分是系统去实现了。也就是说 Binder Driver 这块并不需要知道,Server 中会开启一个线程池去处理客户端调用。为什么要用线程池而不是一个单线程队列呢?试想一下,如果用单线程队列,则会有任务积压,多个客户端同时调用一个服务的时候就会有来不及响应的情况发生,这是绝对不允许的。
对于调用 Binder Driver 中的 transact 接口,客户端可以手动调用,也可以通过 AIDL 的方式生成的代理类来调用,服务端可以继承 Binder 对象,也可以继承 AIDL 生成的接口类的 Stub 对象。这些细节下面继续接着说,这里暂时不展开。
切记,这里 Server 的实现是线程池的方式,而不是单线程队列的方式,区别在于,单线程队列的话,Server 的代码是线程安全的,线程池的话,Server 的代码则不是线程安全的,需要开发者自己做好多线程同步。
1.5 Handle Android 消息传递机制,主要用于线程间通信。
1.5.1 Handler消息机制用于同进程的线程间通信可以说只要有异步线程与主线程通信的地方就一定会有 Handler。
Handler、Message、Message Queue、Looper
Message :代表一个行为what或者一串动作Runnable, 每一个消息在加入消息队列时,都有明确的目标Handler
ThreadLocal: 线程本地存储区(Thread Local Storage,简称为TLS),每个线程都有自己的私有的本地存储区域,不同线程之间彼此不能访问对方的TLS区域。ThreadLocal的作用是提供线程内的局部变量TLS,这种变量在线程的生命周期内起作用,每一个线程有他自己所属的值(线程隔离)
MessageQueue (C层与Java层都有实现) :以队列的形式对外提供插入和删除的工作, 其内部结构是以双向链表的形式存储消息的
Looper (C层与Java层都有实现) :Looper是循环的意思,它负责从消息队列中循环的取出消息然后把消息交给Handler处理
Handler :消息的真正处理者, 具备获取消息、发送消息、处理消息、移除消息等功能
消息机制的模型:
-
Message:需要传递的消息,可以传递数据;
-
MessageQueue:消息队列,但是它的内部实现并不是用的队列,实际上是通过一个单链表的数据结构来维护消息列表,因为单链表在插入和删除上比较有优势。主要功能向消息池投递消息(MessageQueue.enqueueMessage)和取走消息池的消息(MessageQueue.next);
-
Handler:消息辅助类,主要功能向消息池发送各种消息事件(Handler.sendMessage)和处理相应消息事件(Handler.handleMessage);
-
Looper:不断循环执行(Looper.loop),从MessageQueue中读取消息,按分发机制将消息分发给目标处理者。
消息机制的架构:
-
在子线程执行完耗时操作,当Handler发送消息时,将会调用 MessageQueue.enqueueMessage ,向消息队列中添加消息。
-
当通过 Looper.loop 开启循环后,会不断地从线程池中读取消息,即调用 MessageQueue.next
-
然后调用目标Handler(即发送该消息的Handler)的 dispatchMessage 方法传递消息,然后返回到Handler所在线程,目标Handler收到消息,调用 handleMessage 方法,接收消息,处理消息。
1.6 Android - 内容提供者(Content Provider)
内容提供者组件通过请求从一个应用程序向其他的应用程序提供数据。这些请求由类 ContentResolver 的方法来处理。内容提供者可以使用不同的方式来存储数据。数据可以被存放在数据库,文件,甚至是网络。
内容提供者可以让内容集中,必要时可以有多个不同的应用程序来访问。内容提供者的行为和数据库很像。你可以查询,编辑它的内容,使用 insert(), update(), delete() 和 query() 来添加或者删除内容。多数情况下数据被存储在 SQLite 数据库。
内容提供者被实现为类 ContentProvider 类的子类。需要实现一系列标准的 API,以便其他的应用程序来执行事务。
要查询内容提供者,你需要以如下格式的URI的形式来指定查询字符串:
<prefix>://<authority>/<data_type>/<id>
以下是URI中各部分的具体说明:
部分 | 说明 |
---|---|
prefix | 前缀:一直被设置为content:// |
authority | 授权:指定内容提供者的名称,例如联系人,浏览器等。第三方的内容提供者可以是全名,如:cn.programmer.statusprovider |
data_type | 数据类型:这个表明这个特殊的内容提供者中的数据的类型。例如:你要通过内容提供者Contacts来获取所有的通讯录,数据路径是people,那么URI将是下面这样:content://contacts/people |
id | 这个指定特定的请求记录。例如:你在内容提供者Contacts中查找联系人的ID号为5,那么URI看起来是这样:content://contacts/people/5 |
这里描述创建自己的内容提供者的简单步骤。
-
首先,你需要继承类 ContentProviderbase 来创建一个内容提供者类。
-
其次,你需要定义用于访问内容的你的内容提供者URI地址。
-
接下来,你需要创建数据库来保存内容。通常,Android 使用 SQLite 数据库,并在框架中重写 onCreate() 方法来使用 SQLiteOpenHelper 的方法创建或者打开提供者的数据库。当你的应用程序被启动,它的每个内容提供者的 onCreate() 方法将在应用程序主线程中被调用。
-
最后,使用<provider.../>标签在 AndroidManifest.xml 中注册内容提供者。
-
onCreate():当提供者被启动时调用。
-
query():该方法从客户端接受请求。结果是返回指针(Cursor)对象。
-
insert():该方法向内容提供者插入新的记录。
-
delete():该方法从内容提供者中删除已存在的记录。
-
update():该方法更新内容提供者中已存在的记录。
-
getType():该方法为给定的URI返回元数据类型。
1.2 网络服务
1.2.1 http/https
HTTP协议也就是超文本传输协议,是一种使用明文数据传输的网络协议。一直以来HTTP协议都是最主流的网页协议,HTTP协议被用于在Web浏览器和网站服务器之间传递信息,以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息。
HTTPS协议是由SSL/TLS+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全,很多大型互联网网站,如百度、淘宝、腾讯很早就已经把HTTP换成HTTPS了。
https协议需要到CA申请证书,一般免费证书很少,需要交费,Web服务器启用SSL需要获得一个服务器证书并将该证书与要使用SSL的服务器绑定。
http和https使用的是完全不同的连接方式,同时使用的端口也不同,http使用的是80端口,https使用的是443端口。在网络模型中,HTTP工作于应用层,而HTTPS工作在传输层。
1.2.2 tcp/ip
IP地址+端口号网络模型叫:OSI(Open System Interconnection 开放系统互连)模型
UDP 协议是什么 UDP(全称:User Datagram Protocol)中文名是面向数据报的通讯协议,位于OSI模型的传输层。
UDP是一个分发信息的理想协议,适用于追求效率且不需要特别可靠的情形,如直播、电话会议、音视频通话。有很多知名的应用都使用的是UDP协议,例如:域名服务(DNS)、网络文件系统(NFS)等等
IP协议的主要任务,就是按照源IP地址向目标IP地址发送数据报。它并不管这个发送任务能否成功,只负责发过去,将确认是否发送成功的操作抛给上层传输层处理了。
TCP是什么 TCP(Transmission Control Protocol)协议,中文名:传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议。
TCP三次握手与四次挥手。
-
SYN:同步序列编号(Synchronize Sequence Numbers),是客户机发起连接的信号,很多网络攻击就会模仿很多此类型号,让服务器以为有大量的客户端连接接入,从而导致服务器崩溃。
-
ACK:确认字符(Acknowledge character),表示服务器收到了发起连接的信号,给客户端发送的确认消息,如果接收方成功的接收到数据,那么会回复一个ACK数据。
-
SYN-ACK:在服务器接收到消息之后,服务器使用 SYN+ACK 应答给客户端表示接收到了这个消息。
数据的传输在TCP协议的“眼中”就是两边的字节流数据进行交换,通常在每个TCP报文段中都有一对序号和确认号(SN号)。TCP报文发送者称自己的字节流的编号为序号,称接收到对方的字节流编号为确认号。
TCP断开连接的“仪式”——四次挥手,可以用一张图来概括。
1.2.3 Android中及java中使用http或者是socket
SocketServeice(服务器):
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class SocketService { //搭建服务器端 public static void main(String[] args) throws IOException{ ServerSocket server=new ServerSocket(5209); System.out.println("服务器启动成功"); Socket socket=server.accept(); BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedReader out=new BufferedReader(new InputStreamReader(System.in)); PrintWriter pw = new PrintWriter(socket.getOutputStream()); while(true){ System.out.println("客户端说:"+in.readLine()); String str = out.readLine(); pw.println(str); pw.flush(); System.out.println("服务器说:"+str); } } }
SocketClient(客户端):
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class SocketClient { // 搭建客户端 public static void main(String[] args) throws IOException { Socket socket = new Socket("192.168.10.2", 5209); System.out.println("客户端启动成功"); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); BufferedReader out = new BufferedReader(new InputStreamReader(System.in)); PrintWriter pw = new PrintWriter(socket.getOutputStream()); while (true) { String str = out.readLine(); pw.println(str); pw.flush(); System.out.println("客户端说:" + str); System.out.println("服务器说:"+in.readLine()); } } }
1.3 MVC MVP MVVM
MVC将应用抽象为数据层(Model)、视图(View)、逻辑(Controller)
MVP则在MVC基础上,限定了通信方式,即Model和View之间不直接通信,都通过Presenter通信,这个Presenter和MVC中的Controller一脉相承,代表应用中的逻辑层。Presenter负责项目中的逻辑,并且直接与View和Model通信,操作数据更新更新后手动同步到View上。
MVVM设计了VM层,即ViewModel层,ViewModel自动同步数据到视图,用VM代替P之后,MVVM自动从Model映射到View(实现方式是模板渲染),不需要用户手动操作视图,这样代码更简单不易出错,代码更好阅读和维护。
1.4 Rxjava
Rx可以这样定义:Rx = Observables + LINQ + Schedulers。
ReactiveX.io给的定义是,Rx是一个使用可观察数据流进行异步编程的编程接口,ReactiveX结合了观察者模式、迭代器模式和函数式编程的精华。
Observable拥有它的近亲Iterable的全部优雅与灵活。任何对Iterable的操作,你都可以对Observable使用。
1.5 Android 动画
1.5.1帧动画
帧动画就是顺序播放一组预先定义好的图片,就类似于我们观看视频,就是一张一张的图片连续播放。
帧动画的使用很简单,总共就两个步骤:
1、在res/drawable目录下定义一个XML文件,根节点为系统提供的animation-list,然后放入定义更好的图片; 2、使用AnimationDrawable类播放第一步定义好的Drawable中的图片,形成动画效果;
代码示例,第一步,创建Drawable文件:
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="@drawable/image01" android:duration="500"/> <item android:drawable="@drawable/image02" android:duration="500"/> <item android:drawable="@drawable/image03" android:duration="500"/> </animation-list>
上述xml中,有些属性我们要了解到:
1、android:oneshot=“false”: 表示是否重复播放动画,还是只播放一次; 2、每个item都有Drawable和duration属性,Drawable表示我们要播放的图片;duration表示这张图播放的时间; 代码示例,第二步,用AnimationDrawable播放动画:
Button button = (Button) findViewById(R.id.bt_001); button.setBackgroundResource(R.drawable.frame_animation);//把Drawable设置为button的背景 //拿到这个我们定义的Drawable,实际也就是AnimationDrawable AnimationDrawable animationDrawable = (AnimationDrawable) button.getBackground(); animationDrawable.start();//开启动画 实际上,从名字也可以看出,AnimationDrawable是一个Drawable的子类,所以我们定义的xml文件也是防在res/rawable目录下的.
1.5.2、View动画(也称补间动画)
view动画也称为补间动画,因为我们只需要拿到一个view,设定它开始和结束的位置,中间的view会自动由系统补齐,而不需要帧动画每一幅图都是提前准备好的。
View动画是Android一开始就提供的比较原始的动画,主要支持四种效果:平移、缩放、旋转、透明度变化(渐变) 四种基本效果,我们可以再这四种基础效果的基础上,选择其中的几种进行组合。
根据动画效果,补间动画分为以下4类:
-
透明度动画(alpha)
-
缩放动画(scale)
-
平移动画(Translate)
-
旋转动画(rotate)
不同动画与Java类、xml文件关键字对应关系如下:
名称 | Java子类 | xml关键字 | 说明 |
---|---|---|---|
透明度动画 | AlphaAnimation | <alpha> 放置在res/anim/ 目录下 | 透明度渐变 |
旋转动画 | RotateAnimation | <rotate> 放置在res/anim/ 目录下 | 视图旋转 |
缩放动画 | ScaleAnimation | <scale> 放置在res/anim/ 目录下 | 放大/缩小 视图尺寸大小 |
平移动画 | TranslateAnimation | <translate> 放置在res/anim/ 目录下 | 视图位置移动 |
复合动画 | AnimationSet | <set> 放置在res/anim/ 目录下 | 一个持有其它动画元素alpha、scale、translate、rotate或者其它set元素的容器 |
1.5.3属性动画
属性动画可以看作是增强版的补间动画,与补间动画的不同之处体现在:
补间动画只能定义两个关键帧在透明、旋转、位移和倾斜这四个属性的变换,但是属性动画可以定义任何属性的变化。 补间动画只能对 UI 组件执行动画,但属性动画可以对任何对象执行动画。 与补间动画类似的是,属性动画也需要定义几个方面的属性:
动画持续时间。默认为 300ms,可以通过 android:duration 属性指定。 动画插值方式。通过 android:interploator 指定。 动画重复次数。通过 android:repeatCount 指定。 重复行为。通过 android:repeatMode 指定。 动画集。在属性资源文件中通过 <set …/> 来组合。 帧刷新率。指定多长时间播放一帧。默认为 10 ms。
属性动画 API
Animator: 提供创建属性动画的基类,基本不会直接使用这个类。 ValueAnimator:属性动画用到的主要的时间引擎,负责计算各个帧的属性值,基本上其他属性动画都会直接或间接继承它; ObjectAnimator: ValueAnimator 的子类,对指定对象的属性执行动画。 AnimatorSet:Animator 的子类,用于组合多个 Animator。 除了这些 API,属性动画还提供了一个 Evaluator ,用来控制属性动画如何计算属性值。
IntEvaluator:计算 int 类型属性值的计算器。 FloatEvaluator: 用于计算 float 类型属性值的计算器。 ArgbEvaluator: 用于计算十六进制形式表示的颜色值的计算器。 TypeEvaluator: 可以自定义计算器。 使用 ValueAnimator 创建动画的步骤:
调用 ValueAnimator 的 ofInt()、ofFloat() 或者 ofObject() 静态方法创建 ValueAnimator 实例。 调用 ValueAnimator 的 setXxx() 等方法设置持续时间,插值方式、重复次数等。 调用 ValueAnimator 的 start() 方法启动动画。 为 ValueAnimator 注册 AnimatorUpdateListener 监听器,在该监听器中可以监听 ValueAnimator 计算出来的值改变,并将这些值应用到指定对象上。
属性动画的一般使用:
定义属性动画和补间动画等类似,有两种方式:
使用 ValueAnimator 或者 ObjectAnimator 的静态工厂方法创建动画。 使用资源文件来定义动画。 属性动画的使用:
创建 ValueAnimator 或 ObjectAnimator 对象 —— 即可以从 XML 资源文件加载该动画也可以直接调用 ValueAnimator 或者 ObjectAnimator 的静态工厂方法创建动画。 根据需要为 Animator 对象设置属性。 如果需要监听 Animator 的动画开始事件,动画结束事件、动画重复事件、动画值改变事件,并根据事件提供响应处理代码,需要为Animator 对象设置监听器。 如果有多个动画需要同时播放,需要使用 AnimatorSet 组合这些动画。 调用 Animator 对象的 start 启动动画。