Android之Activity组件
一 、定义与创建
定义:简单的说,一个Activity就是一个界面
创建:定义类继承Activity,并在清单文件的Application节点下配置
1 <activity 2 android:name="com.example.application.MainActivity" 3 android:label="@string/app_name" > 4 <intent-filter> 5 <action android:name="android.intent.action.MAIN" /> 6 7 <category android:name="android.intent.category.LAUNCHER" /> 8 </intent-filter> 9 </activity> 10 <activity android:name="com.example.application.PlayGame"></activity>
<intent-filter/>:在Launcher中显示的快捷方式(程序的入口)
一个应用程序对应一个快捷方式即自定义的标签中不配置也可以,程序的入口只有Main一个,在main的界面进行某些操作点击按钮或超链接来启动另外一个Activity
二 、生命周期
一个活动有三个基本状态:
- 激活状态或运行状态,这时它运行在屏幕的前台(处于当前任务活动栈的最上面)。这个活动有用户的操作的焦点。
- 暂停状态,这时活动失去焦点但是它对用户仍可见。也就是说,另一个活动在它的上面且那个活动是透明的或者没有覆盖整个屏幕,因此通过它可以看见暂停状态的活动。一个暂停的活动完全是活着的(它维护着所有的状态和成员信息,且仍然依附在窗口管理器),但是当内存极小时可以被系统杀掉。
- 停止状态,这时活动完全被其他活动掩盖。它仍然保留所有状态和成员信息,但是对用户它不可见,因此它的窗口时隐藏的且当其他地方需要内存时它往往被系统杀掉。
如果一个活动被暂停或停止,系统可以将它从内存移除,通过要求它结束(通过调用它的finish()方法),或简单地杀掉它的进程。当它再次显示给用户时,必须要完全重新启动和恢复到之前的状态。随着活动从一个状态转为另一个状态,通过调用下面的受保护的方法通知该改变:
- void onCreate(Bundle saveInstanceState)
- void onStart()
- void onRestart()
- void onResume()
- void onPause()
- void onStop()
- void onDestroy()
所有这些方法都是钩子,你可以重写当状态改变时做适当的工作。所有的活动必须要实现onCreate()去做一些初始化的设置,当对象第一次实例化的时候。很多活动也会实现onPause()去提交数据修改或准备停止与用户交互。
将他们合并在一起,这七个方法定义了活动的整个生命周期。有三个嵌套的循环,你可以通过这七个方法监视:
- 活动的整个生命时间,从第一次调用onCreate()开始直到调用onDestroy()结束。一个活动在onCreate()中做所有的“全局”状态的初始设置,在onDestroy()中释放所有保留的资源。举例来说,有一个线程运行在后台从网络上下载数据,它可能会在onCreate()中创建线程,在onDestroy()中结束线程。
- 活动的可视生命时间,从调用onStart()到相应的调用onStop() 。在这期间,用户可以在屏幕上看见活动,虽然它可能不是运行在前台且与用户交互。在这两个方法之间,你可以保持显示活动所需要的资源。举例来说,你可以在onStart()中注册一个广播接收者监视影响你的UI的改变,在onStop() 中注销。因为活动在可视和隐藏之间来回切换,onStart()和onStop() 可以调用多次。
- 活动的前台生命时间,从调用onResume()到相应的调用onPause()。在这期间,频繁地在重用和暂停状态转换——例如,当设备进入睡眠状态或一个新的活动启动时调用onPause(),当一个活动返回或一个新的意图被传输时调用onResume()。因此,这两个方法的代码应当是相当轻量级的。
下面这个图解释了这三个循环和状态之间状态的可能路径。着色的椭圆表示活动的主要状态,矩形表示当活动在状态之间转换时你可以执行的回调方法。
三 、Activity的启动
启动Activity:创建意图对象Intent,直接调用startActivity()方法,intent可以启动指定的activity
启动方式:
a、显示意图(Explicit) ----应用程序内跳转,需要指定类名
1 Intent intent=new Intent();//创建意图对象 2 intent.setClass(this, MainActivity.class);//指定类名 3 //intent.setClassName(this,"com.example.application.MainActivity");方法重载,作用同上 4 //intent.setClassName("com.abcde.sqlite","com.abcde.sqlite.ui.RefreshActivity");启动其他程序的Activity(包名+全类名) 5 startActivity(intent);//启动activity
b隐式意图(Implicit)---应用程序间跳转,不需指定类名(创建快捷方式需用隐式意图)
上网操作 :
1 Intent intent=new Intent(); 2 intent.setAction(Intent.ACTION_VIEW);//设置动作 3 intent.setData(Uri.parse("HTTP://www.baidu.com"));//设置数据 4 startActivity(intent);//根据意图中的数据和动作匹配一个Activity
图片或视频:
将所要用的图片和视频烤到mnt的sdcard下,文件名不可有中文,否则无法导入
1 Intent intent=new Intent(); 2 intent.setAction(Intent.ACTION_VIEW); 3 intent.setDataAndType(Uri.parse("file:///mnt/sdcard/a.jpg"),"image/*");//图片 4 intent.setDataAndType(Uri.parse("file:///mnt/sdcrad/1.mp3"),"audio/*");//音乐 5 intent.setDataAndType(Uri.parse("file:///mnt/sdcard/1.mp4"),"vedio/*");//视频 6 startActivity(intent);
四 、Activity之间的数据传递
可传递的数据类型:
基本数据类型,String,Bundle,Serializable,Parcelable---- 点击按钮或者链接通过intent带数据到另一个界面(intent中带有bundle,用来存储数据,类似Mapj集合)
案例:在MainActivity中发送数据,在OtherActivity中获取数据
启动时传递数据:
- 在MainActivity中创建intent对象,利用intent对象通过putExtra()方法向intent中放数据,然后开启Activity;
- 若所放的参数为javabean(person类),则需要person类实现Serializable这个接口,这样就可以放入intent中。因为是一个应用程序,两个activity 之间的跳转,一个应用程序(一个进程)之内的对象传输数据是可以的,但是activity的跳转,有可能从一个程序跳到另一个程序,也许另一个程序都没有person类,两个应用程序之间是不可以传输对象的,应用程序之间传数据只能是字节数据,不能是对象,而实现序列化后,可以把对象转为字节数组这样就可以传输,所以说要传输自定义类对象,要实现Serializable接口;若传入的为集合,List<Person>集合默认实现了,但是必须保证集合中的元素也要实现
- 在OtherActivity中通过getIntent()方法获得intent, 通过intent的getStringExtra()或者getIntExtra()方法获得数据
- Parcelable类(后期绑定服务一定会用到,绑定服务会传参数,参数必须是Parcelable),Person类实现Parcelable这个接口,并添加两个未实现的方法
1 public void writeToParcel(Parcel parcel,int flags){------定义怎么把该类对象写入Parcel 2 parcel.writeString(name); 3 parcel.writeInt(age); 4 }
关闭时返回数据:
如果希望新的Activity可以返回数据, 那么就需要使用startActivityForResult()方法来启动Activity在新的Activity中调用setReuslt()方法设置要返回的数据
finish()之后, 原Activity会自动调用onActivityResult(), 该方法的形参就是setReuslt()设置的数据
五 、启动模式
有四种不同的启动模式可以分配到<activity>元素的launchMody
属性:
- "standard"(默认模式)
- "singleTop "
- "singleTask"
- "singleInstance"
这些模式的在以下四方面不同:
- 哪个任务将持有响应意图(intent)的活动。对"standard"和"singleTop "模式,是产生意图的任务(调用startActivity()方法)——除非Intent对象包含
FLAG_ACTIVITY_NEW_TASK
标志。在那种情况下,像上一节亲和度和新任务(Affinities and new tasks)所描述的那样选择一个不同的任务。
相反,"singleTask"和"singleInstance"模式,总是将活动标记为一个任务的根活动。他们定义一个任务,而从不启动到其他任务。 - 活动是否可以实例化多次。"standard"或"singleTop "活动可以实例化多次。这些实例可以属于多个任务,且一个给定任务可以包含同一个活动的多个实例。
相反,"singleTask"和"singleInstance"活动仅可以被实例化一次。因为这些活动是一个任务的根,这个限制意味着设备上一个时间只有不多于一个任务的实例。 - 是否允许实例所在任务有其他活动。"singleInstance"活动所在任务只有它一个活动。如果他启动别的活动,那些活动将启动到不同的任务中,无论它的模式如何——就好像Intent对象包含
FLAG_ACTIVITY_NEW_TASK
标志。在所有其他方面,"singleInstance"模式等同于"singleTask"模式。
其它三种模式允许多个活动属于一个任务。"singleTask"活动总是任务的根活动,但是它能启动其他活动到它的任务。"standard"或"singleTop "活动的实例可以出现的栈中的任何位置。 - 响应一个意图时是否需要生成类的新实例。对于默认的"standard"模式,创建新的实例去响应每一个新的意图。每个实例仅处理一个意图。对于"singleTop "模式,一个类已存在的实例可以重新用了处理新的意图,如果它位于目标任务的活动栈的栈顶。如果不是在栈顶,就不可以重用。相反,将创建一个新的实例并压入栈顶。
例如,一个任务的活动栈由根活动A、B、C和D组成,顺序为A-B-C-D。当一个意图到达请求类型D时,如果D是默认的"standard"模式,将产生D类的新实例且栈变为A-B-C-D-D。然而,如果D的启动模式是"singleTop ",已存在的D实例将去处理新的意图(因为它在栈顶)且栈仍然是A-B-C-D。
如果,另一方面,到达的意图是请求类型B时,一个B的新实例将启动而不管B的模式是"standard"还是"singleTop "(因为B不是在栈顶),因此栈的结构为A-B-C-D-B。
如前所述,"singleTask"和"singleInstance"活动仅可以被实例化一次,因此他们的实例将处理所有的新意图。一个"singleInstance"活动总是在栈顶(因为仅有一个活动在任务中),因此它总是在可以处理意图的位置。然而,一个"singleTask"活动在栈中可能有或可能没有其他活动在它上面。如果有,即它不在处理意图的位置,意图会被丢弃(即使意图被丢弃了,它的到来使任务转到并保持在前台运行)
当一个已存在的活动被请求处理一个新的意图,Intent对象将通过onNewIntent()调用传到活动。(产生启动活动的意图对象可以由getIntent()获取。)
注意到当一个活动的新实例被创建去处理新意图时,用户总是可以按返回键返回到之前的状态(之前的活动)。但是当一个已存在的活动实例去处理新意图是,用户不可以按返回键返回到意图到达之前的状态。
六、 横竖屏切换
a.默认情况下, 横竖屏切换时会摧毁Activity重构, 因为要进行屏幕适配.
R文件下创建布局文件layout-port(竖屏,指定线性布局,垂直)和layout-land(横屏,指定线性布局,水平),横竖屏切换时控件会随之变化
横竖屏切换和杀死重建文件都需要保存和还原数据:
onSaveInstanceState()在摧毁时自动执行保存数据---onPause()之后onStop()之前执行(两者之间)
onRestoreInstanceState()在恢复的时候自动执行还原数据---onStart()之后onResume()之前执行(两者之间)
被杀死之后再启动才会恢复数据,数据是存在Bundle里的,Bundle是以文件形式存储的,程序再启动时会读取文件,以达到恢复数据的目的
onSaveInstanceState()在Activity失去焦点时也会被调用, 如果Activity在后台被杀死了, 再次启动时会自动调用onRestoreInstanceState()
b.如果不需要屏幕适配, 那么可以通过定义属性控制Activity不摧毁重构
android:configChanges="orientation|screenSize" 这种情况下不执行任何生命周期方法, 也不会改变布局
c.固定Activity方向---屏幕不随手机转动而改变
android:screenOrientation="portrait"---固定屏幕方向指定竖屏
android:screenOrientation="landscape"---固定屏幕方向指定横屏
android:screenOrientation="sensorLandscape"---两个横屏之间的切换
android:screenOrientation="Portrait"----两个竖屏之间的切换
在这种情况下, Activity不会摧毁重构, 也不会改变方向
d.用代码控制横竖屏的方向---通过点击按钮改变屏幕方向或者获取当前屏幕的方向
getResources().getConfiguration().orientation
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)---将当前屏幕置为横屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)---将当前屏幕置为竖屏