Android Activity要点

作者:陆金龙    发表时间:2018-03-23 00:23   


Android Activity

1生命周期

 

(1)onCreate: 创建进行Activity的一些初始化工作,比如使用setContentView加载布局,对一些控件和变量进行初始化等。此时Activity还在后台,不可见。

(2)onStart: 启动Activity已经可见,但是还没出现在前台。在Activity的切换以及按Home键返回桌面再切回应用的过程中被多次调用。Bundle数据的恢复在onStart中进行更合适。

3onResume: 继续、重新开始Activity已经出现在前台并且可见了可以打开独占设备

4onPause:pause暂停,要跳到另一个Activity或应用正常退出时执行。此时Activity在前台并可见,可以进行一些轻量级的工作跳转Activity时当一个Activity执行完了onPause方法后另一个Activity才会启动

5onStop:停止,Activity已经不可见,但还在内存中。做一些资源的回收工作。

6onDestroy:毁灭,这个阶段Activity被销毁,不可见,可做释放资源释放及回收工作。

7onRestart:重新开始,从不可见切换回来时调用,Activity在这时可见。

 

2启动模式

启动模式launchMode:默认情况下,使用启动模式:standard。

standard(不复用,每次new)

singleTop复用栈顶实例

有相同的activity在前台于用户交互,则复用这个Activity,会调用Activity.onNewIntent()。

         栈顶不是target Activity,则new一个。

对于新的Intent,要负责onCreate() 和 onNewIntent() 来控制使它适用于所有情况。

singleTask复用栈内实例

有相同的activity在前台于用户交互,则复用这个Activity,会调用Activity.onNewIntent()。

         栈顶不是目标Activity,则清除此activty旧实例以上的所有activity。

启动实例的Intent的flag会被设置Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT

 

注意:会自动地破坏其他的activity,让该实例出现在栈顶。

场景1:入口Activity比较适用这种情况,因为MainActivity再返回就是退出应用。

 场景2:与另一个应用合作,另一个应用拥有调用singleTask activity存在的任务

singleInstance

开辟一个只允许一个activity实例运行的task. 

intent再次启动这个activity,task会被调到前台,其Activity.onNewIntent() 会被调用.

如果这个activity实例要启动一个新activity,那么新activity会在一个新task中运行。

3 MainActivity的声明

作为应用的入口Activity,需要设置intent-filter action为android.intent.action.MAIN,category为android.intent.category.LAUNCHER。

 <activity

    android:name=".MainActivity"

    android:label="@string/app_name"

    android:theme="@style/AppTheme.NoActionBar">

    <intent-filter>

      <action android:name="android.intent.action.MAIN" />

      <category android:name="android.intent.category.LAUNCHER" />

    </intent-filter>

</activity>

4. 详细条目

4.1 简述Activity

四大组件之一,一般一个用户交互界面对应一个activity

 setContentView() ,// 要显示的布局

 button.setOnclickLinstener{

// 对控件注册事件

 }

 activity 是Context的子类,同时实现了window.callback和keyevent.callback, 可以处理与窗体用户交互的事件。

常用的的有FragmentActivitiy,ListActivity  , PreferenceActivity ,TabAcitivty等。

 如果界面有共同的特点或者功能的时候,还会自己定义一个BaseActivity。

4.2 描述Activity生命周期

生命周期描述的是一个类从创建(new出来)到死亡(垃圾回收)的过程中会执行的方法。 在这个过程中,针对不同的生命阶段会调用不同的方法。

      Activity从创建到销毁有多种状态,从一种状态到另一种状态时会激发相应的回调方法,这些回调方法包括:oncreate ondestroy onstop onstart onresume onpause。

      其实这些方法都是两两对应的,onCreate创建与onDestroy销毁;

      onStart可见与onStop不可见;onResume在前台(捕获焦点,可编辑)与onPause暂停。

onRestart方法 在Activity被onStop后,但是没有被onDestroy,再次启动此Activity时就调用onRestart(而不再调用onCreate)方法。

4.3 两个Activity之间跳转时必然会执行哪几个方法

在A里面激活B组件,A 会调用 onPause()方法;然后B 调用onCreate() ,onStart(), onResume() 。

如果B覆盖了窗体, A会调用onStop()方法。 如果B个透明的,或者是对话框的样式, A就不会调用onStop()方法。

4.4 横竖屏切换时候Activity的生命周期

跟清单文件里的配置有关系:

1、默认切屏首先销毁当前activity,然后重新加载,重新调用各个生命周期。

2、设置Activity的android:configChanges="orientation|keyboardHidden|screenSize"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法。

游戏开发中, 屏幕的朝向都是写死的,横竖屏切换的时候,如果有弹窗会被销毁。

4.5  如何将一个Activity设置成窗口的样式

清单文件里的配置样式android:theme="@android:style/Theme.Dialog"

4.6 你后台的Activity被系统回收怎么办?

如果后台的Activity由于某原因被系统回收了,如何在被系统回收之前保存当前状态?

除了在栈顶的activity,其他的都有可能在内存不足的时候被系统回收,一个activity越处于栈底,被回收的可能性越大.

@Override

protected void onSaveInstanceState(Bundle outState) {

               super.onSaveInstanceState(outState);

               outState.putLong("id",1234567890);

            }

@Override

public void onCreate(Bundle savedInstanceState) {

              //判断savedInstanceState如果不为空就取出来

int id = outState.getLong("id",0);

// todo 恢复界面

super.onCreate(savedInstanceState);

           }

  UI控件大多都实现了onSaveInstanceState()方法,当activity被摧毁和重建时, 指定过ID的UI控件会自动保存和恢复状态数据

  备用方案:切换到后台的时把数据保存,在切换到前台时重新获取数据恢复界面

Activity 中 onSaveInstanceState(Bundle outState) 调用时机

  home键最小化时或长按home键,屏幕旋转时, 开启新的Activity,在onPause后调用

Frament 中 onSaveInstanceState(Bundle outState) 调用时机 

  home键最小化时或长按home键 ,按下电源键,托管该Fragment的Activity 旋转时,托管该Fragment的Activity开启新的Activity时,在onPause后调用 

Activity 中 onRestoreInstanceState(Bundle savedInstanceState) 调用时机

  activity“确实”被销毁,在onStart()之后调用onRestoreInstanceState

  没有设置android:configChanges=”orientation|screenSize”,在屏幕旋转时, activity“确实”被销毁,在onStart()之后调用

 

Fragment 中 setRetainInstance方法介绍 

  Fragment还可以通过在onCreate()中setRetainInstance(true)来保存自定义的对象数据。

  设置后,Activity被系统销毁又重新创建时(如屏幕旋转),可以不完全销毁Fragment,成员变量值会保留,恢复时跳过onDestroy()和onCreate()

4.7 如何退出Activity?

退出activity 直接调用 finish () 方法 . //一般用户点击back键,就退出一个activity

退出activity 会执行 onDestroy()方法 .

4.8 如何安全退出已调用多个Activity的Application?

1. 递归退出

 在打开新的Activity时使用startActivityForResult,然后自己加标志,在onActivityResult中处理关闭,在需要关闭的场景下递归关闭前面的所有Activity。

2. 记录打开的Activity,退出时逐个关闭

每打开一个Activity,就记录在application 全集的环境的list里。在需要退出时,关闭(finish)每一个Activity即可。

3. 发送特定广播(可处理多组件的情况):

在需要结束应用时,发送一个特定的广播。

需要关闭activity 注册接受广播的意图,收到广播后,关闭即可。

4. 通过 intent的flag  FLAG_ACTIVITY_CLEAR_TOP来实现

启动多个Activity从A->B->C->D,如果需要从D直接退出程序。

Intent intent = new Intent();   

intent.setClass(D.this, A.class);  

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 

startActivity(intent);  

finish();  

开启A时将会清除该进程空间的所有Activity。

A在Manifest.xml配置启动模式android:launchMode="singleTop"

在A的onNewIntent中处理退出

Override  

protected void onNewIntent(Intent intent) {  

super.onNewIntent(intent);  

  if ((Intent.FLAG_ACTIVITY_CLEAR_TOP & intent.getFlags()) != 0) {  

  finish();  

  }  

}  

4.9 两个Activity之间怎么传递数据?

1. 基本数据类型通过Intent直接传递

intent.putExtra(name,value)  

// 通过intentputExtra 方法 基本数据类型 都传递

intent.getStringExtra("key","value");

Bundle bundle= new  Bundle();

bundle.putShort(key,value);

intent.putExtras(bundle)

 

2. 文件/网络资源通过Intent传递Uri

intent.setData(uri)

Uri uri = Uri.fromFile(file);  //大图片的传递

3. 让对象实现 implements Serializable 接口把对象存放到文件上.  

 //通过 ObjectOutputStream 存储对象 

File file = new File("c:\1.obj");

FileOutputStream fos  = new FileOutputStream(file);

ObjectOutputStream oos = new ObjectOutputStream(fos);      

Student stu = new Student();

oos.writeObject(stu);   

//从文件中把对象读出来  

 ObjectInputStreamois = new ObjectInputStream(arg0);

 Student stu1 = (Student) ois.readObject();

4. 自定义的application类,全局里面存放对象。

4.10 同一个程序不同的Activity放在不同的Task任务栈

Singleinstance 运行在另外的单独的任务栈里面

激活一个新的activity时候, 给intent设置flag FLAG_ACTIVITY_NEW_TASK

这个被激活的activity就会在新的task栈里面。

Intentintent = new Intent(A.this,B.class);

          intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

          startActivity(intent);

4.11 Activity启动模式的应用场景

singleTop 适合接收通知启动的内容显示页面

例如新闻客户端的新闻内容页面,不用每次收到10个新闻推送都打开一个新页面

singleTask适合作为程序入口点

例如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面。

singleInstance适合需要与程序分离开的页面

一个实例在单独的Task中,完全不影响其他Activity。

例如:闹铃提醒界面,将闹铃提醒与闹铃设置分离。

不要用于中间页面 A -> B (singleInstance) -> C,完全退出后,再启动,首先打开的是B