【
Android四大组件之一
主要用于与用户进行交互,在一个App中可能存在零个或多个Activity
】
【
Activity创建:
创建的步骤:
1) 定义一个类,继承自Activity
2) 在清单文件中进行注册(先注册,后使用)
Android的四大组件都必须要在清单文件中进行注册
思考:
1) 当在AndroidManifest.xml清单文件中,如果不设置默认启动页,会报错吗?
答:不会报错,但是App就没有启动页面
2) 当在AndroidManifest.xml清单文件中,设置多个页面都是默认启动页,会报错吗?如果不报错,到底是执行哪个页面呢?
答:不会报错,如果设置了多个启动页面,那么在程序图标的列表中就会生成多个启动图标, 点击不同的启动图标都可以开启应用程序,进入对应的页面。
】
【
Acitivity的启动
需要使用到Intent类,Intent不是Android四大组件之一,Intent,意图,主要用于Android三大组件之间的通讯,是三大组件的桥梁。
PS:这里的三大组件是Activity、Service、BroadcastReceiver
Activity的关闭
1) finnish方法
2)点击返回按钮(返回按钮的点击事件默认就是关闭当前的Activity,这个点击事件是可以修改的。
】
Context.startActivity(Intent)
【
一个Android应用程序可以包含零或多个Activity,当应用程序具有多个Activity时,就可能需要从一个Activity跳转到另一个Activity。在Android中,Activity之间的导航是通过Intent(意图)来完成
Intent并不是Andorid应用的组件,但它是各组件之间通信的载体
Intent不仅仅可以用于同一个App内来传递“意图”,也可以跨App
==Context,上下文环境(在这里就是指应用程序环境,封装了当前应用程序的一些相关信息)
】
【
显示意图:需要明确指定需要启动的组件名称
new Intent(Context, Class)
intent.setClass(Context, Class)
intent.setClassName(Context, StringclassName)
intent.setClassName(String packageName,String className)
intent.setComponent(ComponentNamecomponent)
intent.setClass(this,SecondActivity.class);
startActivity(intent);
】
【
// 显示意图的演示,需要明确指定开启的组件的类名
publicvoidopen03(View v) {
// 如果使用的是显示意图,那么启动组件的时候就不会去使用意图过滤器过滤
Intent intent =newIntent();
// 设置组件的信息
// 这里要注意:设置组件信息的api有很多,其实都是大同小异的
// intent.setClass(this, SecondActivity.class);
// intent.setClassName(this,"com.example.day06.activitybasic.SecondActivity");
// intent.setClassName(this.getPackageName(),"com.example.day06.activitybasic.SecondActivity");
ComponentName component =newComponentName(this, SecondActivity.class);
intent.setComponent(component);
startActivity(intent);
}
】
【
隐式意图不需要明确指定需要启动的组件的名称,只需要给定启动的组件的相关信息
所谓的相关系,比如:打电话、上网、发邮件
Intent.setAction(String)// action是一个任意的字符串,但是一般以包名.intent.行为命名,比如com.qianfeng.demo.intent.hit
Intent.setData(Uri)
Intent.addCategory(String)// 自定义的一般都是default类型,default类型可以不单独设置(默认)
intent.setAction(String action) //
new Intent(String action)
new Intent(String action, Uri uri)
Intent intent = new Intent()
intent.setAction(String action)
intent.setData(Uriuri)
intent.setAction(String action)
intent.setData(Uri uri)
意图过滤器:
action
Action代表该Intent所要完成的一个抽象“动作”
一个Intent对象最多包含一个action
一个Activity可以定义多个action
Android本身提供了很多action供开发者使用
Action代表该Intent所要完成的一个抽象“动作”
一个Intent对象最多包含一个action
一个Activity可以定义多个action
Android本身提供了很多action供开发者使用
为Activity增加额外的附加类别信息
为Activity增加额外的附加类别信息
data
声明数据的类型(mimeType)、约束(scheme)、主机名(host)、端口(port)、路径(path)等
声明数据的类型(mimeType)、约束(scheme)、主机名(host)、端口(port)、路径(path)等
应用场景:开启别的应用程序中的界面,系统需要查询匹配的Activity,效率较低
】
【示例1:打开拨号界面
publicvoidopen01(View v) {
Intentintent =newIntent();
//如果使用的是隐式意图,那么在意图中就保存相关的信息(就是想做什么事情)
//打篮球(动作+数据)
//动作
intent.setAction(Intent.ACTION_DIAL);
//url:统一资源定位符http://www.baidu.com
//uri:统一资源标识符tel://110 person://zhangsan
intent.setData(Uri.parse("tel://110"));
//开启一个界面,完成指定的操作
startActivity(intent);
}
示例二:自定义隐式视图及过滤器
android:name="com.example.day06.activitybasic.SecondActivity"
android:label="界面2">
那么系统就会找到系统中的各个组件对用的意图过滤器,
然后进行过滤,如果过滤通过就会开启这个组件 -->
<actionandroid:name="com.example.day06.activitybasic.inetnt.hit"/>
<categoryandroid:name="android.intent.category.DEFAULT"/>
<dataandroid:scheme="person"/>
android:name="com.example.day06.activitybasic.ThirdActivity"
android:label="界面3">
"com.example.day06.activitybasic.inetnt.hit"/>
"android.intent.category.DEFAULT"/>
"person"/>
注意:两个Activity设置了两个同样的过滤器
//开启自己的隐式意图,不需要指定Activity的类名
publicvoidopen02(View v){
Intent intent =newIntent();
//设置action
intent.setAction("com.example.day06activity01.inetnt.hit");
//设置类型(如果是默认的,可以不设置)
//intent.addCategory(Intent.CATEGORY_DEFAULT);
//设置Date
intent.setData(Uri.parse("person://zhangsan"));
}
效果图:
】
1、显示意图:必须指定要激活的组件的完整包名和类名
(应用程序之间耦合在一起,一般是在激活自己应用中的组件时使用显示意图。
效率较高)
2、隐式意图:只需要指定执行的动作和数据就可以
(好处:应用程序之间没有耦合。一般在激活其他应用中的组件时使用隐式意图。
缺点:效率较低)
程序设计原则:高内聚、低耦合。
什么时候使用这两个Intent?
一般情况下,在开启同一个应用程序内部的组件会使用显示意图,相反,如果要开启其他应用程序中的组件,一般使用隐式意图。
】
【
1、Intent.setData(Uri)——> intent.getData():传递简单的文本数据,// 传递Uri对象(实际上就是一个字符串)
2、putExtra(name ,value)——> getXXXExtra()//传递额外数据
通过该方法可以传递以下数据类型:
八种基本数据类型
数组
字符串
序列化对象
(在Android中有两个序列化接口:
A)Serializable接口: JDK自带的接口,使用方式很简单,只需要让自定义类实现Serializable接口即可。
b)Parcelable接口,Android SDK提供的接口
相对于Serializable接口,序列化和反序列化的效率更高,是Android推荐使用的,但是序列化和反序列的部分操作需要程序员自己完成
Bundle对象,就是一个容器,操作和Map集合类似,是以键值对的方式存储
3、putExtras(Bundle extras)——> getExtras():可以传递一组数据(Map集合)
4、putXXXArrayListExtra传递ArrayList对象
】
【
快捷键:ctrl+shift+o 优化导包
开启Activity并获取返回值
实现步骤:
1)在Activity01中调用startActivityForResult(inetnt,requestCode)方法,开启一个指定的Activity
intent:意图对象,用于开启指定的Activity
requestCode:请求码,用于区分被开启的Activity
2)在Activity02中通过setResult(resultCode,intent)方法设置返回结果
resultCode:返回码,用于表示返回值的状态(操作成功:Activity.RESULT_OK)
intent:意图对象,用于封装返回结果
设置完结果之后关闭Activity02,当Ativity02被关闭后会自动将结果返回给开启他的组件(Activty01)
3)在Activity01中改写onActivityResult(intrequestCode, int resultCode, Intent data)方法,用于处理返回结果
requestCode,请求码
resultCode,返回码(结果码)
data,Intent对象,封装了返回的数据
注意:在处理结果的时候通常都需要先对请求码和返回码进行判断
if(requestCode== REQUEST_CAL_WEIGHT && resultCode == RESULT_OK) {
}
】
【
概念:当新的Activity结束或返回上一个Activity时,需要返回一些结果,此时就需要设置并处理Activity的返回值。
1)startActivityForResult(Intentintent) // 开启ActivityB
2)getIntent()// 在ActivityB中获取来自ActivityA的Intent对象
3)setResult(intresultCode, Intent data) // 设置返回值(返回码 + 数据)
4)finish() // 关闭ActivityB并将结果返回给ActivityA
5)onActivityResult(intrequstCode, int resultCode, Intent data) // 在ActivityA中处理来自ActivityB的返回值
请求码和返回码
请求码:用于区分开启的Activity
返回码:用于标记结果返回的状态
Activity.RESULT_CANCELED
Activity.RESULT_OK
Activity.RESULT_FIRST_USER
请求码:用于区分开启的Activity
返回码:用于标记结果返回的状态
Activity.RESULT_CANCELED
Activity.RESULT_OK
Activity.RESULT_FIRST_USER
】
【
publicvoidopenClick(View v) {
//开启计算体重的界面
Intentintent =newIntent(this, CalWeightActivity.class);
//开启一个Activity,开启之后就没有关联了
// startActivity(intent);
//开启一个Activity,并且获取Activity的返回值
//参数:requestCode,请求码,用于区分被开启的Activity
startActivityForResult(intent,REQUEST_CAL_WEIGHT);
}
/**
* 当被开启的Activity返回结果时调用
* 参数1:requestCode,请求码
* 参数2:resultCode,返回码(结果码)
* 参数3:data,Intent对象,封装了返回的数据
*/
protectedvoidonActivityResult(intrequestCode,intresultCode, Intent data) {
if(requestCode ==REQUEST_CAL_WEIGHT&& resultCode ==RESULT_OK) {
if(data !=null) {
doubleweight = data.getDoubleExtra("weight", -1);
tv_show.setText(weight +"");
}
}
}
/*
* 设置返回结果
* 注意:这个方法只是用于设置返回值,当调用完以后不会直接将结果返回,
* 而是要等到当前的Activity被关闭之后才会自动将结果返回
*
* 参数1:resultCode,返回码,用于表示返回值的状态
* 参数2:Intent,意图对象,在这里的Intent只是用于Activity之间的数据传递,
* 不是用于开启某个组件,所以不需要包含任何组件的信息
*/
Intent intent =newIntent();
intent.putExtra("weight", weiht);
setResult(Activity.RESULT_OK,intent);
finish();//关闭当前的Acitivity,,将结果返回给
】
【
Activity生命周期的7个相关方法
onCreate(): 当Activity第一次被创建时被调用
onStart(): 当Activity可见时被调用
onResume(): 当Activity获取焦点时被调用
onPause():当Activity失去焦点时被调用
onStop(): 当Activity不可见时被调用
onDestroy(): 当Activity被销毁时被调用
onRestart(): 当Activity重新可见时被调用
各生命周期回调方法的使用场景
onCreate()、onDestroy——> 界面退出之前的数据保存,如:短信草稿
onStart()、onStop()——> 更新UI的操作,如:视频播放、暂停,在Activity可见和不可见时调用
onResume()、onPause()——> 取消界面上的焦点,如:暂停游戏,在Activity是在获取和失去焦点时调用
onRestart(): 当Activity重新可见时被调用,从Activity不可见重新到可见时调用
Activity生命周期的三个状态
Resumed: 运行状态,位于前台,可与用户进行交互
Paused: 另一个Avtivity位于前台,本Activity还可见,但是不可交互
Stoped: 另一个Activity位于前台,完全遮挡本Activity
Activity的三种生命周期
完整生命周期:onCreate—> onStart —>onResume —> onPause —> onStop —> onDestroy
可视生命周期: onStart —> onResume —> onPause —> onStop
前台生命周期: onResume —> onPause
思考题:
1、 当前有一个Activity在前台,当点击返回()
返回:onPause():当Activity失去焦点时被调用------onStop():不可见--------onDestroy()销毁
Home:onPause() :当Activity失去焦点时被调用------onStop():不可见
2、前台ActivityA,开启ActivityB?
A::onPause():当Activity失去焦点时被调用------onStop():不可见
B: onCreate —> onStart可见 —> onResume获取焦点
==Android系统内部有一个内存管理机制,进程是分等级的,当高等级的进程需要使用内存又不够用的时候,系统会自动杀死优先级较低的进程,将释放出来的内存分配给高优先级的进程,当系统中内存又够用的时候,系统会再自动将先前因内存不足被自动杀死的继承重新开启。
】
【Activity状态保存
在某些情况下,系统可能会对Activity进行重构(重新构建)
。。。。。。。。。。。。。
在Activity重构的时候,会导致数据丢失,Android系统提供了状态恢复机制用于保存Activity的状态。
1、在onSaveInstanceState(BundleoutState)中保存数据
2、在onCreate(BundlesavedInstanceState)恢复数据
或者在onRestoreInstanceState(BundlesavedInstanceState)中恢复数据
如果在横竖屏切换的时候不需要重构Activity,那么我们可以在清单文件中进行位置,配置方式如下:
android:configChanges="orientation|screenSize|keyboardHidden"
配置完属性后,就可以放置在横竖屏切换时重构Activity
ps:android:configChanges的作用就是 配置的属性值如果发生改变就不会导致Activity的重构,取而代之的是会调用onConfigurationChanged()方法1、在onSaveInstanceState(BundleoutState)中对数据进行保存,将数据保存在outState对象中
2、从Bundle对象中读取数据,读取数据后重新更新到界面
a)在onCreate(BundlesavedInstanceState)方法中进行恢复
注意:需要判断savedInstanceState是否为空
b)在onRestoreInstanceState(BundlesavedInstanceState)方法中进行恢复
注意:不需要判断savedInstanceState是否为空
】
【
public class MainActivity extends Activity{
privateTextView tv_num;
privateint num = 0;
@Override
protectedvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i("mtag","onCreate");
tv_num= (TextView) findViewById(R.id.tv_num);
/*
* 恢复数据
* 这里要注意的是,当Activity第一次其中时,是不存在数据恢复的情况,
* 所以,Bundle的引用是null
*/
// if(savedInstanceState!= null) {
// intnum = savedInstanceState.getInt("num");
// tv_num.setText(num+"");
// }
}
//当配置发生改变时调用
@Override
publicvoid onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Log.i("mtag","onConfigurationChanged");
if(newConfig.orientation== Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this,"横屏", 0).show();
}else if(newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
Toast.makeText(this,"竖屏", 0).show();
}
}
/**
* 当Activity自动重构时调用,主要用于恢复Activity中的数据
*/
@Override
protectedvoid onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
Log.i("mtag","onRestoreInstanceState");
intnum = savedInstanceState.getInt("num");
tv_num.setText(num+"");
}
/**
* 当Activity自动重构时调用,主要用于保存当前Activity的状态(内部的数据)
* 参数:outState,Bundle对象,是框架传入的一个对象,主要用户保存Activity中的数据
*/
@Override
protectedvoid onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.i("mtag","onSaveInstanceState");
//将数据保存在Bundle对象中
outState.putInt("num",num);
}
@Override
protectedvoid onDestroy() {
super.onDestroy();
Log.i("mtag","onDestroy");
}
publicvoid add(View v) {
//每次点击按钮之后都会加1
tv_num.setText((++num)+"");
}
}】
1.8 任务和后退栈(Task and Back Stack)
【
概念
任务(Task)
一个应用程序一般都是由多个Activity组成的,task就是多个 Activity的集合
后退栈(Back Stack)
就是一个保存和管理应用程序中所有Activity的容器
用户在进行操作时将与task中的Activity进行交互,这些Activity会按照启动顺序排队存入后退栈
Android为什么要引入任务和后退栈的概念?
在Windows下可以同时开启多个程序,并且可以在多个程序之间进行切换,在Andorid下也可以开启多个程序,可以通过长摁home键来查看开启的App,要实现在多个Activity之间进行切换,那么就要将已经打开的Activity保存在内存中,而Android系统是通过后退栈来存储已经开启的Activity,并记录他们开启的先后顺序。
】
【android:launchMode=""在清单文件中配置即可
standard: 默认的启动模式,每次启动Activity都会创建一个新的Activity实例
singleTop:如果Activity位于栈顶,则不再生成实例,而是调用onNewIntent()方法
singleTask:如果存在实例,则带至栈顶并销毁它上面所有的Activity
singleInstance:无论当前Activity是否是同一个App的,都只用一个实例
】