《Android开发实战 从学习到产品》李瑞琪编著 学习笔记。
Android最常见四组件:Activity、Service、ContentProvider、BroadcastReceiver。
Activity:Android开发最重要的组件,Android应用程序界面,凡是在应用中能看到的东西都是放在Activity中的。
一、Activity生命周期
1、概述
Activityt由Activity栈进行管理,新Activity将被加到Activity栈顶,之前的Activity将位于该新Activity底部。Activity的四种状态:
- 当Activity位于栈顶,处于屏幕最前方,运行状态;
- 当Activity失去焦点但任对用户可见(栈顶Activity透明或未铺满屏幕等),暂停状态;
- 当Activity完全被其他Activity遮挡时,Activity对用户不可见,处于停止状态;
- 当Activity被人为或系统原因销毁,处于销毁状态。
开发过程中写的Activity一般都继承Activity类并重写相应的回调方法,Activity生命周期流程图如下:
由图知Activity生命周期的7个事件:
- onCreate():Activity第一次被创建时调用,可在此方法中绑定数据或创建其他视图控件。
- onStart():当Activity变为用户可见之前调用。
- onResume():当Activity可以与用户交互之前调用,即Activity对象到达Activity栈顶即将成为前台进程时调用。
- onPause():当系统调用其他Activity对象时调用(注:新Activity对象必须等待该方法执行完毕再显示出来,多数情况下onPause()方法要关闭onResume()中打开的方法)。
- onStop():当Activity不可视时调用。
- onDestroy():当销毁Activity对象时调用。
- onRestart():当处于onStop()状态的Activity又变为可视时调用。
除这些方法外,还有3个关键的周期循环:
- Activity的完整周期 从第一次调用onCreate(Bundle)设置所有“全局"状态及完成初始化开始,直至调用onDestroy()释放所有系统资源。
- Activity的可视生命周期 自onStart()调用开始至onStop()调用为止,用户屏幕可见此Activity。
- Activity前台生命周期 自onResume()调用起,至onPause()调用为止,该期间Activity位于前台最上面并与用户进行交互。
2、实例:
package com.example.day0907_lifeactivity;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
protected void onDestroy(){
super.onDestroy();
Log.i("LifeActivity","onDestroy");
}
protected void onPause(){
super.onPause();
Log.i("LifeActivity","onPause");
}
protected void onResume(){
super.onResume();
Log.i("LifeActivity","onResume");
}
protected void onRestart(){
super.onRestart();
Log.i("LifeActivity","onRestart");
}
protected void onStart(){
super.onStart();
Log.i("LifeActivity","onStart");
}
protected void onStop(){
super.onStop();
Log.i("LifeActivity","onStop");
}
/*onWindowFocusChanged()方法:在Activity窗口获得或失去焦点时被调动
(在onResume()之后或onPause()之后调用)*/
public void onWindowFocusChanged(boolean hasFocus){
super.onWindowFocusChanged(hasFocus);
Log.i("LifeActivity","onWindowFocusChanged");
}
/*在Activity被覆盖或退居后台之后,系统资源不足将其杀死时;用户改变屏幕方向;
当前Activity跳转到其他Activity或按Home键回到主屏,自身退居后台时 被调用
调用在onPause()之前*/
protected void onSaveInstanceState(Bundle outState){
Log.i("LifeActivity","onSaveInstanceState");
super.onSaveInstanceState(outState);
}
/*当Activity被覆盖或局后台,系统资源不足将其杀死,然后用户又回到Activity时;
* 用户改变屏幕方向重建过程中 被调用。调用在onStart()之后*/
protected void onRestoreInstanceState(Bundle savedInstanceState){
Log.i("LifeActivity","onRestoreInstanceState");
super.onRestoreInstanceState(savedInstanceState);
}
}
点击Android Studio左下角logcat查看日志(设置查看日志level为info,关键字为LifeActivity):
(1).初次运行Activity时:系统调用onCreate和onStart后调用onResume,Activity进入运行状态。
(2).在模拟机上按Home键回主屏幕或跳转Activity:退居后台后,Activity窗口焦点发生变化,故先调用onWindowFocusChanged方法,再依次调用各个方法。
(3).重回原Activity:先调用onRestart方法使用户可见,再调用…
(4). 退出程序:最后调用的onDestroy方法销毁Activity。
(5).横屏:期间调用了一次onDestroy方法销毁Activity及onStart方法打开Activity,故调用了一次onSaveInstanceState方法保存临时数据,和一次onRestoreInstanceState方法恢复数据。
二、Intent与Activity之间的跳转
Intent:完成组件之间的通信。(此处仅介绍完成Activity间的通信),Intent应用场合主要三种:
①.启动一个Activity。
②.启动一个Service。
③.启动一个BroadCast。
当使用一个Intent进行组件通信时,需要先实例化一个Intent对象,此时需要设置Intent属性:
Action(要执行的动作):如ACTION_CALL表示拨打电话、ACTION_EDIT表示调用编辑器、ACTION_SYNC表示同步数据…
Data(执行动作所操作的数据):在Intent中使用指向数据的URI来表示。
Type(显示指定Intent数据类型):不同动作URI数据类型不同。
Category(执行动作的附加信息)
Component(指定Intent目标组件的类名称):通常Android根据Intent包含的上述等属性进行查找,若设置该属性则查找过程不需执行。
Extras(其他所有附加信息的集合):为组件提供扩展信息。
另外,使用Intent时根据是否明确指定Intent对象的接收者,分显示(即在构造Intent对象时就指定接受者)和隐式(在构造Intent对象时不指定接受者,Android需对其进行解析:查找AndroidManifest.xml文件中所有IntentFilter及其定义的Intent,找到最匹配的Intent【判断Intent的Action、Type、Category找到最匹配的Intent】)的Intent。
1.显式意图
要求必须知道被激活组件的包和class
在该项目内创建新Empty Activity(new->)取名为SecondaryActivity,在activity_secondary.xml内放置一个TextView控件编辑其text内容为“第二个Activity!”以作标记。
在activity_main.xml内放置一个Button按钮,使得单击跳转到SecondaryActivity界面,并在MainActivity.java内代码实现跳转功能:
package com.example.day0907_lifeactivity;
import android.content.Intent;
import androidx.appcompat.app.AppCompatActivity;
import android.view.View;
import android.os.Bundle;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//R类:将Android的资源文件存储为键值对的一个类(系统自建,勿改),findViewById获得View控件对象的方法
button = (Button)findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
public void onClick(android.view.View view){
//跳转到第二个Activity
gotoSecondaryActivity();
}
});
}
private void gotoSecondaryActivity(){
Intent toSecondary = new Intent(); //创建一个意图
toSecondary.setClass(this,SecondaryActivity.class);//指定跳转SecondaryActivity
toSecondary.putExtra("name","Ricky"); //设置传递字符串
toSecondary.putExtra("age",25); //设置传递int类型内容
//上述两行代码可改为如下代码 android中使用Bundle来共享变量
// Bundle bundle = new Bundle();
// bundle.putString("name","Ricky");
// bundle.putInt("age",25);
// toSecondary.putExtras(bundle);
startActivity(toSecondary);
}
}
在SecondaryActivity.java内代码接受数据:
package com.example.day0907_lifeactivity;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
public class SecondaryActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_secondary);
Intent intent_accept = getIntent(); //创建一个接收意图
Bundle bundle = intent_accept.getExtras(); //创建一个Bundle对象用于接收Intent数据
String name = bundle.getString("name"); //获取Intent的内容name
int age = bundle.getInt("age"); //获取Intent的内容age
Log.i("SencodaryActivity", name + " " + age);
}
}
程序效果图:
2.隐式意图
*可以不知道被激活组件的包和class,只通过指定action就进行跳转,如果一个Activity想要启动另一个应用的Activity就只能使用隐式意图。
3.带回调方法的意图
有时需定义在MainActivity中的某一控件启动SecondaryActivity并当SecondaryAActivity结束时返回给MainActivity一个执行结果。
4.跳转中对象参数的传递
在Android开发中,有时多个Activity之间需要进行对象的传递,使用Intent也可以完成这一功能。
MainActivity.java 内的gotoSecondaryActivity方法改为:
private void gotoSecondaryActivity(){
Intent toSecondary = new Intent(); //创建一个意图
toSecondary.setClass(this,SecondaryActivity.class);//指定跳转SecondaryActivity
Bundle bundle = new Bundle();
User user = new User();
user.setAge(25);
user.setName("Ricky");
bundle.putSerializable("user",user);
toSecondary.putExtras(bundle);
startActivity(toSecondary);
//startActivityForResult(toSecondary,RequestCode);//启动带请求码意图
}
SecondaryActivity.java 内的onCreate方法改为:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_secondary);
Intent intent = getIntent(); //创建接收意图
Bundle bundle = intent.getExtras();
User user = (User)bundle.get("user"); //???
Log.i("SecodaryActivity", user.getName()+" "+user.getAge());
}
则单击第一个Activity中按钮,日志显示为:
三、Activity启动模式
Task:以栈来管理Activity。
Activity四种启动模式:standard、singleTop、singleTask、singleInstance。
- standard:默认启动模式,若不指定launchMode属性,就会自动使用这种启动模式。
声明为这种启动模式的Activity可以被实例化多次,一个任务当中也可以包含多个Activity的实例。 - singleTop:在AndroidManifest.xml中配置的android:launchMode的属性为singleTop。singleTop模式,若要启动的Activity在当前任务中已存在,且处于栈顶的位置,则系统不会再创建一个该Activity实例,而是调用栈顶Activity的onNewIntent()方法。
例:若Task返回栈中有4个Activity:A-B-C-D,D位于栈顶,A位于栈底,若要求再启动仪一次D,若D启动模式为standard则系统再创建一个D实例,此栈内元素为A-B-C-D-D;若D启动模式为singleTop,系统直接调用D的onNewIntent()方法,此时栈内元素任为A-B-C-D。 - singleTask:该启动模式表示,系统会创建一个新任务,并将启动的Activity放入这个新任务的底部,但是若该任务中已经存在该Activity的实例,不会新创建该Activity的实例而是调用该Activity的onNewIntent()方法,故该启动模式下Activity在同一个任务中只会存在一个实例。
singleTask模式默认情况下只有启动其他应用程序的Activity才会创建一个新任务,启动自己程序中的Activity还是会使用相同的任务。
- singleInstance:singleInstance模式启动Activity会创建一个新的Task,这种Activity所在的Task中始终只会有一个Activity。通过这个Activity打开其他Activity会被放入别的任务当中。
standard模式是Android默认启动模式,可能造成多次启动问题,如用户手误多次点击一个跳转到新Activity按钮,系统会创建多个新Activity,而用户只需一个。singleTop模式可避免这个问题,该模式在启动Activity时,如果发现该返回栈中的栈顶已是该Activity时,就认为可以直接使用它而不会创建新的Activity实例。若要启动的Activity不在栈顶,还是会创建该Activity的实例。将启动模式设置为singleTask,每次启动Activity时系统首先在返回栈中检查是否有该Activity的实例,若有就直接使用该Activity的实例,并将这个Activity上的所有活动统统出栈,若没有就会创建一个新的Activity。而singleInstance模式的活动将会启用一个新的返回栈来管理这个活动,解决了多个应用访问一个Activity时的共享问题。