Android之应用程序基础
应用程序组件:
1.Activity --- 活动
2.Service --- 服务
3.Broadcast receiver --- 广播接收者
4.Content provider --- 内容提供者
Activity:几乎所有的活动都是与用户交互的,,所以Activity累关注创建窗口。
1.setContentView(View) 将自己的UI放到里面
2.活动通常以全屏的方式展示给用户,也可以以浮动窗口或嵌入在另外一个活动中。
有两个方法是几乎所有的Activity子类都实现的:
1.onCreate(Bundle):初始化Activity。
在这个方法里你通常将用布局资源(layout resource)调用setContentView(int)方法定义你的UI,
和用findViewById(int)在你的UI中检索你需要编程地交互的小部件(widgets)。setContentView指定由哪个文件指定布局(main.xml),
可以将这个界面显示出来,然后我们进行相关操作,我们的操作会被包装成为一个意图(Intent),然后这个意图对应有相关的activity进行处理。
2. onPause():处理当离开你的活动时要做的事情。最重要的是,用户做的所有改变应该在这里提交(通常ContentProvider保存数据)。
Service:一个服务没有一个可视化用户界面,而是在后台无期限地运行。
Activity组件: 简单的说,一个Activity就是一个界面 。
每个Activity都要在清单文件里注册 --- AndroidManifest.xml 清单文件的Application节点下配置
例:
<activity
android:name="com.example.application.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.example.application.PlayGame"></activity>
<intent-filter/>:在Launcher中显示的快捷方式 -- 程序的入口。
程序的入口只有Main一个,在main的界面进行某些操作点击按钮或超链接来启动另外一个Activity。
Activity生命周期:
void onCreate(Bundle saveInstanceState)
void onStart()
void onRestart()
void onResume()
void onPause()
void onStop()
void onDestroy()
活动的整个生命周期:
从第一次调用onCreate()开始知道调用onDestroy()结束。
onCreate() -- 所有“全局”状态的初始化设置,
onDestroy() -- 释放所有保留的资源。
例子:
有一个线程运行在后台从网络上下载数据,它可能会在onCreate()中创建线程,在onDestroy()中结束线程。
活动的可视生命周期:
从调用onStart()到调用onStop(),在这期间,用户可以在屏幕上看见Activity活动,虽然它可能不是运行在前台且与用户交互。
在这两个方法之间,你可以保持显示活动所需要的资源。举例来说,你可以在onStart()中注册一个广播接收者监视影响你的UI的改变,
在onStop() 中注销。因为活动在可视和隐藏之间来回切换,onStart()和onStop() 可以调用多次。
活动的前台生命周期:
从调用onResume()到相应的调用onPause(). 这期间频繁的在重用和暂停状态转换。
例如,当设备进入睡眠状态或一个新的活动启动时调用onPause(),当一个活动返回或一个新的意图被传输时调用onResume()。因此,这两个方法的代码应当是相当轻量级的。
转台转换 -- 参见 官方Activity的状态转换图
Activity的启动:
1.创建意图对象 --- Intent
2.Intent意图对象指定启动的Activity -- Intent(Context,Activity)
3.调用startActivity(Intent)
1.显示意图 -- 应用程序内跳转,需要指定类名。
例:
Intent intent=new Intent();//创建意图对象
intent.setClass(this, MainActivity.class);//指定类名
//intent.setClassName(this,"com.example.application.MainActivity");方法重载,作用同上
//intent.setClassName("com.abcde.sqlite","com.abcde.sqlite.ui.RefreshActivity");启动其他程序的Activity(包名+全类名)
startActivity(intent);//启动activity
2.隐式意图 -- 应用程序间跳转,不需要指定类名(创建快捷方式需要隐式意图)
例:
上网操作:
Intent intent = new Intent();
//设置动作
intent.setAction(Intent.ACTION_VIEW);
//设置数据
intent.setDataAndType(Uri.parse("HTTP://www.baidu.com");
//根据意图中的数据和动作匹配一个Activity -- 隐式意图
startActivity();
图片或视频:
将所要用的图片和视频烤到mnt的sdcard下,文件名不可有中文,否则无法导入
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file://mnt/sdcard/a.jpg"),"image/*");
intent.setDataAndType(Uri.parse("file://mnt/sdcard/1.mp3"),"audio/*");
intent.setDataAndType(Uri.parse("file://mnt/sdcard/1.mp4"),"vedio/*");
startActivity();
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)---将当前屏幕置为竖屏