《Android第二章》探究活动
《Android第一行代码》书本记录
Activity(活动)是什么:
- 活动包含用户界面的组件,主要用于和用户进行交互,一个应用程序中可以包含零个或多个活动。
- 四大组件都要在Androidmanifest文件中注册,所以活动是四大组件之一要在里面进行注册。
Activity活动状态:
- 运行状态:当一个活动位于返回栈的栈顶时,这时活动就处于运行状态。系统最不愿意回收的就是处于运行状态的活动,因为这会带来非常差的用户体验。
- 暂停状态:当一个活动不再处于栈顶位置,但仍然可见时,这是活动就进入了暂停状态。处于暂停状态的活动仍然是完全活着的,系统也不愿意去回收这种活动,只有内存极低的情况下,系统才会去考虑回收这种活动。
- 停止状态:当一个活动不再处于栈顶位置,并且完全不可见的时候,就进入停止状态。系统仍然会为这种活动保存相应的状态和成员变量,但是这并不是完全可靠的,当其他地方需要内存时,处于停止状态的活动有可能被系统回收。
- 销毁状态:当一个活动从返回栈中移除后就变成了销毁状态。系统会最倾向于回收处于这种状态的活动,从而保证手机的内存充足。
Activity的生命周期:
- onCreate:活动第一次被创建的时候调用。应该在这个方法中完成活动的初始化操作,比如加载布局、绑定事件。
- onStart:这个方法在活动由不可见变为可见的时候调用。
- onResume:这个方法在活动准备好和用户进行交互的时候调用。此时的活动一定位于返回栈的栈顶,并且处于运行状态。
- onPause:这个方法在系统准备去启动或者恢复另一个活动的时候调用。我们通常会在这个方法中将一些消耗CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶活动的使用。
- onStop:这个方法在活动完全不可见的时候调用。它和onPause()方法的主要区别在于,如果启动的新活动是一个对话框式的活动,那么onPause()方法会得到执行,而onStop()方法并不会执行。
- onDestroy:这个方法在活动被销毁之前调用,之后活动的状态将变为销毁状态。
- onRestart:这个方法在活动由停止状态变为运行状态之前的调用,也就是活动被重新启动了
- 完整生命周期:在onCreate方法和onDestory方法之间所经历的,就是完整生存期期
- 可见生存期:活动在onStart方法和onStop方法之间所经历的,就是可见生存期。在可见生存期内,活动对于用户总是可见的,即便有可能无法和用户进行交互。可以通过这个两个方法,合理地管理那些对用户可见的资源。比如在onStart方法中对资源进行加载,而在onStop方法中对资源进行释放,从而保证处于停止状态的活动不会占用过多内存。
- 前台生存期:活动在onResume方法和onPause方法之间所经历的就是前台生存期。在前台生存期内,活动总是处于运行状态,此时的活动是可以和用户进行交互的,平时看到和接触最多的也就是这个状态下的活动.
Activity的启动模式:
- standard:标准模式,这是系统默认的默认,也就是说你不设置Activity的launchMode时,默认的就是standard。在这种模式下,每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否存在。在这种模式下,谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity所在的栈,但是这是有条件的,前提是启动它的Activity不能是singleInstance,因为singleInstance只能独立于一个任务栈中,不能有其他的Activity实例,这个后面我们会验证。比如非singleInstance模式的Activity A启动了标准模式的Activity B,那么Activity B就会进入到Activity A所在的任务栈。
- singleTop:栈顶复用模式。在这种模式下,如果Activity已经在任务栈的栈顶了,当再次启动同一个Activity的时候,这个Activity不会被重新创建,而且它的onNewIntent()方法会被调用,但是它的onCreate()、onStart()方法不会被调用。此模式下的Activity也会进入启动它的非singleInstance模式的Activity所在的任务栈中。
- singleTask:栈内复用模式。在这种模式下,只要Activity存在栈内,那么多次启动这个Activity都不会重新创建实例,系统会调用它的onNewIntent()方法。此外有个需要注意的地方:singleTask有clear top的效果,也就是说会将其以上的Activity全部出栈,直到singleTask模式的Activity到栈顶.
- singleInstance:这是singleTask的一种加强模式,除了singleTask所有特性以外,具有此模式的Activity只能单独位于一个任务栈中
Intent:
- Intent是Android程序中各组件之间进行交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据。Intent一般可用于启动活动、启动服务以及发送广播等场景。
- Intent的构造函数:Intent(Context packageContext,Class<?>cls),这个构造函数接收两个参数,第一个参数Context要求提供一个启动活动的上下文,第二个参数Class则是指定想要启动的目标活动,通过这个构造函数就可以构建出Intent的“意图”。然后通过Activity类中提供了一个startActivity()方法启动,这个方法专门用于启动活动的,它接收一个Intent参数,这里我们将构建好的Intent传入startActivity()方法就可以启动目标了:
-
1 Intent intetn=new Intent(FirstActivity.this,SecondActivity.class); 2 startActivity(intent);
- 显式Intent:像上面的例子意图非常明显,直接使用startActivity方法来跳转到另外一个活动称之为显示Intent.
- 隐式Intent:顾名思义,意图不明显的Intent,它并不明确指出我们想要启动哪一个活动,而是指定了一系列更为抽象的action和category等信息,然后交由系统去分析这个Intent,并帮我们找出合适的活动去启动:
-
通过<acticity>标签下配置<intent-filter>的内容,可以指定当前活动能够响应的action和category,打开AndroidManifest.xml,添加如下代码: <activity android:name=".MainActivity"> <intent-filter> <action adnroid:name="com.example.activitytest.ACTION_START"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </activity>
在<activity>标签中我们指明了当前活动可以响应com.example.activitytest.ACTION_START这个action,而<category>标签则包含了一些附加信息,
更精确地指明了当前的活动能够响应的Intent中还可能带有category。
只有<action>和<category>中的内容同时能够匹配上Intent中指定的action和category时,这个活动才能响应该Intent: Intent intent=new Intent("com.example.activitytest.ACTION_START"); startActivity(intent); 前面说要匹配<aciton>和<categroy>才能响应,但是为什么没有category呢?
因为是android.intent.category.DEFAULT是一种默认的category,在调用startactivity()方法的时候会自动将这个category添加到Intent中
更多隐式Intent的用法:
- 使用隐式Intent不仅可以启动程序内的活动,还可以启动其他程序的活动,这使得Android多个应用程序之间的功能共享成为了可能。比如说应用程序要打开一个网页,这时没必要自己去实现一个浏览器,而是只需要调用系统的浏览器来打开这个网页就可以了:
Intent intetn=new Intent(Intent.ACTION_VIEW); intent.setData(Uri.parse("http://www.baidu.com")); startActivity(intent); 首先指定了Intent的action是Intent.ACTION_VIEW,这是一个Android系统内置的动作,其常量为android.intent.action.VIEW.
然后通过uri.parse()方法,将一个网址字符串解析成一个Uri对象,再调用Intent的setData()方法将这个Uri对象传递进去.
- 上面setData()方法中的Uri:
主要用于接收Uri对象,主要用于指定当前Intent正在操作的数据,而这些数据通常都是以字符串的形式传到Uri.parse()方法中解析.
与此对应,可以在<intent-filter>标签中再配置一个<data>标签,用于更精确地指定当前活动能够响应什么类型数据。<data>标签中主要可以配置一下内容:
android: scheme。用于指定数据的协议部分,如上例中的http部分。
andoird:host。用于指定数据的主机名部分,如上例中的www.baidu.com部分.
android:port。用于指定数据的端口部分,一般紧随在主机名之后。
android:path。用于指定主机名和端口之后的部分,如一段网址中跟在域名之后的内容。
android:mimeType。用于指定可以处理的数据类型,允许使用通配符的方式进行指定android:scheme为http,就可以响应所有的http协议的Intent了.
在MainActvity的<intent-filter>标签中配置了当前活动能够响应的action是Intent.ACTION_VIEW的常量值,
而category指定了默认的category值,另外在<data>标签中我们通过android:scheme指定了数据的协议必须是http协议: <actvity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.DEFAULT"/> <data android:scheme="http"/> </intent-filter> </actvity> 这样MainActivity应该就和浏览器一样,能够响应一个打开网页的Intent了.
除了http协议外,还有其他协议,比如geo表示显示地理位置,tel表示拨打电话:
Intent intent=new Intent(Intent.ACTION_DIAL); intent.setData(Uri.parse("tel:10086")); startActivity(intent); Intent的action是Intent.ACTION_DIAL,这又是Android系统的内置动作。然后data部分指定了协议是tel,号码是10086,运行程序就会弹出拨打电话号码界面并且输入10086.
Intent活动之间传递数据
从FirstActivity活动传递到SecondActvity.class: String data="Hello SecondActivity"; Intent intent=new Intent(FirstActivity.this,SecondActivity.class); intent.putExtra("extra_data",data); startActivity(intent); 这里putExtra()方法接收两个参数,第一个参数是键,用于后面从Intent中取值,第二个参数才是真正要传递的数据。 然后从SecondActvity中取出数据: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); Intent intent=getIntent(); String data=intent.getStringExtra("extra_data"); }
首先通过getIntent()方法获取到用于启动的SecondActivity的Intent,然后调用getStringExtra()方法,
传入相应的键值,就可以获取到传递的数据了,如果数据是整数型就使用getIntExtra()方法以此类推
返回数据给上一个活动:
在当前活动按下back键就可以返回到上一个活动,想要获得传下来的数据,那么可以通过startActivityForResult()方法启动这个活动:
startActivityForResult()方法接收两个参数,第一个参数是Intent,第二个参数是请求码, 用于在之后的回调中判断数据的来源。 FirstActivity的活动通过startActivityForResult跳转到SecondActivity活动: Intent intent=new Intent(FirstActivity.this,SecondActivity.class); startActivityForResult(intent,1); 这里求码为1,这个请求码可以自己定
SecondActivity里加一个按钮,点击就执行一下代码:
Intent intent=new Intent();
intent.putExtra("data_return","Hello FirstActvity");
setResult(RESULT_OK,intent);
finish();
如果不想点击按钮返回到FirstActivity而是按返回键back,那么可以通过重写onBackPressed()方法来解决:
@Override
public void onBackPressed() {
super.onBackPressed();
Intent intent=new Intent();
intent.putExtra("data_return","Hello FirstActvity");
setResult(RESULT_OK,intent);//一般只使用RESULT_OK表示请求成功或RESULT_CANCELED
finish();}
注意:这里最后调用的finish()方法是销毁当前活动,但是与onDestroy不同,finsh方法只是把Activity移除栈,
资源占用的情况下并不会及时调用onDestroy()方法,若调用onDestroy方法则资源释放,那么就没有数据可以返回
最后一步是在FirstActivity里接收数据: @Override protected void onActivityReenter(int requestCode,int resultCode, Intent data) { super.onActivityReenter(resultCode, data); if(resultCode==RESULT_OK&&requestCode==1){ String returnedData=data.getStringExtra("data_return"); } } 在FirstActivity重写了onActivityReenter()方法,里面有三个参数,第一个参数requestCode就是我们在调用startActivityForResult()方法传入的1,
第二个参数则是resultCode,RESULT_OK表示请求成功,第三个参数是Intent,这就是我们从SecondActvitity传回来的数据Intent.

浙公网安备 33010602011771号