Activity

来源:互联网 发布:ubuntu设置用户根目录 编辑:程序博客网 时间:2024/06/16 09:48

一、切换Activity的5种方式


Intent intent = new Intent();
(1)intent.setClass(this,OtherActivity.class);
(2)intent.setClassName(this,"com.xiazdong.OtherActivity");
(3)intent.setClassName("com.xiazdong","com.xiazdong.OtherActivity");//此种方式用来激活不同应用的Activity,只需要指定第一个参数:包名 为另一个应用即可;
(4)
Component comp = new Component(this,OtherActivity.class);
intent.setComponent(comp);
(5)Intent intent = new Intent(this,OtherActivity.class);
二、发送参数与接收参数方式
(1)putExtra方式:
发送
intent.putExtra("name","xiazdong");
intent.putExtra("age",20);
接收
String name = intent.getStringExtra("name");
int age = intent.getIntExtra("age");
(2)Bundle方式:

发送
Bundle bundle = new Bundle();
bundle.putString("name","xiazdong");
bundle.putInt("age",20);
intent.putExtras(bundle);
接收
Bundle bundle = intent.getExtras();
String name = bundle.getString("name");
int age = bundle.getInt("age");
三、带返回值的Activity
0.5451314589008689

1.Activity生命周期理解

355709d1-936f-4130-b3ae-08fcde489ce2


1.启动Activity:系统会先调用onCreate方法,然后调用onStart方法,最后调用onResume,Activity进入运行状态。

2.当前Activity被其他Activity覆盖其上或被锁屏:系统会调用onPause方法,暂停当前Activity的执行。

3.当前Activity由被覆盖状态回到前台或解锁屏:系统会调用onResume方法,再次进入运行状态。

4.当前Activity转到新的Activity界面或按Home键回到主屏,自身退居后台:系统会先调用onPause方法,然后调用onStop方法,进入停滞状态。

5.用户后退回到此Activity:系统会先调用onRestart方法,然后调用onStart方法,最后调用onResume方法,再次进入运行状态。

6.当前Activity处于被覆盖状态或者后台不可见状态,即第2步和第4步,系统内存不足,杀死当前Activity,而后用户退回当前Activity:再次调用onCreate方法、onStart方法、onResume方法,进入运行状态。

7.用户退出当前Activity:系统先调用onPause方法,然后调用onStop方法,最后调用onDestory方法,结束当前Activity。

但是知道这些还不够,我们必须亲自试验一下才能深刻体会,融会贯通。

LifeCycleActivity的Activity,如下:

  1. public class LifeCycleActivity extends Activity {
  2. private static final String TAG = "LifeCycleActivity";
  3. private Context context = this;
  4. private int param = 1;
  5. //Activity创建时被调用
  6. @Override
  7. public void onCreate(Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. Log.i(TAG, "onCreate called.");
  10. setContentView(R.layout.lifecycle);
  11. Button btn = (Button) findViewById(R.id.btn);
  12. btn.setOnClickListener(new View.OnClickListener() {
  13. @Override
  14. public void onClick(View v) {
  15. Intent intent = new Intent(context, TargetActivity.class);
  16. startActivity(intent);
  17. }
  18. });
  19. }
  20. //Activity创建或者从后台重新回到前台时被调用
  21. @Override
  22. protected void onStart() {
  23. super.onStart();
  24. Log.i(TAG, "onStart called.");
  25. }
  26. //Activity从后台重新回到前台时被调用
  27. @Override
  28. protected void onRestart() {
  29. super.onRestart();
  30. Log.i(TAG, "onRestart called.");
  31. }
  32. //Activity创建或者从被覆盖、后台重新回到前台时被调用
  33. @Override
  34. protected void onResume() {
  35. super.onResume();
  36. Log.i(TAG, "onResume called.");
  37. }
  38. //Activity窗口获得或失去焦点时被调用,在onResume之后或onPause之后
  39. /*@Override
  40. public void onWindowFocusChanged(boolean hasFocus) {
  41. super.onWindowFocusChanged(hasFocus);
  42. Log.i(TAG, "onWindowFocusChanged called.");
  43. }*/
  44. //Activity被覆盖到下面或者锁屏时被调用
  45. @Override
  46. protected void onPause() {
  47. super.onPause();
  48. Log.i(TAG, "onPause called.");
  49. //有可能在执行完onPause或onStop后,系统资源紧张将Activity杀死,所以有必要在此保存持久数据
  50. }
  51. //退出当前Activity或者跳转到新Activity时被调用
  52. @Override
  53. protected void onStop() {
  54. super.onStop();
  55. Log.i(TAG, "onStop called.");
  56. }
  57. //退出当前Activity时被调用,调用之后Activity就结束了
  58. @Override
  59. protected void onDestroy() {
  60. super.onDestroy();
  61. Log.i(TAG, "onDestory called.");
  62. }
  63. /**
  64. * Activity被系统杀死时被调用.
  65. * 例如:屏幕方向改变时,Activity被销毁再重建;当前Activity处于后台,系统资源紧张将其杀死.
  66. * 另外,当跳转到其他Activity或者按Home键回到主屏时该方法也会被调用,系统是为了保存当前View组件的状态.
  67. * 在onPause之前被调用.
  68. */
  69. @Override
  70. protected void onSaveInstanceState(Bundle outState) {
  71. outState.putInt("param", param);
  72. Log.i(TAG, "onSaveInstanceState called. put param: " + param);
  73. super.onSaveInstanceState(outState);
  74. }
  75. /**
  76. * Activity被系统杀死后再重建时被调用.
  77. * 例如:屏幕方向改变时,Activity被销毁再重建;当前Activity处于后台,系统资源紧张将其杀死,用户又启动该Activity.
  78. * 这两种情况下onRestoreInstanceState都会被调用,在onStart之后.
  79. */
  80. @Override
  81. protected void onRestoreInstanceState(Bundle savedInstanceState) {
  82. param = savedInstanceState.getInt("param");
  83. Log.i(TAG, "onRestoreInstanceState called. get param: " + param);
  84. super.onRestoreInstanceState(savedInstanceState);
  85. }
  86. }

1.onWindowFocusChanged:

在Activity窗口获得或失去焦点时被调用,例如创建时首次呈现在用户面前;当前Activity被其他Activity覆盖;当前Activity转到其他Activity或按Home键回到主屏,自身退居后台;用户退出当前Activity。以上几种情况都会调用

onWindowFocusChanged,并且当Activity被创建时是在onResume之后被调用,当Activity被覆盖或者退居后台或者当前Activity退出时,它是在onPause之后被调用,如图所示:

0.0024986150674521923

这个方法在某种场合下还是很有用的,

   例如程序启动时想要获取视特定视图组件的尺寸大小,在onCreate中可能无法取到,因为窗口Window对象还没创建完成,这个时候我们就需要在onWindowFocusChanged里获取;

   当时试图在onCreate里加载frame动画失败的原因就是因为窗口Window对象没有初始化完成,所以最后我将加载动画的代码放到了onWindowFocusChanged中,问题迎刃而解。

2.onSaveInstanceState:

(1)在Activity被覆盖或退居后台之后,系统资源不足将其杀死,此方法会被调用;

(2)在用户改变屏幕方向时,此方法会被调用;

(3)在当前Activity跳转到其他Activity或者按Home键回到主屏,自身退居后台时,此方法会被调用。

第一种情况我们无法保证什么时候发生,系统根据资源紧张程度去调度;

第二种是屏幕翻转方向时,系统先销毁当前的Activity,然后再重建一个新的,调用此方法时,我们可以保存一些临时数据;

第三种情况系统调用此方法是为了保存当前窗口各个View组件的状态。onSaveInstanceState的调用顺序是在onPause之前。

3.onRestoreInstanceState:

(1)在Activity被覆盖或退居后台之后,系统资源不足将其杀死,然后用户又回到了此Activity,此方法会被调用;

(2)在用户改变屏幕方向时,重建的过程中,此方法会被调用。我们可以重写此方法,以便可以恢复一些临时数据。

onRestoreInstanceState的调用顺序是在onStart之后。

实验过程分析:

1.启动Activity:

0.8632905862759799

在系统调用了onCreate和onStart之后,调用了onResume,自此,Activity进入了运行状态。

2.跳转到其他Activity,或按下Home键回到主屏:

0.9616143137682229

我们看到,此时onSaveInstanceState方法在onPause之前被调用了,并且注意,退居后台时,onPause后onStop相继被调用。

3.从后台回到前台:

0.04571537324227393

当从后台会到前台时,系统先调用onRestart方法,然后调用onStart方法,最后调用onResume方法,Activity又进入了运行状态。

4.修改TargetActivity在AndroidManifest.xml中的配置,将android:theme属性设置为@android:style/Theme.Dialog,然后再点击LifeCycleActivity中的按钮,跳转行为就变为了TargetActivity覆盖到LifeCycleActivity之上了,此时调用的方法为:

0.5119941211305559

注意还有一种情况就是,我们点击按钮,只是按下锁屏键,执行的效果也是如上。

我们注意到,此时LifeCycleActivity的OnPause方法被调用,并没有调用onStop方法,因为此时的LifeCycleActivity没有退居后台,只是被覆盖或被锁屏;onSaveInstanceState会在onPause之前被调用。

5.按回退键使LifeCycleActivity从被覆盖回到前面,或者按解锁键解锁屏幕:

0.25372745329514146

此时只有onResume方法被调用,直接再次进入运行状态。

6.退出:

0.7691543756518513

最后onDestory方法被调用,标志着LifeCycleActivity的终结。

在所有的过程中,并没有onRestoreInstanceState的出现,这个并不奇怪,因为之前我们就说过,onRestoreInstanceState只有在杀死不在前台的Activity之后用户回到此Activity,或者用户改变屏幕方向的这两个重建过程中被调用。

我们要演示第一种情况比较困难,我们可以结合第二种情况演示一下具体过程。顺便也向大家讲解一下屏幕方向改变的应对策略。

首先介绍一下关于Activity屏幕方向的相关知识。

我们可以为一个Activity指定一个特定的方向,指定之后即使转动屏幕方向,显示方向也不会跟着改变:两种方式

AndroidManifest.xm1.

指定的Activity设置android:screenOrientation="portrait",//竖屏

指定的Activity设置android:screenOrientation="landscape"

或者在onCreate方法中指定:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);  //竖屏

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); //横屏

OrientationActivity,如下:

  1. public class OrientationActivity extends Activity {
  2. private static final String TAG = "OrientationActivity";
  3. private int param = 1;
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.orientation_portrait);
  8. Log.i(TAG, "onCreate called.");
  9. }
  10. @Override
  11. protected void onStart() {
  12. super.onStart();
  13. Log.i(TAG, "onStart called.");
  14. }
  15. @Override
  16. protected void onRestart() {
  17. super.onRestart();
  18. Log.i(TAG, "onRestart called.");
  19. }
  20. @Override
  21. protected void onResume() {
  22. super.onResume();
  23. Log.i(TAG, "onResume called.");
  24. }
  25. @Override
  26. protected void onPause() {
  27. super.onPause();
  28. Log.i(TAG, "onPause called.");
  29. }
  30. @Override
  31. protected void onStop() {
  32. super.onStop();
  33. Log.i(TAG, "onStop called.");
  34. }
  35. @Override
  36. protected void onDestroy() {
  37. super.onDestroy();
  38. Log.i(TAG, "onDestory called.");
  39. }
  40. @Override
  41. protected void onSaveInstanceState(Bundle outState) {
  42. outState.putInt("param", param);
  43. Log.i(TAG, "onSaveInstanceState called. put param: " + param);
  44. super.onSaveInstanceState(outState);
  45. }
  46. @Override
  47. protected void onRestoreInstanceState(Bundle savedInstanceState) {
  48. param = savedInstanceState.getInt("param");
  49. Log.i(TAG, "onRestoreInstanceState called. get param: " + param);
  50. super.onRestoreInstanceState(savedInstanceState);
  51. }
  52. //当指定了android:configChanges="orientation"后,方向改变时onConfigurationChanged被调用
  53. @Override
  54. public void onConfigurationChanged(Configuration newConfig) {
  55. super.onConfigurationChanged(newConfig);
  56. Log.i(TAG, "onConfigurationChanged called.");
  57. switch (newConfig.orientation) {
  58. case Configuration.ORIENTATION_PORTRAIT:
  59. setContentView(R.layout.orientation_portrait);
  60. break;
  61. case Configuration.ORIENTATION_LANDSCAPE:
  62. setContentView(R.layout.orientation_landscape);
  63. break;
  64. }
  65. }
  66. }

首先我们需要进入“Settings->Display”中,将“Auto-rotate Screen”一项选中,表明可以自动根据方向旋转屏幕,

然后我们就可以测试流程了,当我们旋转屏幕时,我们发现系统会先将当前Activity销毁,然后重建一个新的:

0.8403449077159166

系统先是调用onSaveInstanceState方法,我们保存了一个临时参数到Bundle对象里面,然后当Activity重建之后我们又成功的取出了这个参数。

为了避免这样销毁重建的过程,我们需要在AndroidMainfest.xml中对OrientationActivity对应的<activity>配置android:configChanges="orientation",然后我们再测试一下,我试着做了四次的旋转,打印如下:

0.3981212836224586

可以看到,每次旋转方向时,只有onConfigurationChanged方法被调用,没有了销毁重建的过程。

以下是需要注意的几点:

1.如果<activity>配置了android:screenOrientation属性,则会使android:configChanges="orientation"失效。

2.模拟器与真机差别很大:

模拟器中如果不配置android:configChanges属性或配置值为orientation,切到横屏执行一次销毁->重建,切到竖屏执行两次。真机均为一次。

模拟器中如果配置android:configChanges="orientation|keyboardHidden"(如果是Android4.0,则是"orientation|keyboardHidden|screenSize"),切竖屏执行一次onConfigurationChanged,切横屏执行两次。真机均为一次。

当用户在系统与你的应用之间切换的过程中,你的应用中的Activity实例也会在自己的不同生命周期中切换。例如,用户第一次打开你的应用,应用展现在用户的手机桌面,获取用户的输入焦点。在这个过程中,Android系统调用了你的Activity中的一系列的生命周期方法,这些方法建立了应用组建和用户之间的联系。如果用户启动了应用中的另外一个Activity,或者直接切换到另外一个应用,系统也调用了Activity生命周期中的一系列方法使应用可以在后台运行。

在Activity生命周期的回调方法中你可以定义Activity在用户第一次进入和重新进入应用的行为。举例来说,当你做一个流媒体播放器,你可以在用户切换到另外一个应用的时候暂停视频并停止网络连接,当用户切换回来的时候,重新连接网络,并且从用户之前暂停的点继续播放。


理解生命周期中回调方法
   在Activity生命周期之中,系统调用了App生命周期中的回调方法集,这些生命周期回调方法就像一个一级一级的金字塔。Activity生命周期的每一个阶段都对应金字塔的一个台阶。当系统创建了一个新的Activity实例,回调方法一级一级的从塔底向塔顶移动,当位于金字塔顶部的时候,这个Activity就位于用户前台,用户此时就可以与Activity互动了。

   当用户要离开Activity的时候,系统调用另外一串方法,使Activity的状态从塔顶移动到塔底。在有些情况下,Activity只是完成部分的状态迁移并且等待用户的指令,并重新回到塔顶的状态。

0.28188041830435395

   根据Activity复杂度的不同,你或许不用实现所有的生命周期方法。可是,理解每个生命周期回调函数的意义从而确保你的应用按照用户的期望正确的动作则非常重要。正确的实现生命周期的回调方法,从而使应用正确的动作,主要有以下几点需要注意:
     确保应用在用户使用你的时候可以接电话或者切换到其他应用而不崩溃。
     确保你的应用在用户不使用的时候不消耗系统资源。
     确保用户在从其他的应用切换回你的应用的时候能够继续之前的工作
     在用户屏幕切换或者其他动作的时候不崩溃或者丢失用户数据
   图一所显示的Activity不同状态之间的迁移的几种情形,可是在这些状态当中只有三种是稳定的状态,所谓稳定就是Activity可以在这个状态持续保持一段时间,者三个状态是:
     Resumed:这个状态下,Activity来到用户前台,并且完成与用户的交互。(有些情况下我们也称这个状态为运行态。)
     Paused:在这个状态下,Activity被另外一个在前台运行的半透明的Activity或者被另外一个Activity部分盖住,在这个状态下Activity不能接受用户的输入,也不能执行任何代码 。
     Stopped:在这个状态下,Activity被全部盖住,对用户完全不可见,可以认为已经在后台了。在停止状态下,Activity的所有实例,以及他的所有状态信息都被保存,可是不能执行任何代码。
     另外的状态(Created和Started)是一个过渡状态,系统将迅速通过呼叫生命周期的回调函数来迁移到其生命周期的下一站。系统在呼叫了onCreate()->onStart()->onResume()

指定你的应用的启动Activity当用户启动你的应用程序的时候系统调用了那个你声明为启动Activity的onCreat()方法。这个Activity作为你的应用主进入点你可以通过修改AndroidManifest.xml这个位于你的工程根目录的文件来实现这一点。

  1. <span style="font-family:KaiTi_GB2312;"><activity android:name=".MainActivity" android:label="@string/app_name">
  2. <intent-filter>
  3. <action android:name="android.intent.action.MAIN" />
  4. <category android:name="android.intent.category.LAUNCHER" />
  5. </intent-filter>
  6. </activity></span>

注意:当你用Android SDK建立一个工程的时候,工程中的默认会包含一个Activity,而且会被默认为启动Activity
如果MAIN或者LAUNCHER在你的应用中被多次定义,你的应用的图标将不会在用户的应用列表中出现
Start一个Activity

   Android应用与其他的过程式编程语言从一个Main()开始运行不同,Android系统通过触发一个特别的Activity生命周期中的一个回调方法来启动一个Activity。Android中有一系列的回调方法启动一个Activity,也有一系列的回调方法来终止一个Activity。

启动一个新的Activity实例
   大部分应用都会提供多个不同的Activity来实现不同的用户功能,当用户通过点击应用图标来启动应用,或者另外一个Activity接受用户的指令来来调用你的应用,系统都会通过调用onCreate()创建一个新的Activity实例。

   你必须通过实现onCreate()方法来完成基本的应用启动逻辑,而且这个只会在Activity的生命周期中发生一次。你如你可以通过onCreate()应该定义用户接口和一些系统级的量。

Destroythe Activity销毁一个Activity
   Activity生命周期的第一个回调方法是onCreate(),而其最后一个回调方法是onDestroy()。系统通过调用这个方法将Activity的实例彻底的从系统内存中移除。
大部分的应用可能不需要实现这个方法,因为很多本地类的实例在onPause()和onStop()方法中已经销毁了。当然如果你的应用有些后台运行的线程,或者一些其他的长期占有的系统资源,你也应该在onDestroy()中销毁他们。

   注意:系统一般都会在调用了onPause()和onStop()之后再调用onDestroy(),但是如果你在onCreate()方法中调用了finish()则是一个例外。

Pause、Resume一个Activity
   在应用的使用过程中,一个在前台的Activity可能会被部分的遮盖,这回导致Activity进入Pause状态。当一个Activity被完全遮盖时,其进入stop状态。

当你的Activity进入pasued状态,系统调用你的Activity的onPause()方法,从而使你有机会停止你的正在运行的动作,保存你应该保存的信息以保证用户回来的时候不丢失信息


Pause YourActivity
   当系统调用你的Activity的onPause方法,从技术角度来说意味着你的Activity还部分可视,可视更多的是用户将要离开此Activity,这个Activity将进入Stopped状态。你应该使用onPause()方法完成以下功能:
     停止一切可能会消耗CPU的动画后者动作
     提交未保存的修改,当然是用户期望保存的修改
     释放一切可能会消耗电池而你的应用也不需要的资源

   一般来说,你不需要用onPause方法将用户修改存储到永久存储器上,唯一的例外就是用户期望自动存储的信息。不管怎么说,你应该避免执行一些消耗CPU的动作,以避免影响Activity之间切换的感觉,你应该在onStop方法中执行那些大运算量的关闭操作。

ResumeYour Activity
   系统如果要将你的Activity从Paused状态唤醒,需要调用onResume方法。

   记得你Activity任何一次到前台的运行都需要调用onResume方法。所以你所要实现onResume方法来初始化那些被onPause方法释放的组件。

Stop、Restart一个Activity
   恰当的停止和重启你的Activity是其生命周期中非常重要的过程,他们保证你的应用对用户来说一致都是可用的,并且不会丢失他们的数据,你需要:
      当用户从你的应用切换到其他的应用,你的Activity能够正确的停止;当用户从跟其他的应用切换回你的应用,你的应用可以正确的重启;
      当用户在你的Activity中启动了另外一个新的Activity,当前Activity在新的Activity创建之后停止;当用户点击返回按钮,原先的Activity可以正确重启;
      当用户在使用你的应用的时候接到一个电话,你的Activity可以正确的停止;
   Activity类提供了两个生命周期方法onStop() 和 onRestart(),从而可以定义该Activity停止和重启的过程中的动作。与pause状态不同,stop状态保证UI不再可见,而用户的输入焦点在另外一个Activity中。

   注意:在Activity处于停止状态时,系统还是将其保存在系统内存当中,所以你可以不实现onStop() 和 onRestart()方法,甚至你可以连onStart()方法也不必实现。因为大部分Activity都比较简单,你可以通过onPause方法来停止正在运行的动作,断开系统资源。

Stop YourActivity
   当你的Activity被呼叫了onStop方法,它已经不可见了,应该释放所有用户在不使用情况下不需要的资源。当Activity被停止,系统可能销毁这个Activity实例,甚至在极端情况下杀死应用进程已恢复内存等系统资源。

   尽管onPause方法在onStop方法之前调用,但是你需要使用onStop方法来执行那些耗CPU资源的操作,例如同步数据库。


Start/RestartYour Activity
   当一个处于停止状态的Activity需要被唤醒到前台运行,它的onRestart方法将被调用,同时onStart方法也会被调用。onRestart方法只有在系统从Stop状态下被激活才会被调用,所以你可以利用其来恢复那些在stop过程中被释放的资源。
   通过onRestart方法来恢复Activity状态的做法不是非常普遍,所以我们没有为这个方法列出一个指南。因为onStop方法应该将Activity中的资源释放,所以你需要在onRestart中将这个资源重新实例化,同样在Activity创建的时候也需要将这些资源实例化,因为这个原因我们一般将onStart和onStop做资源申请与释放上的对应。
   例如,用户切换出你的应用并且长时间没有返回,onStart方法就是去确认系统资源有没有被正确设置的好地方。

   当系统需要系会你的Activity,它需要调用你的Activity的onDestroy()方法。因为你已经在onStop方法中释放了大部分的资源,onDestroy方法应当没有很多工作需要完成。这个方法是你释放资源,避免内存泄露的最后的机会,你需要确保所有附加的线程等被正确的停止


Recreate一个Activity
   在一些情况下,Activity因为应用的正常动作被销毁,例如用户按返回按钮,或者应用受到finish()调用。系统也会在Activity长时间不用或者系统需要资源的情况下销毁Activity。
   当你的Activity因为按返回或者自我终结的方式销毁的,系统就会认为Activity不被需要了,会在系统中消失。但是,在因为系统的限制而被销毁的Activity,虽然其实例已经被销毁,但是系统仍然会记住其曾经存在过,当用户切换回来的时候,系统会重新创建一个实例,并且将在销毁时保存在bundle中的实例状态数据传递给这个实例。

   注意:Activity在用户旋转屏幕的时候都会销毁并重新创建一个Activity

保存和恢复 Activity 状态

   当你的Activity加入stop状态的时候系统调用onSaveInstanceState(),你可以一系列的键值对来存储目前的状态。当Activity需要Resume的时候,系统调用onRestoreInstanceState()将这些键值对恢复出来。

Activity基础总结:

三个循环

四个阶段

七个方法


三个循环

提供两个关于Activity的生命周期模型图示帮助理解:

0.3267954378388822                                          图1

0.961097156163305

从图2所示的Activity生命周期不难看出,在这个图中包含了两层循环,

第一层循环是onPause -> onResume -> onPause,

第二层循环是onStop -> onRestart -> onStart -> onResume -> onPause -> onStop。

我们可以将这两层循环看成是整合Activity生命周期中的子生命周期。第一层循环称为焦点生命周期,第二层循环称为可视生命周期。

也就是说,第一层循环在Activity焦点的获得与失去的过程中循环,在这一过程中,Activity始终是可见的。而第二层循环是在Activity可见与不可见的过程中循环,在这个过程中伴随着Activity的焦点的获得与失去。也就是说,Activity首先会被显示,然后会获得焦点,接着失去焦点,最后由于弹出其他的Activity,使当前的Activity变成不可见。因此,Activity有如下3种生命周期:

  1. 整体生命周期:onCreate -> ... ... -> onDestroy。
  2. 可视生命周期:onStop -> ... ... -> onPause。
  3. 焦点生命周期:onPause -> onResume。



四个阶段

上面7个生命周期方法分别在4个阶段按着一定的顺序进行调用,这4个阶段如下:

  1. 开始Activity:在这个阶段依次执行3个生命周期方法:onCreate、onStart和onResume。
  2. Activity失去焦点:如果在Activity获得焦点的情况下进入其他的Activity或应用程序,这时当前的Activity会失去焦点。在这一阶段,会依次执行onPause和onStop方法。
  3. Activity重新获得焦点:如果Activity重新获得焦点,会依次执行3个生命周期方法:onRestart、onStart和onResume。
  4. 关闭Activity:当Activity被关闭时系统会依次执行3个生命周期方法:onPause、onStop和onDestroy。

如果在这4个阶段执行生命周期方法的过程中不发生状态的改变,那么系统会按着上面的描述依次执行这4个阶段中的生命周期方法,但如果在执行的过程中改变了状态,系统会按着更复杂的方式调用生命周期方法。

在执行的过程中可以改变系统的执行轨迹的生命周期方法是onPause和onStop。如果在执行onPause方法的过程中Activity重新获得了焦点,然后又失去了焦点。系统将不会再执行onStop方法,而是按着如下的顺序执行相应的生命周期方法:

onPause -> onResume-> onPause

如果在执行onStop方法的过程中Activity重新获得了焦点,然后又失去了焦点。系统将不会执行onDestroy方法,而是按着如下的顺序执行相应的生命周期方法:

onStop -> onRestart -> onStart -> onResume -> onPause -> onStop

在图2所示的Activity生命周期里可以看出,系统在终止应用程序进程时会调用onPause、onStop和onDesktroy方法。而onPause方法排在了最前面,也就是说,Activity在失去焦点时就可能被终止进程,而onStop和onDestroy方法可能没有机会执行。因此,应该在onPause方法中保存当前Activity状态,这样才能保证在任何时候终止进程时都可以执行保存Activity状态的代码。

七个方法

下面对其分别详细说明(文字中的粗体字表示后文中会经常用到的概念在第一次出现时会给出解释,之后后文不再详细说明):

1. void onCreate(Bundle savedInstanceState) 当Activity被第首次加载时执行。

我们新启动一个程序的时候其主窗体的onCreate事件就会被执行。如果Activity被销毁后(onDestroy后),再重新加载进Task时,其onCreate事件也会被重新执行。

注意这里的参数 savedInstanceState(Bundle类型是一个键值对集合,大家可以看成是.Net中的Dictionary)是一个很有用的设计,由于前面已经说到的手机应用的特殊性,一个Activity很可能被强制交换到后台(交换到后台就是指该窗体不再对用户可见,但实际上又还是存在于某个Task中的,比如一个新的Activity压入了当前的Task从而“遮盖”住了当前的 Activity,或者用户按了Home键回到桌面,又或者其他重要事件发生导致新的Activity出现在当前Activity之上,比如来电界面),而如果此后用户在一段时间内没有重新查看该窗体(Android通过长按Home键可以选择最近运行的6个程序,或者用户直接再次点击程序的运行图标,如果窗体所在的Task和进程没有被系统销毁,则不用重新加载,直接重新显示Task顶部的Activity,这就称之为重新查看某个程序的窗体),该窗体连同其所在的 Task和Process则可能已经被系统自动销毁了,此时如果再次查看该窗体,则要重新执行 onCreate事件初始化窗体。而这个时候我们可能希望用户继续上次打开该窗体时的操作状态进行操作,而不是一切从头开始。例如用户在编辑短信时突然来电,接完电话后用户又去做了一些其他的事情,比如保存来电号码到联系人,而没有立即回到短信编辑界面,导致了短信编辑界面被销毁,当用户重新进入短信程序时他可能希望继续上次的编辑。

这种情况我们就可以覆写Activity的void onSaveInstanceState(Bundle outState)事件,通过向outState中写入一些我们需要在窗体销毁前保存的状态或信息,这样在窗体重新执行onCreate的时候,则会通过 savedInstanceState将之前保存的信息传递进来,此时我们就可以有选择的利用这些信息来初始化窗体,而不是一切从头开始。
2. void onStart()   activity变为在屏幕上对用户可见时调用。
onCreate事件之后执行。或者当前窗体被交换到后台后,在用户重新查看窗体前已经过去了一段时间,窗体已经执行了onStop事件,但是窗体和其所在进程并没有被销毁,用户再次重新查看窗体时会执行onRestart事件,之后会跳过onCreate事件,直接执行窗体的onStart事件。 
3. void onResume()   activity开始与用户交互时调用(无论是启动还是重新启动一个活动,该方法总是被调用的)
onStart事件之后执行。或者当前窗体被交换到后台后,在用户重新查看窗体时,窗体还没有被销毁,也没有执行过onStop事件(窗体还继续存在于Task中),则会跳过窗体的onCreate和onStart事件,直接执行onResume事件。 
4. void onPause()   activity被暂停或收回cpu和其他资源时调用

该方法用于保存活动状态的,也是保护现场(压栈),窗体被交换到后台时执行。 
5. void onStop()    activity被停止并转为不可见阶段及后续的生命周期事件时调用。
onPause事件之后执行。如果一段时间内用户还没有重新查看该窗体,则该窗体的onStop事件将会被执行;或者用户直接按了Back键,将该窗体从当前Task中移除,也会执行该窗体的onStop事件。 
6. void onRestart()   重新启动activity时调用。该活动仍在栈中,而不是启动新的活动。
onStop事件执行后,如果窗体和其所在的进程没有被系统销毁,此时用户又重新查看该窗体,则会执行窗体的onRestart事件,onRestart事件后会跳过窗体的onCreate事件直接执行onStart事件。 
7. void onDestroy()   activity被完全从系统内存中移除时调用,

该方法被调用可能是因为有人直接调用onFinish()方法或者系统决定停止该活动以释放资源!
Activity被销毁的时候执行。在窗体的onStop事件之后,如果没有再次查看该窗体,Activity则会被销毁。 
最后用一个实际的例子来说明Activity的各个生命周期。

假设有一个程序由2个Activity A和B组成,A是这个程序的启动界面。

当用户启动程序时,Process和默认的Task分别被创建,接着A被压入到当前的Task中,依次执行了 onCreate, onStart, onResume事件被呈现给了用户;

此时用户选择A中的某个功能开启界面B,界面B被压入当前Task遮盖住了A,A的onPause事件执行,B的 onCreate, onStart, onResume事件执行,呈现了界面B给用户;

用户在界面B操作完成后,使用Back键回到界面A,界面B不再可见,界面B的onPause, onStop, onDestroy执行,A的onResume事件被执行,呈现界面A给用户。此时突然来电,界面A的onPause事件被执行,电话接听界面被呈现给用户,用户接听完电话后,又按了Home键回到桌面,打开另一个程序“联系人”,添加了联系人信息又做了一些其他的操作,此时界面A不再可见,其 onStop事件被执行,但并没有被销毁。

此后用户重新从菜单中点击了我们的程序,由于A和其所在的进程和Task并没有被销毁,A的onRestart 和onStart事件被执行,接着A的onResume事件被执行,A又被呈现给了用户。用户这次使用完后,按Back键返回到桌面,A的 onPause, onStop被执行,随后A的onDestroy被执行,由于当前Task中已经没有任何Activity,A所在的Process的重要程度被降到很低,很快A所在的Process被系统结束。



2.Activity间的数据传递

Activity单向数据传递

下面的例子演示了从 OriginActivity activity 传递字符串“some data!” 到DestinationActivity activity.
注:这是两个活动之间发送数据的最直接的方法。

OriginActivity

public class OriginActivity extends AppCompatActivity {    @Overrideprotected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_origin);        // Create a new Intent object, containing DestinationActivity as target Activity.final Intent intent = new Intent(this, DestinationActivity.class);        // Add data in the form of key/value pairs to the intent object by using putExtra()        intent.putExtra(DestinationActivity.EXTRA_DATA, "Some data!");        // Start the target Activity with the intent object        startActivity(intent);    }}

DestinationActivity

public class DestinationActivity extends AppCompatActivity {    public static final String EXTRA_DATA = "EXTRA_DATA";    @Overrideprotected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_destination);        // getIntent() returns the Intent object which was used to start this Activityfinal Intent intent = getIntent();        // Retrieve the data from the intent object by using the same key that// was previously used to add data to the intent object in OriginActivity.final String data = intent.getStringExtra(EXTRA_DATA);    }}

其他的数据类型

对于其他的数据基本类型传递也是可以的,调用intent。putExtra(key,value);但是取值时候要注明相应类型,比如传入的String,取值时候是getStringExtra()以此类推。

传递对象

有两种方式

Serializable

Serializable这种方式直接实现Serializable接口,剩下的系统会帮我们做好。

代码如下(简单粗暴直接代码示例!)

intent.putExtra(DestinationActivity.EXTRA_DATA, myParcelableObject);bundle.putParcelable(DestinationActivity.EXTRA_DATA, myParcelableObject);final MyParcelableType data = intent.getParcelableExtra(EXTRA_DATA);

Parcelable

Parcelable是一个Android特定的接口,可以对自定义数据类型实现的(即你自己的对象/ POJO对象)。它是Android提供的,比Serializable更加高效。

代码如下(简单粗暴直接代码示例!)

bundle.putSerializable(DestinationActivity.EXTRA_DATA, mySerializableObject);final SerializableType data = (SerializableType)bundle.getSerializable(EXTRA_DATA);

Parcelable代码示例(依旧粗暴)

public class Foo implements Parcelable{private final int myFirstVariable;    private final String mySecondVariable;    private final long myThirdVariable;    public Foo(int myFirstVariable, String mySecondVariable, long myThirdVariable)    {        this.myFirstVariable = myFirstVariable;        this.mySecondVariable = mySecondVariable;        this.myThirdVariable = myThirdVariable;    }    // Note that you MUST read values from the parcel IN THE SAME ORDER that// values were WRITTEN to the parcel! This method is our own custom method// to instantiate our object from a Parcel. It is used in the Parcelable.Creator variable we declare below.public Foo(Parcel in)    {        this.myFirstVariable = in.readInt();        this.mySecondVariable = in.readString();        this.myThirdVariable = in.readLong();    }    // The describe contents method can normally return 0. It's used when// the parceled object includes a file descriptor.@Overridepublic int describeContents()    {        return 0;    }    @Overridepublic void writeToParcel(Parcel dest, int flags)    {        dest.writeInt(myFirstVariable);        dest.writeString(mySecondVariable);        dest.writeLong(myThirdVariable);    }    // Note that this seemingly random field IS NOT OPTIONAL. The system will// look for this variable using reflection in order to instantiate your// parceled object when read from an Intent.public static final Parcelable.Creator<Foo> CREATOR = new Parcelable.Creator<Foo>()    {        // This method is used to actually instantiate our custom object// from the Parcel. Convention dictates we make a new constructor that// takes the parcel in as its only argument.public Foo createFromParcel(Parcel in)        {            return new Foo(in);        }        // This method is used to make an array of your custom object.// Declaring a new array with the provided size is usually enough.public Foo[] newArray(int size)        {            return new Foo[size];        }    };}

Activty之间传递数据并且返回

举个栗子

MainActivity向DetailActivity传递数据,并且等待返回,MainActivity需要重写 onActivityResult(int requestCode, int resultCode, Intent data)方法,其中requestCode用于唯一标识请求的是DetailActivity,resultCode代表是请求的状态

粗暴的代码示例

MainActivity:public class MainActivity extends Activity {    // Use a unique request code for each use case private static final int REQUEST_CODE_EXAMPLE = 0x9345;     @Overrideprotected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        // Create an Intent to start DetailActivityfinal Intent intent = new Intent(this, DetailActivity.class);        // Start DetailActivity with the request code        startActivityForResult(intent, REQUEST_CODE_EXAMPLE);    }    // onActivityResult only get called // when the other Activity previously started using startActivityForResult@Overridepublic void onActivityResult(int requestCode, int resultCode, Intent data) {        super.onActivityResult(requestCode, resultCode, data);        // First we need to check if the requestCode matches the one we used.if(requestCode == REQUEST_CODE_EXAMPLE) {            // The resultCode is set by the DetailActivity// By convention RESULT_OK means that whatever// DetailActivity did was executed successfullyif(resultCode == Activity.RESULT_OK) {                // Get the result from the returned Intentfinal String result = data.getStringExtra(DetailActivity.EXTRA_DATA);                // Use the data - in this case, display it in a Toast.                Toast.makeText(this, "Result: " + result, Toast.LENGTH_LONG).show();            } else {                // setResult wasn't successfully executed by DetailActivity // Due to some error or flow of control. No data to retrieve.            }        }    }}DetailActivity:public class DetailActivity extends Activity {    // Constant used to identify data sent between Activities.public static final String EXTRA_DATA = "EXTRA_DATA";    @Overrideprotected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_detail);        final Button button = (Button) findViewById(R.id.button);        // When this button is clicked we want to return a result        button.setOnClickListener(new View.OnClickListener() {            @Overridepublic void onClick(View view) {                // Create a new Intent object as container for the resultfinal Intent data = new Intent();                // Add the required data to be returned to the MainActivity                data.putExtra(EXTRA_DATA, "Some interesting data!");                // Set the resultCode as Activity.RESULT_OK to // indicate a success and attach the Intent// which contains our result data                setResult(Activity.RESULT_OK, data);                 // With finish() we close the DetailActivity to // return back to MainActivity                finish();            }        });    }    @Overridepublic void onBackPressed() {        // When the user hits the back button set the resultCode // as Activity.RESULT_CANCELED to indicate a failure        setResult(Activity.RESULT_CANCELED);        super.onBackPressed();    }}

注意事项

1.数据会立即返回,在调用finish()之后,所以setResult()方法需要在finish()之前调用,否否则数据不会返回。

2.确定你的Activity没有使用android:launchMode="singleTask”启动模式,否则他会在一个单独的task,这样数据也不会返回。如果你的Activity使用singleTask启动,那么会立即调用onActivityResult(),并且返回result code o是Activity.RESULT_CANCELED.

3.谨慎的使用android:launchMode="singleInstance”。在 Lollipop (Android 5.0, API Level 21)之前,不会返回数据。


Activity之间传递数据一般通过以下几种方式实现:

1. 通过intent传递数据

2. 通过Application

3. 使用单例

4. 静态成员变量。(可以考虑 WeakReferences

5. 持久化(sqlite、share preference、file等)

一、通过intent传递数据

(1)直接传递,intent.putExtra(key, value)

(2)通过bundle,intent.putExtras(bundle);

TL:

(1)这两种都要求传递的对象必须可序列化(Parcelable、Serializable)

(2)Parcelable实现相对复杂

(3)关于Parcelable和Serializable,官方说法:

Serializable: it's error prone and horribly slow. So in general: stay away from Serializable if possible.

     也就是说和Parcelable相比,Seriaizable容易出错并且速度相当慢。是否这样,可参见下一篇博客说明。

(4)通过intent传递数据是有大小限制滴,超过限制,要么抛异常,要么新的Activity启动失败,所以还是很严重的。

Activity之间使用Parcel传递大量数据产生的问题。

Activity之间通过intent传递大量数据,导致新Activity无法启动。

比较常用的是直接利用intent传递,比如使用bundle,如下:

Intent intent =new Intent(ActivityA.this,ActivityB.class); Bundle bundle =new Bundle();bundle.putParcelableArrayList("data", dataList);intent.putExtras(bundle);startActivity(intent);

问题:当传递数据量过大,比如list的size过大,会导致B无法启动。现象即启动失败,activityB的oncreate()都不会执行。


分析:

官方文档提到TransactionTooLargeException异常,“The Binder transaction failed because it was too large.”即传输数据过大异常。

并且提到这样一句话:“Parcel objects stored in the Binder transaction buffe”,这表明实际上底层parcel对象在不同activity直接传递过程中保存在一个叫做“ Binder transaction buffe”的地方,既然是缓冲区,肯定有大小限制。

官方文档还提到

“The Binder transaction buffer has a limited fixed size, currently 1Mb, which is shared by all transactions in progress for the process. Consequently this exception can be thrown when there are many transactions in progress even when most of the individual transactions are of moderate size.”

即缓冲区最大1MB,并且这是该进程中所有正在进行中的传输对象所公用的。至于都有哪些传输对象、具体怎么分配,这个还不太清楚。可以肯定的是Activity之间使用Parcel传输数据是有大小限制的。那么在传输大小可能很大的情况下就要做点处理了。

-------

另外,

该博客“Yet another post on Serializable vs Parcelable”中在对比Serializable和Parcel时提到以下两点数据,仅供参考了解,实际使用各有不同

1. 使用Serializable和parcel传输相同对象,都转换为byte[]后,parcel大概是serializable的20倍了。

2. 但是官方建议使用Parcel,原因是说速度是serializable的将近10倍。

Serializable: it's error prone and horribly slow. So in general: stay away from Serializable if possible.

Parcelable: If you want to pass complex user-defined objects, take a look at the Parcelable interface. It's harder to implement, but it has considerable speed gains compared to Serializable.

但是有时候出现该问题时居然不报错(我遇到的就没抛异常),甚至没有特殊的log(adb logcat -v threadtime -s ActivityManager 、adb logcat -b events)

并没有像文章或者官方文档中提到的“ throwing a TransactionTooLargeException (or just logging E: !!! FAILED BINDER TRANSACTION !!! on pre 15 API levels)”

比较奇葩!

---------

针对parcel传递数据大小限制,自个儿做了个简单实验:

机型:Galaxy Nexus

系统:4.1.2  sdk16

过程:ActivityA,ActivityB,DataBean(每个对象大概200byte),A启动B并使用Parcel对象传递list<dataBean>。

当list大小为900个时,无法启动B。即传输数据大概在200*900 < 200k

所以按照官方解释,对于具体某一次Activity间传输的限制大小是不确定的,依据使用环境而定。

解决方法:

一. 限制传递数据量

二. 改变数据传输方式

1. 静态static

2. 单例

3. Application

4. 持久化

二、Application

   这个应该也都接触过,将数据保存早全局Application中,随整个应用的存在而存在,这样很多地方都能访问。具体使用就不多说了。

但是需要注意的是:

  当由于某些原因(比如系统内存不足),我们的app会被系统强制杀死,此时再次点击进入应用时,系统会直接进入被杀死前的那个界面,制造一种从来没有被杀死的假象。那么问题来了,系统强制停止了应用,进程死了,那么再次启动时Application自然新的,那里边的数据自然木有啦,如果直接使用很可能报空指针或者其他错误。

  因此还是要考虑好这种情况的:

  (1)使用时一定要做好非空判断

  (2)如果数据为空,可以考虑逻辑上让应用直接返回到最初的activity,比如用 FLAG_ACTIVITY_CLEAR_TASK 或者 BroadcastReceiver 杀掉其他的activity。

三、使用单例

比如一种常见的写法:

  1. public class DataHolder {
  2. private String data;
  3. public String getData() {return data;}
  4. public void setData(String data) {this.data = data;}
  5. private static final DataHolder holder = new DataHolder();
  6. public static DataHolder getInstance() {return holder;}
  7. }

这样在启动activity之前:

DataHolder.getInstance().setData(data);

新的activity中获取数据:

String data = DataHolder.getInstance().getData();

四、静态Statis

这个可以直接在activity中也可以单独一个数据结构体,就和单例差不多了。

比如:

  1. public class DataHolder {
  2. private static String data;
  3. public static String getData() {return data;}
  4. public static String setData(String data) {this.data = data;}
  5. }

启动之前设置数据,新的activity获取数据。

注意:这些情况如果数据很大很多,比如bitmap,处理不当是很容易导致内存泄露或者内存溢出的。

所以可以考虑使用WeakReferences 将数据包装起来。

比如:

  1. public class DataHolder {
  2. Map<String, WeakReference<Object>> data = new HashMap<String, WeakReference<Object>>();
  3. void save(String id, Object object) {
  4. data.put(id, new WeakReference<Object>(object));
  5. }
  6. Object retrieve(String id) {
  7. WeakReference<Object> objectWeakReference = data.get(id);
  8. return objectWeakReference.get();
  9. }
  10. }

启动之前:

DataHolder.getInstance().save(someId, someObject);
新activity中:
DataHolder.getInstance().retrieve(someId);
这里可能需要通过intent传递id,如果数据唯一,id都可以不传递的。save() retrieve()中id都固定即可。

五、持久化数据

那就是sqlite、share preference、file等了。

优点:

(1)应用中所有地方都可以访问

(2)即使应用被强杀也不是问题了

缺点:

(1)操作麻烦

(2)效率低下

(3)io读写嘛,其实还是比较容易出错的

大家在做项目的过程中都会用到http请求 返回json或者xml类型的数据与服务器端进行交互,但有些情况下数据需要传递到其他的Activity,这样就省去再次调用请求,获得更好的用户体验。接下来就说一说我在做项目中Activity常用的数据传输方式。

1、传递Integer、String等基本类型数据

[java] view plain copy

  1. Intent intent = new Intent();  
  2. intent.setClass(WelcomeActivity.this,MainActivity.class);  
  3. intent.putExtra("name", "张三");  
  4. intent.putExtra("age", 20);  
  5. startActivity(intent); 

接收:

[java] view plain copy

  1. String name = getIntent().getStringExtra("name");  
  2. int age = getIntent().getIntExtra("age", 0); 

2、传递List<String>字符串集合类型的数据

[java] view plain copy

  1. List<String> mList = new ArrayList<String>();  
  2. Intent intent = new Intent();  
  3. intent.setClass(WelcomeActivity.this,MainActivity.class);  
  4. intent.putExtra("mList", (Serializable)mList);  
  5. startActivity(intent); 

List类型的数据传递需要对其进行序列化。

接收:

[java] view plain copy

  1. List<String> list = (List<String>) getIntent().getSerializableExtra("mList"); 

3、传递对象类型数据

[java] view plain copy

  1. Person bean = new Person();  
  2. Intent intent = new Intent();  
  3. intent.setClass(WelcomeActivity.this,MainActivity.class);  
  4. intent.putExtra("bean", (Serializable)bean);  
  5. startActivity(intent); 

对象类型的数据传递需要对其进行序列化。

接收:

[java] view plain copy

  1. Person bean = (Person) getIntent().getSerializableExtra("bean"); 

4、传递List<Class>对象集合数据

[java] view plain copy

  1. <span style="font-size:12px;">List<Person> mList = new ArrayList<Person>();  
  2. Intent intent = new Intent();  
  3. intent.setClass(WelcomeActivity.this,MainActivity.class);  
  4. intent.putExtra("mList", (Serializable)mList);  
  5. startActivity(intent);</span> 

List<Class>类型的数据传递需要对其进行序列化。

接收:

[java] view plain copy

  1. List<Person> list = (List<Person>) getIntent().getSerializableExtra("mList"); 

*  注:  传递对象和对象集合的时候 需要对 对象进行序列化操作 。

来源: http://blog.csdn.net/daiwei714/article/details/45644741

一,简单传递(简单的字符串)

第一个activity通过putExtra()将字符串传入i

0.5084665575996041

 1  protected void onCreate(Bundle savedInstanceState) { 2         super.onCreate(savedInstanceState); 3         setContentView(R.layout.activity_main); 4         findViewById(R.id.btnStartAty).setOnClickListener(new View.OnClickListener() { 5             @Override 6             public void onClick(View v) { 7                 Intent i= new Intent(MainActivity.this,TheAty.class); 8                 i.putExtra("date","Hello SWWWWWW"); 9                 startActivity(i);1011             }12         });13     }

0.681459242478013

第二个activity通过getIntent()获取之前put进来的数据,然后再set到UI界面中去

0.8189673407468945

  
  private TextView tv;

1 protected void onCreate(Bundle savedInstanceState) {2 super.onCreate(savedInstanceState);3 setContentView(R.layout.activity_the_aty);45 Intent i =getIntent();67 tv=(TextView) findViewById(R.id.tv);

      //通过“date”关键字进行添加8 tv.setText(i.getStringExtra("date"));9 }

0.9365342517849058

二,通过 包Bundle进行传递

通过首先将数据传入Bundle包,然后将bundle包放入第二个activity

然后再通过第二个activity获取这个包

0.7428791734855622

 1  protected void onCreate(Bundle savedInstanceState) { 2         super.onCreate(savedInstanceState); 3         setContentView(R.layout.activity_main); 4         findViewById(R.id.btnStartAty).setOnClickListener(new View.OnClickListener() { 5             @Override 6             public void onClick(View v) { 7                 Intent i= new Intent(MainActivity.this,TheAty.class); 8                 Bundle b=new Bundle(); 9                 b.putString("name","SWWWWW");10                 b.putInt("age",21);11                 b.putString("depart","KuaiJi");12                 i.putExtras(b);13                 startActivity(i);1415             }16         });17     }

0.27849100064486265

第二个activity获取包时:

0.3458936889655888

1
private TextView tv;
 
protected void onCreate(Bundle savedInstanceState) {2 super.onCreate(savedInstanceState);3 setContentView(R.layout.activity_the_aty);45 Intent i =getIntent();6 Bundle data=i.getExtras();7 tv=(TextView) findViewById(R.id.tv);8 tv.setText(String.format("name=%s,age=%d,depart=%s",data.getString("name"),data.getInt("age"),data.getString("depart")));9 }

0.40535818552598357

个人觉得,最后一行format()中的那一段,类似于C语言中的printf~

三,传递一个对象

<一>Serializable接口

首先创建一个类User.java

构造方法User()、getter()和setter()需要创建

Serializable操作简单,只需要一句即可。但是相对来说效率比较低

后面我会介绍另一种方法:继承Parcelable接口

0.5508243655785918

 1 public class User implements Serializable{ 2     private String name; 3     private int age; 4 5     public String getName() { 6         return name; 7     } 8 9     public void setName(String name) {10         this.name = name;11     }1213     public int getAge() {14         return age;15     }1617     public void setAge(int age) {18         this.age = age;19     }20     public User(String name, int age){21         this.name=name;22         this.age=age;23     }24 }

0.24769215239211917

同样的,new的一个新的类压入到Intent i中去

然后通过后面一个activity中getIntent()出来

MainActivity动作:

0.8339141104370356

 1 protected void onCreate(Bundle savedInstanceState) { 2         super.onCreate(savedInstanceState); 3         setContentView(R.layout.activity_main); 4         findViewById(R.id.btnStartAty).setOnClickListener(new View.OnClickListener() { 5             @Override 6             public void onClick(View v) { 7                 Intent i= new Intent(MainActivity.this,TheAty.class); 8 9                 i.putExtra("user",new User("SWWWW",21));10                 startActivity(i);1112             }13         });14     }

0.4308382351882756

TheAty动作:

0.12875181483104825

private TextView tv;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_the_aty);        Intent i =getIntent();//        Bundle data=i.getExtras();            tv=(TextView) findViewById(R.id.tv);//        //tv.setText(i.getStringExtra("date"));//        tv.setText(String.format("name=%s,age=%d,depart=%s",data.getString("name"),data.getInt("age"),data.getString("depart")));        User user= (User) i.getSerializableExtra("user");        tv.setText(String.format("User info(name=%s, age=%d)",user.getName(),user.getAge()));    }

0.2719520144164562

<二>继承Parcelable接口

同样的,先写一个User.java类

这里比较麻烦的就是必须要重写两个函数:

writeToParcel和describeContents 即代码的最后两个函数

第一个不需要改变

第二个则模拟了第一个方法中的读取方法,不过是我们程序猿手写。但是效率高。

为了代码更优,还是建议大家使用这种方法。

 

0.1521828242111951

public class User implements Parcelable {    private String name;    private int age;    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 User(String name, int age){        this.name=name;        this.age=age;    }    protected User(Parcel in) {        name = in.readString();        age = in.readInt();    }    public static final Creator<User> CREATOR = new Creator<User>() {        @Override        public User createFromParcel(Parcel in) {            return new User(in.readString(),in.readInt());        }        @Override        public User[] newArray(int size) {            return new User[size];        }    };    @Override    public int describeContents() {        return 0;    }    @Override    public void writeToParcel(Parcel dest, int flags) {        dest.writeString(getName());        dest.writeInt(getAge());    }}

0.8063553189858794

最后还需要改动的一点是:

User user= (User) i.getSerializableExtra("user");

需要改为:
User user=i.getParcelableExtra("user");

2.Activity启动模式

启动模式有四种,分别是:standard、singleTop、singleTask、singleInstance,

可以在AndroidManifest.xml文件中通过给<Activity>标签指定android:launchMode属性来选择启动模式。


1. standard

standard是活动默认的启动模式,在不进行显示指定的情况下,所有活动都会自动使用这种启动模式。

Android是使用返回栈来管理活动的,在standard模式下,每当启动一个新的活动,它就会在返回栈中入栈,并处理栈顶的位置。

对于使用standard模式的活动,系统不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建该活动的一个新的实例。

例如:应用启动显示的活动是A,A中启动了B,B中启动了C,活动A、B、C的启动模式都是standard模式的,这时候你如果想退出这个应用,需要点击三次Back键才可以。

同样的,如果我们在活动A中,点击按钮Button启动了活动A,然后再点击按钮Button,又启动了A,这时候返回栈中有三个活动A,需要点击三次Back键才能退出应用。


2. singleTop

使用singleTop模式时,在启动活动的时候,如果返现返回栈的栈顶已经是该活动,则认为可以直接使用,不会再创建新的该活动的实例。

例如,系统默认启动了活动A,在活动A中,点击按钮Button启动了活动A,然后再点击按钮Button,又启动了A,这时候返回栈中其实仍旧只有一个活动A,我们只需要点击一次Back键就能退出应用,活动A是singleTop模式的。

同样的,应用中有A、B两个活动,它们的启动模式都是singleTop,应用启动A,然后A启动了B,B又启动了A活动,这时候返回栈中其实有两个A,一个B,我们需要点击三次Back键才能退出应用。

3. singleTask

使用singleTask模式时,每次启动活动的时候,系统首先会在返回栈中检查是否存在该活动的实例,如果发现已经存在该活动的实例,直接使用该实例,并把这个活动之上的所有活动统统出栈,如果没有发现就会创建一个新的活动实例。

例如,应用默认启动了活动A,活动A是singleTask模式的,然后A启动了B,B启动了C,C又启动了A,这时候返回栈中其实只有一个A,B、C都已经被出栈,只需要点击一次Back键就可以退出应用。

4. singleInstance

使用singleInstance模式的活动,会有一个单独的返回栈来管理这个活动,一般来说,这种模式是可以用来实现其他应用程序和我们的程序可以共享这个活动的实例的,不管是哪个应用程序来访问这个活动,都共用的同一个返回栈。

例如,应用默认启动了活动A,A启动了活动B,活动B是singleInstance模式的,然后活动B启动了C,我们点击Back键,会从C跳转到活动A,因为A和C在一个返回栈,而B是另一个返回栈,在点击Back键,A跳到了B,再点击Back键,退出程序。






3.Activity启动过程分析




<二>Activity的生命周期

如图【图片是借用别人的】,

0.07675052271224558

Activity的“整个生命周期”是发生在第一次调用onCreate(Bundle)和唯一最后调用onDestroy()方法之间。在onCreate(Bundle)方法中完成活动的初始化操作设置全局状态,比如加载布局、绑定事件等,并在onDestroy()方法释放资源。

Activity的“显示生命周期”是发生在调用onStart()方法以及调用相对应的onStop()方法之间。在这之间,可以在手机屏幕上看到这个活动。随着Activity对用户的可见和不可见状态的改变,这两个方法能被多次调用。

Activity的“前台生命周期”是在onResume()和onPause()方法之间所经历的,在这个周期内,活动处于运行状态,此时的活动是可以和用户进行交互的。

我个人的方法是:创建一个app,然后在Activity的代码中把这些方法全部重写出来,为每个方法打上断点(或者日志输出),Debug进行调试,就基本上明白了什么时候会被调用。

<三>Activity的启动和Activity之间的数据传递

这里我们需要用到一个对象Intent,Intent是Android程序中各组件之间进行交互的一种重要方式,它一般可被用于启动活动、启动服务、以及发送广播等场景,关于它的用法后面再详细说。

1. 简单的启动新的Activity

使用的方法:startActivity(Intent)

示例:

0.6962726139463484

Intent _intent = new Intent();_intent.setClass(MainActivity.this, ActivityB.class);startActivity(_intent);

//这个调用方法也可以写成

Intent _intent2 = new Intent(MainActivity.this,ActivityB.class);
startActivity(_intent2);

0.5626824665814638

实例化一个Intent对象,然后指定从当前的MainActivity这个活动,跳转到ActivityB这个活动。

2. 启动新的Activity,并有返回值

使用方法:public void startActivityForResult(Intent intent, int requestCode),注意第二个参数:requesCode,这个参数类似于当初特工接头时的暗号,

示例:

1. 应用从活动MainActivity跳转到ActivityC,并请求一个字符串;

2. 在活动Activity中操作,关闭活动ActivityC时,返回请求的字符串给MainActivty;

3.活动MainActivity获取字符串。

0.09282873151823878

    class ButtonActivitiesClickListener implements OnClickListener {        @Override        public void onClick(View v) {             if (v.getId() == R.id.btnSkipToC) {             Intent _intent = new Intent();             _intent.setClass(MainActivity.this, ActivityC.class);                         startActivityForResult(_intent, 100);                         }        }    }

0.6852403122466058

注意,这里就是启动新的活动ActivityC,暗号requestCode是100。

在活动ActivityC中,点击关闭按钮时用void setResult (int resultCode, Intent data)传回请求的字符串,

0.6582640870474279

    class ButtonActivityAListener implements OnClickListener {        @Override        public void onClick(View v) {            if (v.getId() == R.id.btnreturn) {                Intent _intent = new Intent();                EditText editText = (EditText) findViewById(R.id.edittext_first);                String inputStr = editText.getText().toString();                _intent.putExtra("dashenzaijia", inputStr);                setResult(Activity.RESULT_OK, _intent);                finish();            }        }    }

0.4162046010605991

备注:Intent.putExtra(String name, String value)类似于一个数据字典,这个Intent就是ActivityC返回字符串给MainActivity的载体,name就是键,finish()方法类似于winform中的Close();

关闭活动ActivityC后,然后再MainActivity中,有一个虚方法,重载一下,然后从这个方法里面获取ActivityC的返回值,如下:

0.2442143796943128

    @Override    protected void onActivityResult(int arg0, int arg1, Intent arg2) {        // TODO Auto-generated method stubsuper.onActivityResult(arg0, arg1, arg2);        if (arg0 == 100 && arg1 == Activity.RESULT_OK) {            String returnValue = arg2.getStringExtra("dashenzaijia");            TextView view = (TextView) this.findViewById(R.id.textview_showresult);            if (!returnValue.isEmpty()) {                view.setText("来自Activity C的值:" + returnValue);            } else {                view.setText(null);            }        }    }

0.07043638196773827

第一个参数就是当初定义的两个活动之间的暗号,第二个参数是跳转后页面的关闭时的结果,类似于C# 里面窗体关闭时的DialogResult,第三个参数就是返回值的载体。

<四>活动的启动模式

启动模式有四种,分别是:standard、singleTop、singleTask、singleInstance,可以在AndroidManifest.xml文件中通过给<Activity>标签指定android:launchMode属性来选择启动模式。

1. standard

standard是活动默认的启动模式,在不进行显示指定的情况下,所有活动都会自动使用这种启动模式。Android是使用返回栈来管理活动的,在standard模式下,每当启动一个新的活动,它就会在返回栈中入栈,并处理栈顶的位置。对于使用standard模式的活动,系统不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建该活动的一个新的实例。

例如:应用启动显示的活动是A,A中启动了B,B中启动了C,活动A、B、C的启动模式都是standard模式的,这时候你如果想退出这个应用,需要点击三次Back键才可以。

同样的,如果我们在活动A中,点击按钮Button启动了活动A,然后再点击按钮Button,又启动了A,这时候返回栈中有三个活动A,需要点击三次Back键才能退出应用。

2. singleTop

使用singleTop模式时,在启动活动的时候,如果返现返回栈的栈顶已经是该活动,则认为可以直接使用,不会再创建新的该活动的实例。

例如,系统默认启动了活动A,在活动A中,点击按钮Button启动了活动A,然后再点击按钮Button,又启动了A,这时候返回栈中其实仍旧只有一个活动A,我们只需要点击一次Back键就能退出应用,活动A是singleTop模式的。

同样的,应用中有A、B两个活动,它们的启动模式都是singleTop,应用启动A,然后A启动了B,B又启动了A活动,这时候返回栈中其实有两个A,一个B,我们需要点击三次Back键才能退出应用。

3. singleTask

使用singleTask模式时,每次启动活动的时候,系统首先会在返回栈中检查是否存在该活动的实例,如果发现已经存在该活动的实例,直接使用该实例,并把这个活动之上的所有活动统统出栈,如果没有发现就会创建一个新的活动实例。

例如,应用默认启动了活动A,活动A是singleTask模式的,然后A启动了B,B启动了C,C又启动了A,这时候返回栈中其实只有一个A,B、C都已经被出栈,只需要点击一次Back键就可以退出应用。

4. singleInstance

使用singleInstance模式的活动,会有一个单独的返回栈来管理这个活动,一般来说,这种模式是可以用来实现其他应用程序和我们的程序可以共享这个活动的实例的,不管是哪个应用程序来访问这个活动,都共用的同一个返回栈。

例如,应用默认启动了活动A,A启动了活动B,活动B是singleInstance模式的,然后活动B启动了C,我们点击Back键,会从C跳转到活动A,因为A和C在一个返回栈,而B是另一个返回栈,在点击Back键,A跳到了B,再点击Back键,退出程序。

关于Activity的最基本的一些知识就说完了。

来源: http://www.cnblogs.com/yuqf/p/5365472.html

原创粉丝点击