目录
2. Activity / ActionBarActivity / AppCompatActivity 的区别
1. 什么是Activity
Activity 是一个应用组件,用户可与其提供的屏幕进行交互,以执行拨打电话、拍摄照片、发送电子邮件或查看地图等操作
Activity 用于显示用户界面,用户通过 Activity 交互完成相关操作
每个 Activity 都会获得一个用于绘制其用户界面的窗口
2. Activity / ActionBarActivity / AppCompatActivity 的区别
-
ActionBarActivity 和 AppCompatActivity 都是为了低版本兼容而提出的提出来的,他们都在 v7 包下
-
ActionBarActivity 已被废弃,在 5.0+ 版本弃用了,可以使用 ToolBar 代替
-
Android Studio 创建一个 Activity 默认继承的是:AppCompatActivity
3. Activity 的创建流程
-
自定义
Activity
类名,继承Activity
类或者其它子类,比如AppCompatActivity
class MainActivity extends AppCompatActivity
-
重写
onCreate()
方法,然后在该方法中调用setContentView()
设置要显示的视图@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 设置显示的试图 }
-
在
AndroidManifest.xml
中对Activity
进行注册和配置<activity android:icon="图标" android:name="类名" android:label="Activity 要显示的标题" android:theme="要应用的主题" > </activity>
-
调用
startActivity(Intent)
启动Activity
Intent it = new Intent(MainActivity.this, MsActivity.class); startActivity(it);
-
调用
finish()
直接关闭当前Activity
finish();
其实我们可以把它写到启动第二个
Activity
的方法中,当启动了第二个Activity
时就会关闭第一个Activity
4. Activity生命周期
4.1 Activity的四种基本状态:
Active/Running: Activity处于活动状态,此时Activity处于栈顶,是可见状态,可与用户进行交互。
Paused: 当Activity失去焦点时,或被一个新的非全屏的Activity,或被一个透明的Activity放置在栈顶时,Activity就转化为Paused状态。但我们需要明白,此时Activity只是失去了与用户交互的能力,其所有的状态信息及其成员变量都还存在,只有在系统内存紧张的情况下,才有可能被系统回收掉。
Stopped: 当一个Activity被另一个Activity完全覆盖时,被覆盖的Activity就会进入Stopped状态,此时它不再可见,但是跟Paused状态一样保持着其所有状态信息及其成员变量。
Killed: 当Activity被系统回收掉时,Activity就处于Killed状态。 Activity会在以上四种形态中相互切换,至于如何切换,这因用户的操作不同而异。
对于activity生命周期中各个方法,需要记住他们是成对出现的
onCreate | 只在activity被创建时调用一次,表示正在被创建,一些初始化工作在这里(加载布局资源,初始化所需要的数据等),如果有耗时任务需开异步线程去完成。 |
onStart | Activity正在被启动,在这个状态下Activity还在加载其他资源,正在向我们展示,用户还无法看到,不能交互 |
onResume | Activity创建完成,用户可看见界面,可交互 |
onPause | Activity正在暂停,正常情况下接着会执行onStop()。这时可以做数据的存储、动画停止的操作,但是不能太耗时,要不然影响新Activity的创建 |
onStop | Activity即将停止,这时可以做一些回收工作,一样不能太耗时 |
onDestory | Activity即将被销毁,可以做一些工作和资源的回收(Service、BroadCastReceiver、Map、Bitmap回收等) |
onRestart | Activity正在重新启动,一般时当前Activity从不可见到可见状态时会执行这个方法,例如:用户按下Home键(锁屏)或者打开新Activity再返回这个Activity |
4.2 activity生命周期中各个相邻状态之间的区别:
1. onCreate和onStart之间有什么区别?
(1)可见与不可见的区别。前者不可见,后者可见。
(2)执行次数的区别。onCreate方法只在Activity创建时执行一次,而onStart方法在Activity的切换以及按Home键返回桌面再切回应用的过程中被多次调用。因此Bundle数据的恢复在onStart中进行比onCreate中执行更合适。
(3)onCreate能做的事onStart其实都能做,但是onstart能做的事onCreate却未必适合做。如:setContentView和资源初始化在两者都能做,然而想动画的初始化在onStart中做比较好。
2.onStart方法 和 onResume 方法有什么区别?
(1)是否在前台。onStart方法中Activity可见但不在前台,不可交互,而在onResume中在前台。
(2)职责不同,onStart方法中主要还是进行初始化工作,而onResume方法,根据官方的建议,可以做开启动画和独占设备的操作。这里所谓的前台并不是我们日常所说的前台任务的那个前台, 这里的前台指: 能否与用户产生交互
3.onPause方法和onStop方法有什么区别?
(1)是否可见。onPause时Activity可见,onStop时Activity不可见,但 Activity对象还在内存中。
(2)在系统内存不足的时候可能不会执行onStop方法,因此程序状态的保存、独占设备和动画的关闭、以及一些数据的保存最好在onPause中进行,但要注意不能太耗时。
4.onStop方法和onDestroy方法有什么区别?
onStop阶段Activity还没有被销毁,对象还在内存中,此时可以通过切换Activity再次回到该Activity,而onDestroy阶段Acivity被销毁
4.3 按键对生命周期的影响:
1. BACK键:
这个应用程序将结束,这时候我们将先后调用 onPause()->onStop()->onDestory() 三个方法。
再次启动App时,会执行 onCreate()->onStart()->onResume()
2. HOME键:
当我们打开应用程序时,比如浏览器,我正在浏览NBA新闻,看到一半时,我突然想听歌,这时候我们会选择按HOME键,然后去打开音乐应用程序
当我们按HOME的时候,Activity先后执行了 onPause()->onStop() 这两个方法,这时候应用程序并没有销毁。
当我们从桌面再次启动应用程序时,则先后分别执行了 onRestart()->onStart()->onResume() 三个方法。
Activity切换的生命周期:
1.从启动ActivityA 进入到ActivityB的生命周期走向:
ActivityA 的生命周期onPause()---------------------------------->onStop(),
ActivityB的生命周期onCreate() -> onStart()->onResume()。
当ActivityA启动ActivityB时,执行到onPause()时,并没有立即执行onStop();
而是先执行ActivityB 的相应方法,直到ActivityB 的onResume()执行完毕,也就是ActivityB启动成功后,才调用自身的onStop()
2.从ActivityB 返回到ActivityA时的生命周期走向
ActivityB的生命周期 onPause()->onStop()->onDestory()
ActivityA的生命周期了从onStop()开始,onRestart()->onStart()->onResume()
ActivityA执行完 onResume(), ActivityB才开始执行 onStop()->onDestory()
5. Activity 的4种加载模式
Activity的启动模式:(面试注意)
Activity有四种启动模式:standard、singleTop、singleTask、singleInstance。可以在AndroidManifest.xml中activity标签的属性android:launchMode中设置该activity的加载模式。
- standard模式:默认的模式,以这种模式加载时,每当启动一个新的活动,必定会构造一个新的Activity实例放到返回栈(目标task)的栈顶,不管这个Activity是否已经存在于返回栈中;
- singleTop模式:如果一个以singleTop模式启动的activity的实例已经存在于返回桟的桟顶,那么再启动这个Activity时,不会创建新的实例,而是重用位于栈顶的那个实例,并且会调用该实例的onNewIntent()方法将Intent对象传递到这个实例中;
注:如果以singleTop模式启动的activity的一个实例已经存在于返回桟中,但是不在桟顶,那么它的行为和standard模式相同,也会创建多个实例;
- singleTask模式:这种模式下,每次启动一个activity时,系统首先会在返回栈中检查是否存在该活动的实例,如果存在,则直接使用该实例,并把这个活动之上的所有活动统统清除;如果没有发现就会创建一个新的活动实例;
- singleInstance模式:总是在新的任务中开启,并且这个新的任务中有且只有这一个实例,也就是说被该实例启动的其他activity会自动运行于另一个任务中。当再次启动该activity的实例时,会重新调用已存在的任务和实例。并且会调用这个实例的onNewIntent()方法,将Intent实例传递到该实例中。和singleTask相同,同一时刻在系统中只会存在一个这样的Activity实例。(singleInstance即单实例)
注:前面三种模式中,每个应用程序都有自己的返回栈,同一个活动在不同的返回栈中入栈时,必然是创建了新的实例。而使用singleInstance模式可以解决这个问题,在这种模式下会有一个单独的返回栈来管理这个活动,不管是哪一个应用程序来访问这个活动,都公用同一个返回栈,也就解决了共享活动实例的问题。(此时可以实现任务之间的切换,而不是单独某个栈中的实例切换)
Activity有四种启动模式:standard、singleTop、singleTask、singleInstance。可以在AndroidManifest.xml中activity标签的属性android:launchMode中设置该activity的加载模式。
我们也可以不在清单文件中设置,只在代码中通过flag来设置也是可以的,如下:
1 Intent intent = new Intent(MainActivity.this,SecondActivity.class); 2 //相当于singleTask 3 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 4 startActivity(intent);
设置加载模式:
<activity
android:name=".SingleTaskActivity"
android:label="singleTask launchMode"
android:launchMode="singleTask">
任务栈:
每个应用都有一个任务栈,是用来存放Activity的,功能类似于函数调用的栈,先后顺序代表了Activity的出现顺序;
左侧任务栈为:Activity1-->Activity2-->Activity3
standard (默认): 每次激活Activity时(startActivity),都创建Activity实例,并放入任务栈;
singleTop:如果某个Activity自己激活自己,即任务栈栈顶就是该Activity,则不需要创建,其余情况都要创建Activity实例
singleTask:如果要激活的那个Activity在任务栈中存在该实例,则不需要创建,只需要把此Activity放入栈顶,并把该Activity以上的Activity实例都pop;
singleInstance:如果应用1的任务栈中创建了MainActivity实例,如果应用2也要激活MainActivity,则不需要创建,两应用共享该Activity实例;
Activity四种启动模式的应用场景
6. Activity 的启动方式
6.1 显式启动:
通过包名来启动,这是最常见的
startActivity(new Intent(当前 Activity.this,要启动的 Activity.class));
通过 Intent 的 ComponentName
ComponentName cn = new ComponentName("当前 Activity 的全限定类名","启动 Activity 的全限定类名") ; Intent intent = new Intent() ; intent.setComponent(cn) ; startActivity(intent) ;
初始化 Intent 时指定包名
Intent intent = new Intent("android.intent.action.MAIN"); intent.setClassName("当前 Activity 的全限定类名","启动 Activity 的全限定类名"); startActivity(intent);
6.2 隐式启动:
通过 Intent-filter 的 Action,Category 或 data 来实现
AndroidManifest.xml 配置
<activity android:name=".SecondActivity" android:label="第二个 Activity" > <intent-filter> <action android:name="ms_action" /> <category android:name="ms_category" /> <category android:name="android.intent.catetory.DEFAULT" /> </intent-filter>
Java 代码
Intent it = new Intent(); it.setAction("ms_action"); it.addCategory("ms_category"); startActivity(it);
直接通过包名启动 apk 的
Intent intent = getPackageManager().getLaunchIntentForPackage ("apk 第一个启动的 Activity 的全限定类名") ; if(intent != null) startActivity(intent) ;
7. Activity 数据传递
一个 App 一般都由多个 Activity 构成的,这就涉及到了多个 Activity 间数据传递的问题了
Activity 间的数据传递流程一般如下
-
一个传一个
存数据
Intent it1 = new Intent(A.this, B.class); it1.putExtra("key",value); startActivity(it1);
取数据
Intent it2 = getIntent(); getXxxExtra("key"); // Xxx 是数据类型
-
一次传多个
存数据
Intent it1 = new Intent(A.this, B.class); Bundle bd = new Bundle(); bd.putInt("num",1); bd.putString("detail","www.twle.cn"); it1.putExtra(bd); startActivity(it1);
取数据
Intent it2 = getIntent(); Bundle bd = it2.getExtra(); int n = bd.getInt("num"); String d = bd.getString("detail");
多个 Activity 间的交互 (后一个传回给前一个):
-
使用下面的方法启动一个
Activity
startActivityForResult(Intent intent, int requestCode)
-
在要启动的
Activity
中重写方法onActivityResult(int requestCode, int resultCode, Intent data);
参数 说明 requestCode 用于区分该
Activity
中不同的启动方式,可以自定义比如有两个不同的按钮,启动的是同一个 Activity, 传递的数据可能不同,就可以使用 requestCode 来区分
resultCode 子 Activity 通过 setResult()
放回的码 -
在子
Activity
中重写
startActivityForResult的一个例子:
第一个Activity打开第二个Activity时,第二个Activity关闭并想返回数据给第一个Activity时,我们就要重写
onActivityResult(int requestCode, int resultCode, Intent data)
这个方法.首先我们要在第一个Activity调用startActivityForResult这个方法,代码如下:
public void onClick(View v) {
//得到新打开Activity关闭后返回的数据
//第二个参数为请求码,可以根据业务需求自己编号
startActivityForResult(new Intent(MainActivity.this, OtherActivity.class), 1);
}
});
在第二个Activity中使用setResult设置要返回的值:
putExtra() : 将数据返回 给 Intent
setResult // 设置返回的数据
public void onClick(View v) {
//数据是使用Intent返回
Intent intent = new Intent();
//把返回数据存入Intent
intent.putExtra("result", "My name is luis");
//设置返回数据
OtherActivity.this.setResult(RESULT_OK, intent);//RESULT_OK为自定义常量
//关闭Activity
OtherActivity.this.finish();
}
});
当第二个Activity关闭时,返回第一个Activity,在第一个Activity中重写onActivityResult方法,数据可以从data中取出:
String result = data.getExtras().getString("result");//得到新Activity 关闭后返回的数据
a.请求码的作用 requestCode :
使用startActivityForResult(Intent intent, int requestCode)方法打开新的Activity,我们需要为startActivityForResult()方法传入一个请求码(第二个参数)。请求码的值是根据业务需要由自已设定,用于标识请求来源。
例如:一个Activity有两个按钮,点击这两个按钮都会打开同一个Activity,不管是那个按钮打开新Activity,当这个新Activity关闭后,系统都会调用前面Activity的onActivityResult(int requestCode, int resultCode, Intent data)方法。在onActivityResult()方法如果需要知道新Activity是由那个按钮打开的,并且要做出相应的业务处理,这时可以这样做:
@Override public void onCreate(Bundle savedInstanceState) {
....
button1.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
startActivityForResult (new Intent(MainActivity.this, NewActivity.class), 1);
}
});
button2.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
startActivityForResult (new Intent(MainActivity.this, NewActivity.class), 2);
}
});
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch(requestCode){
case 1:
//来自按钮1的请求,作相应业务处理
String result = data.getExtras().getString("result");//得到新Activity 关闭后返回的数据
case 2:
//来自按钮2的请求,作相应业务处理
}
}
}
b.结果码的作用 resultCode:
在一个Activity中,可能会使用main 主活动页面中,startActivityForResult()方法打开多个不同的Activity处理不同的业务,
当这些新Activity关闭后,系统都会调用前面Activity的onActivityResult(int requestCode, int resultCode, Intent data)方法。为了知道返回的数据来自于哪个新Activity,在onActivityResult()方法中可以这样做(ResultActivity和NewActivity为要打开的新Activity):
public class ResultActivity extends Activity {
.....
ResultActivity.this.setResult(1, intent);
ResultActivity.this.finish();
}
public class NewActivity extends Activity {
......
NewActivity.this.setResult(2, intent);
NewActivity.this.finish();
}
public class MainActivity extends Activity { // 在该Activity会打开ResultActivity和NewActivity
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch(resultCode){
case 1:
// ResultActivity的返回数据
case 2:
// NewActivity的返回数据
}
}
}
判断当前是哪个 Activity:
如果要判断当前是那个 Activity
,只需要让所有的 Activity
继承一个自定义的 BaseActivity
然后在 onCreate()
方法中添加以下语句
Log.d("BaseActivity",getClass().getSimpleName());