Activity加载模式及数据传递
2016-09-29 21:19
183 查看
Activity的启动方式有两种,一种是应用程序启动时默认启动,另一种是通过Intent启动。
在做Activity生命周期的实验的时候,我们发现在通过Intent做页面切换的时候新启动的Activity会覆盖到原来的Activity之上,销毁新的Activity后,原来的Activity就会出现,我们知道这是因为Activity栈的关系,其实还与Activity的加载模式有关。
Android是采用Task来管理多个Activity的,当我们启动一个应用时,Android就会为之创建了一个Task,然后启动这个应用入口的Activity。关于Tast,Android并没有为Task提供API,因此开发者无法真正访问Task,只能调用Activity的getTaskId()方法来获取它所在的Task的ID。我们可以把Task理解成Activity栈,Task以栈的样式来管理Activity,先启动的Activity被放在Task栈底,后启动的Activity被放在Task栈顶。
Activity的加载模式就是指Activity与Task之间的加载关系。真正的开发中,我们并不希望出现像那种新启动的Activity退出后原来的Activity又出现,如果要启动很多个Activity,那么逐个退出就会逐个显示。Activity加载模式的控制就是解决Activity大量重复创建或过多的问题。
Activity启动方式有四种,分别是:standard、singleTop、singleTask、singleInstance。配置Activity的加载模式需要在配置文件<activity>标签内设置属性launchMode,格式如下
<activity
android:name=".FirstActivity"
android:label="@string/app_name"
android:launchMode="standard"></activity>
1.standard默认模式
一般创建Activity类会自动配置属性,但不会出现launchMode的属性,其实正是默认模式,默认模式可以不写出来。默认模式即是这种无限覆盖,按栈回退的模式,值得注意的是,Activity允许在自己的界面重新创建自己,默认模式下,新创建的Activity就会出来覆盖自己,再创建再覆盖。如下一个简单例子,点击按钮跳转到A界面,操作:A0->A1->A2,回退A2->A1->A0。
布局文件如下
配置文件如下
Activity类文件如下,我们定一个静态属性,每新建一个Activity就加1
效果如下
2.singleTop栈顶单例模式
如果当前Activity已经存在,那么不允许再次创建,即不允许在Activity上创建相同的Activity,而如果通过当前为栈顶单例模式的Activity创建了一个默认模式的Activity,再通过默认模式的Activity创建栈顶单例模式的Activity是允许的,回退也是按栈回退。如下一个简单的例子,操作:无论点几次跳转A页面的按钮都不会有跳转,A0->B0->A1,回退A1->B0->A0。
布局文件如下
第一个界面
第二个界面
配置文件如下
Activity类文件如下
第一个
第二个
效果如下
3.singleTask栈内单例模式
如果想要创建过Activity已经创建过,也允许界面跳转到该界面,但是回退发现之前创建过的Activity被移动到最上面,并且连带销毁中间其他的Activity。如下一个实例,操作:无论点几次跳转A页面的按钮都不会有跳转,A0->B0->A0,我们发现再通过B界面的按钮跳转A界面,我们设置的静态属性没有增加,也就是说还是那个Activity,回退后应用程序就退出了,可见中间创建的B界面已经被销毁了;再进行A0->B0->C0->B1->A0,同样的,回退A界面,中间三个界面并没有回退却已经被销毁。
布局文件如下
第一个界面
第二个界面
第三个界面
配置文件如下
Activity类文件如下
第一个
第二个
第三个
效果如下
4.singleInstance全局单例模式
如果Activity被设为全局单例模式,那么它在创建时Android会给它单个提供一个Task栈,再创建别的Activity会被加入到另外一个Activity栈(以上三种模式下,所有Activity均处于同一个栈)。那么这样会有什么样的效果呢,首先它不能重复创建,其他栈中的Activity启动它也不会新建而是直接跳转,回退它只会出现一次,因为它只有一个。如下面一个例子,操作A0->B0->C0->A0->C1->B1->A0,回退A0->B1-C1->C0->B0,可见A的栈与B、C是相互独立,我们看到在切换界面的时候切换到A界面的动画都不一样了。(为什么要先进入C,因为两个Tast栈切换时,如果直接切换栈顶界面就会新建,如果不是栈顶就会弹到栈顶界面)我们在每个Activity中加入日志输出,表明它们的TaskID,这样就能验证它们属于不同的Task栈。
布局文件与上一个例子相同。
配置文件如下
Activity类文件如下
第一个
第二个
第三个
效果如下
日志输出如下
可以看到A的栈ID与BC是不同的。
Activity中Activity间的数据传递是依靠Intent的putExtra()方法完成的。这个方法功能非常强大,可以传递字符串、数组、数字类型、对象、图片等等。(要传递对象需要实现Serializable接口)
putExtra()需要一个标记自己的String类型和一个数据作为参数,可以通过getStringExtra(),getIntExtra()等方法获取数据。
有时候,我们希望传递一定的数据到另一个界面,由这个界面返回数据,可以通过startActivityForResult()方法传递数据,它需要一个标记的int类型参数(请求码),下一个界面可以通过setResult()方法传回数据,也需要一个标记的int类型参数(结果码),传递数据的界面需要通过onActivityResult(int requestCode, int resultCode, Intent data)方法接受传回数据。下面做一个简单的实例进行测试
布局文件如下
第一个界面
第二个界面
第三个界面
Activity类文件如下
第一个
第二个
第三个
Bean类文件如下
效果如下
在Activity的运行过程中有时会由于Activity的原因导致数据丢失,Android为Activity准备了两个方法来保存和恢复数据onSaveInstanceState和onRestoreInstanceState。
那么这来你两个方法什么时候执行呢?当某个activity变得“容易”被系统销毁时,该activity的onSaveInstanceState就会被执行,除非该activity是被用户主动销毁的,例如当用户按BACK键的时候。
何为“容易”呢?言下之意就是该activity还没有被销毁,而仅仅是一种可能性。这种可能性有哪些?通过重写一个activity的所有生命周期的onXXX方法,包括onSaveInstanceState和onRestoreInstanceState方法,我们可以清楚地知道当某个activity(假定为activity A)显示在当前Task的最上层时,其onSaveInstanceState方法会在什么时候被执行,有这么几种情况:
1、当用户按下HOME键时。
这是显而易见的,系统不知道你按下HOME后要运行多少其他的程序,自然也不知道activity A是否会被销毁,故系统会调用onSaveInstanceState,让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则
2、长按HOME键,选择运行其他的程序时。
3、按下电源按键(关闭屏幕显示)时。
4、从activity A中启动一个新的activity时。
5、屏幕方向切换时,例如从竖屏切换到横屏时。
在屏幕切换之前,系统会销毁activityA,在屏幕切换之后系统又会自动地创建activity A,所以onSaveInstanceState一定会被执行。
总而言之,onSaveInstanceState的调用遵循一个重要原则,即当系统“未经你许可”时销毁了你的activity,则onSaveInstanceState会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据。
至于onRestoreInstanceState方法,需要注意的是,onSaveInstanceState方法和onRestoreInstanceState方法“不一定”是成对的被调用的,onRestoreInstanceState被调用的前提是,activity A“确实”被系统销毁了,而如果仅仅是停留在有这种可能性的情况下,则该方法不会被调用,例如,当正在显示activity A的时候,用户按下HOME键回到主界面,然后用户紧接着又返回到activity A,这种情况下activity A一般不会因为内存的原因被系统销毁,故activity
A的onRestoreInstanceState方法不会被执行。
另外,onRestoreInstanceState的bundle参数也会传递到onCreate方法中,你也可以选择在onCreate方法中做数据还原,我们关于数据传递的例子都是在onCreate方法中执行的。
在做Activity生命周期的实验的时候,我们发现在通过Intent做页面切换的时候新启动的Activity会覆盖到原来的Activity之上,销毁新的Activity后,原来的Activity就会出现,我们知道这是因为Activity栈的关系,其实还与Activity的加载模式有关。
Android是采用Task来管理多个Activity的,当我们启动一个应用时,Android就会为之创建了一个Task,然后启动这个应用入口的Activity。关于Tast,Android并没有为Task提供API,因此开发者无法真正访问Task,只能调用Activity的getTaskId()方法来获取它所在的Task的ID。我们可以把Task理解成Activity栈,Task以栈的样式来管理Activity,先启动的Activity被放在Task栈底,后启动的Activity被放在Task栈顶。
Activity的加载模式就是指Activity与Task之间的加载关系。真正的开发中,我们并不希望出现像那种新启动的Activity退出后原来的Activity又出现,如果要启动很多个Activity,那么逐个退出就会逐个显示。Activity加载模式的控制就是解决Activity大量重复创建或过多的问题。
Activity启动方式有四种,分别是:standard、singleTop、singleTask、singleInstance。配置Activity的加载模式需要在配置文件<activity>标签内设置属性launchMode,格式如下
<activity
android:name=".FirstActivity"
android:label="@string/app_name"
android:launchMode="standard"></activity>
1.standard默认模式
一般创建Activity类会自动配置属性,但不会出现launchMode的属性,其实正是默认模式,默认模式可以不写出来。默认模式即是这种无限覆盖,按栈回退的模式,值得注意的是,Activity允许在自己的界面重新创建自己,默认模式下,新创建的Activity就会出来覆盖自己,再创建再覆盖。如下一个简单例子,点击按钮跳转到A界面,操作:A0->A1->A2,回退A2->A1->A0。
布局文件如下
<LinearLayout 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:orientation="vertical" 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.briup.activity.FirstActivity" > <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="New A" android:onClick="newA" /> <TextView android:id="@+id/A_tv" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:textSize="20sp"/> </LinearLayout>
配置文件如下
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.briup.activity" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".FirstActivity" android:label="@string/app_name" android:launchMode="standard"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
Activity类文件如下,我们定一个静态属性,每新建一个Activity就加1
import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.TextView; public class FirstActivity extends Activity { private static int A = 0; private TextView aTv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_first); aTv = (TextView) findViewById(R.id.A_tv); aTv.setText("A-Num:"+A++); } public void newA(View v){ Intent intent = new Intent(this,FirstActivity.class); startActivity(intent); } }
效果如下
2.singleTop栈顶单例模式
如果当前Activity已经存在,那么不允许再次创建,即不允许在Activity上创建相同的Activity,而如果通过当前为栈顶单例模式的Activity创建了一个默认模式的Activity,再通过默认模式的Activity创建栈顶单例模式的Activity是允许的,回退也是按栈回退。如下一个简单的例子,操作:无论点几次跳转A页面的按钮都不会有跳转,A0->B0->A1,回退A1->B0->A0。
布局文件如下
第一个界面
<LinearLayout 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:orientation="vertical" 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.briup.activity.FirstActivity" > <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="New A" android:onClick="newA" /> <TextView android:id="@+id/A_tv" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:textSize="20sp"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="New B" android:onClick="newB"/> </LinearLayout>
第二个界面
<LinearLayout 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:orientation="vertical" 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.briup.activity.SecondActivity" > <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="new A" android:onClick="newA" /> <TextView android:id="@+id/B_tv" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:textSize="20sp"/> </LinearLayout>
配置文件如下
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.briup.activity" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".FirstActivity" android:label="@string/app_name" android:launchMode="singleTop">p <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".SecondActivity" android:label="@string/title_activity_second" > </activity> </application> </manifest>
Activity类文件如下
第一个
import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.TextView; public class FirstActivity extends Activity { private static int A = 0; private TextView aTv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_first); aTv = (TextView) findViewById(R.id.A_tv); aTv.setText("A-Num:"+A++); } public void newA(View v){ Intent intent = new Intent(this,FirstActivity.class); startActivity(intent); } public void newB(View v){ Intent intent = new Intent(this,SecondActivity.class); startActivity(intent); } }
第二个
import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.TextView; public class SecondActivity extends Activity { private static int B = 0; private TextView bTv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); bTv = (TextView) findViewById(R.id.B_tv); bTv.setText("B-NUM:"+B++); } public void newA(View v){ Intent intent = new Intent(this,FirstActivity.class); startActivity(intent); } }
效果如下
3.singleTask栈内单例模式
如果想要创建过Activity已经创建过,也允许界面跳转到该界面,但是回退发现之前创建过的Activity被移动到最上面,并且连带销毁中间其他的Activity。如下一个实例,操作:无论点几次跳转A页面的按钮都不会有跳转,A0->B0->A0,我们发现再通过B界面的按钮跳转A界面,我们设置的静态属性没有增加,也就是说还是那个Activity,回退后应用程序就退出了,可见中间创建的B界面已经被销毁了;再进行A0->B0->C0->B1->A0,同样的,回退A界面,中间三个界面并没有回退却已经被销毁。
布局文件如下
第一个界面
<LinearLayout 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:orientation="vertical" 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.briup.activity.FirstActivity" > <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="New A" android:onClick="newA" /> <TextView android:id="@+id/A_tv" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:textSize="20sp"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="New B" android:onClick="newB"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="New C" android:onClick="newC"/> </LinearLayout>
第二个界面
<LinearLayout 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:orientation="vertical" 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.briup.activity.SecondActivity" > <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="new A" android:onClick="newA" /> <TextView android:id="@+id/B_tv" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:textSize="20sp"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="new C" android:onClick="newC" /> </LinearLayout>
第三个界面
<LinearLayout 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:orientation="vertical" 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.briup.activity.ThirdActivity" > <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="new A" android:onClick="newA" /> <TextView android:id="@+id/C_tv" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:textSize="20sp"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="new B" android:onClick="newB" /> </LinearLayout>
配置文件如下
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.briup.activity" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".FirstActivity" android:label="@string/app_name" android:launchMode="singleTask" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".SecondActivity" android:label="@string/title_activity_second" > </activity> <activity android:name=".ThirdActivity" android:label="@string/title_activity_third" > </activity> </application> </manifest>
Activity类文件如下
第一个
import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.TextView; public class FirstActivity extends Activity { private static int A = 0; private TextView aTv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_first); aTv = (TextView) findViewById(R.id.A_tv); aTv.setText("A-Num:"+A++); } public void newA(View v){ Intent intent = new Intent(this,FirstActivity.class); startActivity(intent); } public void newB(View v){ Intent intent = new Intent(this,SecondActivity.class); startActivity(intent); } public void newC(View v){ Intent intent = new Intent(this,ThirdActivity.class); startActivity(intent); } }
第二个
import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.TextView; public class SecondActivity extends Activity { private static int B = 0; private TextView bTv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); bTv = (TextView) findViewById(R.id.B_tv); bTv.setText("B-NUM:"+B++); } public void newA(View v){ Intent intent = new Intent(this,FirstActivity.class); startActivity(intent); } public void newC(View v){ Intent intent = new Intent(this,ThirdActivity.class); startActivity(intent); } }
第三个
import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.TextView; public class ThirdActivity extends Activity { private static int C = 0; private TextView cTv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_third); cTv = (TextView) findViewById(R.id.C_tv); cTv.setText("C-NUM:"+C++); } public void newA(View v){ Intent intent = new Intent(this,FirstActivity.class); startActivity(intent); } public void newB(View v){ Intent intent = new Intent(this,SecondActivity.class); startActivity(intent); } }
效果如下
4.singleInstance全局单例模式
如果Activity被设为全局单例模式,那么它在创建时Android会给它单个提供一个Task栈,再创建别的Activity会被加入到另外一个Activity栈(以上三种模式下,所有Activity均处于同一个栈)。那么这样会有什么样的效果呢,首先它不能重复创建,其他栈中的Activity启动它也不会新建而是直接跳转,回退它只会出现一次,因为它只有一个。如下面一个例子,操作A0->B0->C0->A0->C1->B1->A0,回退A0->B1-C1->C0->B0,可见A的栈与B、C是相互独立,我们看到在切换界面的时候切换到A界面的动画都不一样了。(为什么要先进入C,因为两个Tast栈切换时,如果直接切换栈顶界面就会新建,如果不是栈顶就会弹到栈顶界面)我们在每个Activity中加入日志输出,表明它们的TaskID,这样就能验证它们属于不同的Task栈。
布局文件与上一个例子相同。
配置文件如下
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.briup.activity" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".FirstActivity" android:label="@string/app_name" android:launchMode="singleInstance" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".SecondActivity" android:label="@string/title_activity_second" > </activity> <activity android:name=".ThirdActivity" android:label="@string/title_activity_third" > </activity> </application> </manifest>
Activity类文件如下
第一个
import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.TextView; public class FirstActivity extends Activity { private static int A = 0; private TextView aTv; private static final String TAG = "briup"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_first); aTv = (TextView) findViewById(R.id.A_tv); aTv.setText("A-Num:"+A++); } @Override protected void onResume() { // TODO Auto-generated method stub super.onResume(); Log.i(TAG, "FirstActivity:"+getTaskId()); } public void newA(View v){ Intent intent = new Intent(this,FirstActivity.class); startActivity(intent); } public void newB(View v){ Intent intent = new Intent(this,SecondActivity.class); startActivity(intent); } public void newC(View v){ Intent intent = new Intent(this,ThirdActivity.class); startActivity(intent); } }
第二个
import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.TextView; public class SecondActivity extends Activity { private static int B = 0; private TextView bTv; private static final String TAG = "briup"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); bTv = (TextView) findViewById(R.id.B_tv); bTv.setText("B-NUM:"+B++); Log.i(TAG, "SecondActivity:"+getTaskId()); } public void newA(View v){ Intent intent = new Intent(this,FirstActivity.class); startActivity(intent); } public void newC(View v){ Intent d487 intent = new Intent(this,ThirdActivity.class); startActivity(intent); } }
第三个
import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.TextView; public class ThirdActivity extends Activity { private static int C = 0; private TextView cTv; private static final String TAG = "briup"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_third); cTv = (TextView) findViewById(R.id.C_tv); cTv.setText("C-NUM:"+C++); Log.i(TAG, "ThirdActivity:"+getTaskId()); } public void newA(View v){ Intent intent = new Intent(this,FirstActivity.class); startActivity(intent); } public void newB(View v){ Intent intent = new Intent(this,SecondActivity.class); startActivity(intent); } }
效果如下
日志输出如下
可以看到A的栈ID与BC是不同的。
Activity中Activity间的数据传递是依靠Intent的putExtra()方法完成的。这个方法功能非常强大,可以传递字符串、数组、数字类型、对象、图片等等。(要传递对象需要实现Serializable接口)
putExtra()需要一个标记自己的String类型和一个数据作为参数,可以通过getStringExtra(),getIntExtra()等方法获取数据。
有时候,我们希望传递一定的数据到另一个界面,由这个界面返回数据,可以通过startActivityForResult()方法传递数据,它需要一个标记的int类型参数(请求码),下一个界面可以通过setResult()方法传回数据,也需要一个标记的int类型参数(结果码),传递数据的界面需要通过onActivityResult(int requestCode, int resultCode, Intent data)方法接受传回数据。下面做一个简单的实例进行测试
布局文件如下
第一个界面
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:orientation="vertical" 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.briup.activitystart.MainActivity" > <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="GotoSecond" android:onClick="gotoSecond" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="GotoThird" android:onClick="gotoThird" /> </LinearLayout>
第二个界面
<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.briup.activitystart.SecondActivity" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Copy That" android:onClick="back" android:layout_centerInParent="true"/> </RelativeLayout>
第三个界面
<LinearLayout 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:orientation="vertical" 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.briup.activitystart.ThirdActivity" > <ImageView android:id="@+id/third_iv" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <TextView android:id="@+id/third_tv1" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="20sp" /> <TextView android:id="@+id/third_tv2" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="20sp" /> </LinearLayout>
Activity类文件如下
第一个
import android.app.Activity; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.view.View; import android.widget.Toast; public class MainActivity extends Activity { private Bean b; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); b = new Bean("德莱厄斯", 40, "诺克萨斯"); } public void gotoSecond(View v){ Intent intent = new Intent(this,SecondActivity.class); intent.putExtra("name", "Testing,do you copy?"); startActivityForResult(intent,1);//请求码 } public void gotoThird(View v) { Intent intent = new Intent(MainActivity.this,ThirdActivity.class); intent.putExtra("name", "德莱文"); intent.putExtra("age", 20); intent.putExtra("bean", b); Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);//位图 intent.putExtra("bitmap", bitmap); startActivity(intent); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // 接收数据方法 super.onActivityResult(requestCode, resultCode, data); if(requestCode==1&&resultCode==1){ String name = data.getStringExtra("data"); Toast.makeText(MainActivity.this, name, Toast.LENGTH_LONG).show(); } } }
第二个
import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.Toast; public class SecondActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); Intent intent = getIntent(); Toast.makeText(this, intent.getStringExtra("name"), Toast.LENGTH_LONG).show(); } public void back(View v){ Button b = (Button) v; Intent intent = new Intent(); intent.putExtra("data", b.getText().toString()); setResult(1, intent);//结果码 finish();//要想让第一个界面收到信息必须销毁这个界面,否则无法收到,如果通过跳转等于重新创建了第一界面,和这个界面的联系就是新的了 } }
第三个
import android.app.Activity; import android.content.Intent; import android.graphics.Bitmap; import android.os.Bundle; import android.widget.ImageView; import android.widget.TextView; public class ThirdActivity extends Activity { private TextView thirdTv1,thirdTv2; private ImageView thirdIv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_third); thirdTv1 = (TextView) findViewById(R.id.third_tv1); thirdTv2 = (TextView) findViewById(R.id.third_tv2); thirdIv = (ImageView) findViewById(R.id.third_iv); Intent intent = getIntent();//拿到上一层传递的意图 if(intent!=null){ String name = intent.getStringExtra("name");//接收字符串 int age = intent.getIntExtra("age", 18);//接收整数,18为默认值,若没有传过值就使用默认值,可不填 thirdTv1.setText("字符串-name= "+name+"\n整数-age= "+age); Bean b = (Bean) intent.getSerializableExtra("bean");//接受对象 thirdTv2.setText("对象:\n"+b.toString()); Bitmap bitmap = intent.getParcelableExtra("bitmap");//接收位图 thirdIv.setImageBitmap(bitmap); } } }
Bean类文件如下
import java.io.Serializable; public class Bean implements Serializable{ /** * */ private static final long serialVersionUID = 1L; private String name; private int age; private String desc; public Bean(String name, int age, String desc) { super(); this.name = name; this.age = age; this.desc = desc; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public static long getSerialversionuid() { return serialVersionUID; } @Override public String toString() { return "Bean [name=" + name + ", age=" + age + ", desc=" + desc + "]"; } }
效果如下
在Activity的运行过程中有时会由于Activity的原因导致数据丢失,Android为Activity准备了两个方法来保存和恢复数据onSaveInstanceState和onRestoreInstanceState。
那么这来你两个方法什么时候执行呢?当某个activity变得“容易”被系统销毁时,该activity的onSaveInstanceState就会被执行,除非该activity是被用户主动销毁的,例如当用户按BACK键的时候。
何为“容易”呢?言下之意就是该activity还没有被销毁,而仅仅是一种可能性。这种可能性有哪些?通过重写一个activity的所有生命周期的onXXX方法,包括onSaveInstanceState和onRestoreInstanceState方法,我们可以清楚地知道当某个activity(假定为activity A)显示在当前Task的最上层时,其onSaveInstanceState方法会在什么时候被执行,有这么几种情况:
1、当用户按下HOME键时。
这是显而易见的,系统不知道你按下HOME后要运行多少其他的程序,自然也不知道activity A是否会被销毁,故系统会调用onSaveInstanceState,让用户有机会保存某些非永久性的数据。以下几种情况的分析都遵循该原则
2、长按HOME键,选择运行其他的程序时。
3、按下电源按键(关闭屏幕显示)时。
4、从activity A中启动一个新的activity时。
5、屏幕方向切换时,例如从竖屏切换到横屏时。
在屏幕切换之前,系统会销毁activityA,在屏幕切换之后系统又会自动地创建activity A,所以onSaveInstanceState一定会被执行。
总而言之,onSaveInstanceState的调用遵循一个重要原则,即当系统“未经你许可”时销毁了你的activity,则onSaveInstanceState会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据。
至于onRestoreInstanceState方法,需要注意的是,onSaveInstanceState方法和onRestoreInstanceState方法“不一定”是成对的被调用的,onRestoreInstanceState被调用的前提是,activity A“确实”被系统销毁了,而如果仅仅是停留在有这种可能性的情况下,则该方法不会被调用,例如,当正在显示activity A的时候,用户按下HOME键回到主界面,然后用户紧接着又返回到activity A,这种情况下activity A一般不会因为内存的原因被系统销毁,故activity
A的onRestoreInstanceState方法不会被执行。
另外,onRestoreInstanceState的bundle参数也会传递到onCreate方法中,你也可以选择在onCreate方法中做数据还原,我们关于数据传递的例子都是在onCreate方法中执行的。
相关文章推荐
- Activity之间数据传递与共享的几种途径(bitmap篇)&异步加载&service
- [Android] 以singleInstance模式加载的Activity怎么接收以Bundle方式传递过来的参数 By onNewIntent() but not onResum
- Android 以singleInstance模式加载的Activity怎么接收以putExtra方式传递过来参数
- Activity之间的数据传递、启动模式
- Android-Activity生命周期-4种启动模式-数据传递-显式隐式跳转
- [Android] 以singleInstance模式加载的Activity怎么接收以Bundle方式传递过来的参数 By onNewIntent() but not onResum
- Android(监听+回调=观察者)模式从Dialog到Activity传递数据
- Android教程 -04 启动其它Activity,静态工厂设计模式传递数据
- [Android] 以singleInstance模式加载的Activity怎么接收以Bundle方式传递过来的参数 By onNewIntent() but not onResum
- Acitivity在singleTask加载模式下的数据传递处理
- android83 Activity的生命周期,启动模式,返回时传递数据
- android之旅13 Activity数据传递与启动模式
- Android Activity传递数据使用getIntent()接收不到,揭秘Intent传递数据与Activity启动模式singleTask的关系。
- Activity生命周期,数据传递,启动模式详解
- Fragment基础点滴学习---Activity传递数据到Fragment(Fragment使用静态加载的方式)
- Android教程 -04 启动其它Activity,静态工厂设计模式传递数据
- Android中Activity和Fragment之间数据传递(例子中也有事务加载Fragment)
- [Android] 以singleInstance模式加载的Activity怎么接收以Bundle方式传递过来的参数 By onNewIntent() but not onResum
- 使用viewpager+fragment,在activity启动模式为singleTask,跳转到当前页面重新加载数据fragment数据不更新
- Android 以singleInstance模式加载的Activity怎么接收以putExtra方式传递过来参数