4.3.1Activity的生命周期演示
如果不是启动的对话框风格的Activity,会进入Stop状态,可以注释掉
AndroidManifest.xml中
4.按下HOME键,
MainActivity失去焦点并且不可见,但它并未销毁,进入stop状态
Activity大致会经过如下4种状态:
1.运行状态:当前Activity位于前台(返回栈的栈顶),用户可见,可以获得焦点。
2.暂停状态:其他Activity位于前台
(返回栈的栈顶)
,但该Activity依然可见,只是不能获得焦点
3.停止状态:该Activity不可见,失去焦点,该
Activity不在处于栈顶位置。
4.销毁状态:该Activity结束,或Activity所在的进程被结束。(该Activity从返回栈中移除)
开发Activity时经常复写onCreate(Bundle saveStatus)方法,该方法用于对该Activity进行初始化。
除此之外,覆盖onPause()也很常见,比如用户正在玩一个游戏,此时有电话进来,那么我们需要将当前游戏暂停,并保存该游戏的进行状态,这就可以通过覆盖onPause()方法来实现。接下来当用户切换到游戏状态时,onResume()方法已经被回调,因此可以通过复写onResume()方法来恢复游戏状态。
onCreate(): 它会在活动第一次被创建的时候调用。应该在这个方法中完成活动的初始化操作,比如加载布局、绑定事件等。
onStart(): 这个方法在活动由不可见变为可见的时候调用
onResume():这个方法在活动准备好和用户进行交互的时候调用。此时的活动一定位于返回栈的栈顶,并且处于运行状态。
onPause():这个方法在系统准备去启动或者恢复另一个活动的时候调用。我们通常会在这个方法中将一些消耗CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶活动 的使用。
onStop():这个方法在活动完全不可见的时候调用。它和onPause()的主要区别在于。如果启动的新活动是一个对话框式的活动,那么onPause()方法会得到执行,而onStop()方法不会执行
onDestory():这个方法在活动被销毁之前调用,之后活动将变为销毁状态。
onRestart():这个方法在活动由停止状态变为运行状态之前调用,也就是活动被重新启动了。
以上7个方法中除了onRestart(),其他都是两两相对的,从而又可以将活动分为3种生存期。
完整生存期:onCreate()----onDestroy()。一般情况下,一个活动会在onCreate()方法中完成各种初始化操作,而在onDestroy()中完成释放内存的操作。
可见生存期:onStart()---onStop()。在可见生存期内,活动对于用户总是可见的,即使有可能无法和用户交互。我们也可以通过这两个方法,合理的管理那些对用户可见的资源。比如在onStart()中对资源进行加载,在onStop()中对资源进行释放,从而保证处于停止状态的活动不会占用过多内存。
前台生存期:onResume()--onPause()。在前台生存区内,活动总是处于运行状态的,此时活动是可以和用户进行交互的。
例:MainActivity中有两个button,一个用于启动对话框风格的Activity,另一个用于退出该应用
package com.example.administrator.lifetest;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
final String MTAG = "MYTEST";
Button startActivity,closeActivity;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e(MTAG,"----onCreate----");
startActivity = (Button)findViewById(R.id.startActivity);
closeActivity = (Button)findViewById(R.id.closeActivity);
startActivity.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,SecondActivitry.class);
startActivity(intent);
}
});
closeActivity.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MainActivity.this.finish();
}
});
}
@Override
protected void onStart() {
super.onStart();
Log.e(MTAG,"----onStart----");
}
@Override
protected void onResume() {
super.onResume();
Log.e(MTAG,"----onResume----");
}
@Override
protected void onPause() {
super.onPause();
Log.e(MTAG,"----onPause----");
}
@Override
protected void onStop() {
super.onStop();
Log.e(MTAG,"----onStop----");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.e(MTAG,"----onDestroy----");
}
@Override
protected void onRestart() {
super.onRestart();
Log.e(MTAG,"----onRestart----");
}
}
布局文件activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.administrator.lifetest.MainActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="startActivity"
android:id="@+id/startActivity"
/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/startActivity"
android:text="closeActivity"
android:id="@+id/closeActivity"
/>
</RelativeLayout>
SecondActivitry
public class SecondActivitry extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView textView = new TextView(this);
textView.setText("对话框风格的Activity");
setContentView(textView);
}
}
注意记得在AndroidManifest.xml中配置 主题为对话框风格
<activity android:name=".SecondActivitry"
android:theme="@style/Base.V7.Theme.AppCompat.Dialog">
</activity>
1.当程序启动时,会自动启动并执行MainActivity
2.当点击 “启动对话框风格的Activity” 按钮时
(对话框风格的Activity进入前台,虽然MainActivity不能获得焦点,但依然部分可见,所以进入暂停状态)
android:theme="@style/Base.V7.Theme.AppCompat.Dialog"
结果如下
3.点击返回后(MainActivity再次进入运行状态)
5.再次启动该应用程序
6.点击 “CLOSEACTIVITY” 按钮后 ,MainActivity将会被销毁
4.3.3Activity的4种加载模式
Android对Activity的管理:Android采用Task来管理多个Activity,当我们启动一个应用时,Android就会为之创建一个Task,然后启动这个应用的入口Activity(即<intent-filter.../
>中配置为MAIN和LUNCHER的Activity)。Task以栈的形式来管理Activity,这个栈也被称之为返回栈,先启动的Activity放在Task栈底,后启动的Activity放在Task栈顶。每当我们按下Back键或者调用finish()方法去销毁一个活动时,处于栈顶的活动会出栈,这时前一个入栈的活动会重新处于栈顶位置。系统总是会显示处于栈顶的活动给用户。
由于Android没有为Task提供API,只能调用Activity的getTaskId()来获取它所在的Task的ID
配置Activity时可指定android:launchMode属性,该属性用于配置该Activity的加载模式
standard: 标准模式,这是默认的加载模式
singleTop:Task栈顶单例模式
singleTask:Task内单例模式
singleInstance:全局单例模式
1.standard模式
每次通过这种模式来启动目标Activity时,Android总会为目标Activity创建一个新的实例,并将该Activity添加到当前Task栈中----这种模式不会启动新的Task,新Activity将被添加到原有的Task中。
例:每次点击button都会再次启动MainActivity。
public class MainActivity extends AppCompatActivity {
Button startActivity;
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textview);
startActivity = (Button)findViewById(R.id.startActivity);
textView.setText("Activity为:"+this.toString()+"\n"+"Task的ID为"+this.getTaskId());
startActivity.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,MainActivity.class);
startActivity(intent);
}
});
}
}
不同Activity实例的hashCode值有差异,但它们所在的Task ID总是相同的----表明这种加载模式不会使用全新的Task
2.singleTop模式
与standrad模式基本相同,但有一点不同:当将要启动的Activity已经位于Task栈顶时,系统不会重新创建目标Activity的实例。
不再用默认加载模式,在AndroidManifest.xml中把加载模式改为singleTop
<activity android:name=".MainActivity"
android:launchMode="singleTop">
无论再点击多少次button,界面上的程序都不会有任何变化。
3.singleTask模式
采用这种加载模式的Activity在同一个Task内只有一个实例,当系统采用singleTask模式时。
(1)如果要加载的目标Activity不存在,系统将会创建目标Activity的实例,并将它加入Task栈顶。
(2)如果将要启动的Acitvity已经在栈顶,此时与singleTop的行为相同
(3)如果将要启动的目标Activity已经存在,但没有位于Actvity栈顶,系统将会把位于该Activity上的所有Activity都移出Task栈,从而使得目标Activity转入栈顶。
例:MainActivity的加载模式为standrad,SecondActicity的加载模式为singleTask
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.administrator.lifetest">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SecondActivitry"
android:launchMode="singleTask"
></activity>
</application>
</manifest>
MainActivity的button点击事件是启动SecondActicity,textview显示当前Acticvity 和 所在的Task ID
public class MainActivity extends AppCompatActivity {
// final String MTAG = "MYTEST";
Button startActivity;
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textview);
startActivity = (Button)findViewById(R.id.startActivity);
textView.setText("Activity为:"+this.toString()+"\n"+"Task的ID为"+this.getTaskId());
startActivity.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,SecondActivitry.class);
startActivity(intent);
}
});
}
}
SecondActicity
的button点击事件是启动
MainActivity
,textview显示当前Acticvity 和 所在的Task ID
public class SecondActivitry extends AppCompatActivity {
Button but;
TextView tex;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_second);
but = (Button) findViewById(R.id.startMain);
tex = (TextView) findViewById(R.id.stx);
tex.setText("Activity为:"+this.toString()+"\n"+"Task的ID为"+this.getTaskId());
but.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent mintent = new Intent(SecondActivitry.this,MainActivity.class);
startActivity(mintent);
}
});
}
}
应用程序LifeTest
1.进入MainActivity 2.点击button进入SecondActivity 3.点击button进入MainActivity
4.点击button进入SecondActivity
会发现这两次进入SecondActivity的实例都一样都一样
而此时Task栈中 只剩两个Activty实例: 第一个MainActivity----SecondActivity
点返回键之后退回到第一个MainActivity,再返回一次会退出应用程序
4.singleInstance模式
在singleInstance模式下,系统保证无论从哪个Task中启动目标Activity,只会创建一个目标Activity实例,并会用一个全新的Task栈来加载该Activity实例
(1)如果将要启动的目标Actvity不存在,系统会先创建一个全新的Task栈,再创建目标Activity的实例,并将它加入新的Task栈顶
(2)如果将要启动的目标Activity已经存在,无论它位于哪个应用程序中,位于哪个Task中系统都会把该Activity所在的Task转到前台,从而使该Activity显示出来
采用singleInstance模式加载的Activity总是位于Task栈顶,且采用singleInstance模式加载的Activity所在的Task将只包含该Activity
把singleTask例子中SecondActivity的加载模式改为singleInstance,并且将exported属性配置成true--表明该Activity能被其他应用程序启动。并且配置<intent-filter.../>子元素,表明该Activity可通过隐式Intent启动
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.administrator.lifetest">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SecondActivitry"
android:launchMode="singleInstance"
android:exported="true">
<intent-filter>
<!--指定该Activity能响应Action为指定字符串"xufelony"的Intent-->
<action android:name ="xufelony"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
</manifest>
重新新建一个Project
在
SingleActivity
使用隐式Intent启动该SecondActivity,就算他们不在同一个应用程序
public class SingleActivity extends AppCompatActivity {
Button button;
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single);
button = (Button) findViewById(R.id.startSecond);
textView = (TextView) findViewById(R.id.testlauchSecond);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//使用隐式Intent启动SecondActivity
Intent intent = new Intent();
intent.setAction("xufelony");
startActivity(intent);
}
});
}
}
在应用程序SingleInstanceTest的SingleActivity中
当点击button时,会把SecondActivity所在的Task(应用程序LifeTest)转入前台(注意此时
LifeTest的Task栈中只有
SecondActivity而没有
MainActivity。
因为采用singleInstance模式加载的Activity所在的Task将只包含该Activity
),从而将
SecondActivity显示出来