Activity详解(上)

一.Activity的生命周期

 

图例

 

 

 

2.说明

<1> onCreate()

您必须实现此回调,它会在系统创建您的 Activity 时触发。您的实现应该初始化 Activity 的基本组件:例如,您的应用应该在此处创建视图并将数据绑定到列表。最重要的是,您必须在此处调用 setContentView() 来定义 Activity 界面的布局。onCreate() 完成后,下一个回调将是 onStart()。

 

 

<2> onStart()
onCreate() 退出后,Activity 将进入“已启动”状态,并对用户可见。此回调包含 Activity 进入前台与用户进行互动之前的最后准备工作。

 

 

<3> onResume()
系统会在 Activity 开始与用户互动之前调用此回调。此时,该 Activity 位于 Activity 堆栈的顶部,并会捕获所有用户输入。应用的大部分核心功能都是在 onResume() 方法中实现的。

 

 

<4> onPause()
当 Activity 失去焦点并进入“已暂停”状态时,系统就会调用 onPause()。当系统为您的 Activity 调用 onPause() 时,从技术上来说,这意味着您的 Activity 仍然部分可见,但大多数情况下,这表明用户正在离开该 Activity,该 Activity 很快将进入“已停止”或“已恢复”状态。

如果用户希望界面继续更新,则处于“已暂停”状态的 Activity 也可以继续更新界面。例如,显示导航地图屏幕或播放媒体播放器的 Activity 就属于此类 Activity。即使此类 Activity 失去了焦点,用户仍希望其界面继续更新。

您不应使用 onPause() 来保存应用或用户数据、进行网络呼叫或执行数据库事务。

 

 

<5> onStop()
当 Activity 对用户不再可见时,系统会调用 onStop()。出现这种情况的原因可能是 Activity 被销毁,新的 Activity 启动,或者现有的 Activity 正在进入“已恢复”状态并覆盖了已停止的 Activity。在所有这些情况下,停止的 Activity 都将完全不再可见。

 

 

<6> onRestart()
当处于“已停止”状态的 Activity 即将重启时,系统就会调用此回调。onRestart() 会从 Activity 停止时的状态恢复 Activity。

 

 

<7> onDestroy()
系统会在销毁 Activity 之前调用此回调。

此回调是 Activity 接收的最后一个回调。通常,实现 onDestroy() 是为了确保在销毁 Activity 或包含该 Activity 的进程时释放该 Activity 的所有资源。

 

      如果有新的 Activity 或对话框出现在前台,并且局部覆盖了正在进行的 Activity,则被覆盖的 Activity 会失去焦点并进入“已暂停”状态。然后,系统会调用 onPause()。

当被覆盖的 Activity 返回到前台并重新获得焦点时,会调用 onResume()。

 

      如果有新的 Activity 或对话框出现在前台,夺取了焦点且完全覆盖了正在进行的 Activity,则被覆盖的 Activity 会失去焦点并进入“已停止”状态。然后,系统会快速地接连调用 onPause() 和 onStop()。当被覆盖的 Activity 的同一实例返回到前台时,系统会对该 Activity 调用 onRestart()、onStart() 和 onResume()。如果被覆盖的 Activity 的新实例进入后台,则系统不会调用 onRestart(),而只会调用 onStart() 和 onResume()。

     也就是说,如果一个Activity执行了onPause()方法,那么再次回到前台 该Activity执行 onStart()方法和OnResume()方法。

                       如果一个Activity执行了onPause()方法后又执行了onStop方法,那么再次回到前台 该Activity执行 onRestart()方法onStart()方法和onResume()方法。

 

 

 

 

 

二.Activity的启动

 

1. 显式启动

<1> 最常见的

startActivity(new Intent(当前Act.this,要启动的Act.class));

 

<2> 通过Intent的ComponentName

ComponentName cn = new ComponentName("当前Act的全限定类名","启动Act的全限定类名") ;

Intent intent = new Intent() ;

intent.setComponent(cn) ;

startActivity(intent) ; 

 

<3> 初始化Intent时指定包名

Intent intent = new Intent("android.intent.action.MAIN");

intent.setClassName("当前Act的全限定类名","启动Act的全限定类名");

startActivity(intent);

 

 

2.隐式启动:通过Intent-filter的Action,Category或data来实现 这个是通过Intent的 intent-filter**来实现的

 

 

 

 

 

 

三.Activity间的数据传递

 

1.方式一 Intent 方式

传数据

Intent intent=new Intent(SplashActivity.this, MyActivity.class);
intent.putExtra("name","张三");
intent.putExtra("age",25);
intent.putExtra("Id",371695856532415698L);
startActivity(intent);

接收数据

Intent intent=getIntent();
String name=intent.getStringExtra("name");
int age=intent.getIntExtra("age",0);
long Id=intent.getLongExtra("Id",0);


Log.d("TAG", "onCreate方法name----:"+name);
Log.d("TAG", "onCreate方法age----:"+age);
Log.d("TAG", "onCreate方法Id----:"+Id);

结果

onCreate方法name----:张三
onCreate方法age----:25
onCreate方法Id----:371695856532415698

 

 

2.方式二 Bundle 方式

传数据

Intent intent=new Intent(SplashActivity.this, MyActivity.class);
Bundle bundle=new Bundle();
bundle.putString("name","张三");
bundle.putInt("age",25);
bundle.putLong("Id",371695856532415698L);
intent.putExtras(bundle);
startActivity(intent);

接收数据

Intent intent=getIntent();
Bundle bundle=intent.getExtras();
String name=bundle.getString("name","");
int age=bundle.getInt("age",0);
long Id=bundle.getLong("Id",0);


Log.d("TAG", "onCreate方法1name----:"+name);
Log.d("TAG", "onCreate方法1age----:"+age);
Log.d("TAG", "onCreate方法1Id----:"+Id);

结果

onCreate方法1name----:张三
onCreate方法1age----:25
onCreate方法1Id----:371695856532415698

 

注意

无论是Intent 方式还是Bundle方式都还可以传递更多类型的数据,比如

<1> 数组类型

传递
bundle.putStringArray("shuzu",new String[]{"张三","李四","王五"});


接收
String [] shuzu=bundle.getStringArray("shuzu");

 

<2> 集合类型

传递
ArrayList<String> list=new ArrayList<>();
list.add("111");
list.add("222");
list.add("333");
bundle.putStringArrayList("list",list);


接收
ArrayList list =bundle.getStringArrayList("list");

 

<3> 对象类型

   1.将对象转换成Json,然后当成字符串传递。

   

   2.对象通过Serializable,Parcelable序列化。

 

 

<4> Bitmap类型

 

 

<5> 等等其他类型

 

 

注意

如果数据量过大,比如集合数据过大,或是Bitmap图片过大等等,如果还是用Intent传递往往会报错的。所以一般不建议使用Intent或是Bundle方式传递大的数据。

 

 

 

 

 

 

 

四.随时关闭Activity

 

有时我们可能会打开了很多个Activity,突然来个这样的需求,在某个页面可以关掉 所有的Activity并退出程序。

 

 

下面提供一个关闭所有Activity的方法, 就是用一个list集合来存储所有Activity。

 

工具类:

package com.dchealth.patient.XinSui.test;

import android.app.Activity;

import java.util.LinkedList;

public class ActivityCollector {

    public static LinkedList<Activity> activities = new LinkedList<>();

    /**
     * Activity进栈
     */

    public static void addActivityIntoTask(Activity activity) {
        activities.add(activity);
    }

    /**
     * Activity出栈
     */

    public static void removeActivityFromTask(Activity activity) {
        activities.remove(activity);
    }

    /**
     * 关闭所有Activity
     */

    public static void finishAllActivity() {
        for (Activity activity : activities) {
            if (!activity.isFinishing()) {
                activity.finish();
            }
        }
    }

}

 

完全退出App的方法

如果想死整个App,连后台任务都杀死 杀得一干二净的话。

public void AppExit(Context context) {
    try {
         ActivityCollector.finishAll();//关闭所有页面
         ActivityManager activityMgr = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
         activityMgr.killBackgroundProcesses(context.getPackageName());//杀死后台服务
         System.exit(0);//结束进程
        } catch (Exception ignored) {

        }
}

 

清单文件需要添加权限

<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />

 

 

 

 

 

 

 

五.Activity横竖屏切换

 

1.页面没有必要设置横竖屏切换

页面没有必要设置横竖屏切换即在清单文件AndroidManifest中明确设定了Activity的screenOrientation属性

 

代码

<1> 强制此页面横屏显示

清单文件代码

<activity
   android:name=".test.MyActivity"
   android:screenOrientation="landscape">

</activity>

 

<2> 强制此页面数竖屏显示

清单文件代码

<activity
    android:name=".test.MyActivity"
    android:screenOrientation="portrait">

</activity>

显然这种情况不涉及生命周期方法变更。

 

 

 

2.页面要进行横竖屏切换

 

<1> 不设置 android:screenOrientation属性

清单文件代码

<activity
    android:name=".test.MyActivity">
</activity>

 

Activity代码

package com.dchealth.patient.XinSui.test;

import android.content.res.Configuration;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import com.dchealth.patient.XinSui.R;

public class MyActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        Log.d("TAG", "onCreate方法");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d("TAG", "onStart方法");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d("TAG", "onResume方法");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d("TAG", "onPause方法");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d("TAG", "onStop方法");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("TAG", "onDestroy方法");
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.d("TAG", "onConfigurationChanged方法");
    }
}

 

刚刚进入(默认竖屏)

onCreate方法
onStart方法
onResume方法

 

竖屏切换成横屏

onPause方法
onStop方法
onDestroy方法

onCreate方法
onStart方法
onResume方法

 

横屏切换成竖屏

onPause方法
onStop方法
onDestroy方法

onCreate方法
onStart方法
onResume方法

由此可知当不在清单文件中设置android:screenOrientation时 切换屏幕时activity生命周期方法会重复执行,即切换时相当于退出重新进入

并且此时onConfigurationChanged方法并没有执行(竖屏——>横屏,横屏——>竖屏都没有)

 

 

 

<2> 配置android:screenOrientation

清单文件代码

<activity
    android:name=".test.MyActivity"
    android:configChanges="orientation|keyboardHidden|screenSize"
    android:screenOrientation="sensor">
</activity>

 

Activity代码

package com.dchealth.patient.XinSui.test;

import android.content.res.Configuration;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import com.dchealth.patient.XinSui.R;

public class MyActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        Log.d("TAG", "onCreate方法");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d("TAG", "onStart方法");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d("TAG", "onResume方法");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d("TAG", "onPause方法");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d("TAG", "onStop方法");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("TAG", "onDestroy方法");
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.d("TAG", "onConfigurationChanged方法");
    }
}

 

刚刚进入(默认竖屏)

onCreate方法
onStart方法
onResume方法

 

竖屏切换成横屏

onConfigurationChanged方法

 

横屏切换成竖屏

onConfigurationChanged方法

由此可知当在清单文件中设置android:screenOrientation时 切换屏幕时activity生命周期方法不会会重复执行

并且此时onConfigurationChanged方法执行(竖屏——>横屏,横屏——>竖屏都执行一次)

 

 

注意

onConfigurationChanged方法有可能未被调用。

根据正常认知,在AndroidManifest.xml中设置Android:configChanges="orientation“,

然后在Java代码中重写onConfigurationChanged,即不会重复Activity生命周期,而是调用onConfigurationChanged。

 

然而今天这种做法没有效果,什么原因呢。

原来,自从Android 3.2(API 13),screen size也开始跟着设备的横竖切换而改变。

所以,在AndroidManifest.xml里设置的MiniSdkVersion和 TargetSdkVersion属性大于等于13的情况下,

如果你想阻止程序在运行时重新加载Activity,除了设置”orientation“,你还必须设置"ScreenSize"。
 

解决方法:

android:configChanges="orientation|keyboardHidden|screenSize"
android:screenOrientation="sensor"

附 android:screenOrientation 取值及含义 android:screenOrientation设定该活动的方向,该值可以是任何一个下面的字符串

(1) "unspecified"
默认值. 由系统选择显示方向. 在不同的设备可能会有所不同。


(2) "landscape"
横向


(3) "portrait"
纵向


(4) "user"
用户当前的首选方向。


(5) "behind"
与在活动下的活动相同方向。


(6) "sensor"
根据物理方向传感器确定方向. 取决於用户手持的方向, 当用户转动设备, 它跟随改变。


(7) "nosensor"
不经物理方向传感器确定方向. 该传感器被忽略, 所以当用户转动设备, 显示不会跟随改变. 除了这个区别,系统选择使用相同的政策取向对於“未指定”设置. 系统根据“未指定”("unspecified")设定选择相同显示方向。

 

 

 

 

 

 

 

六.保存和恢复界面瞬态

 

1.简介

用户期望 Activity 的界面状态在整个配置变更(例如旋转或切换到多窗口模式)期间保持不变。然而,发生此类配置变更时,系统会默认销毁 Activity,从而消除存储在 Activity 实例中的所有界面状态。同样,如果用户暂时从您的应用切换到其他应用,并在稍后返回您的应用,他们也希望界面状态保持不变。但是,当用户离开应用且您的 Activity 停止时,系统可能会销毁您应用的进程。

 

系统用于恢复先前状态的已保存数据称为实例状态,是存储在 Bundle 对象中的键值对集合。默认情况下,系统使用 Bundle 实例状态来保存 Activity 布局中每个 View 对象的相关信息(例如在 EditText 控件中输入的文本值)。这样,如果您的 Activity 实例被销毁并重新创建,布局状态便会恢复为其先前的状态,且您无需编写代码。但是,您的 Activity 可能包含您要恢复的更多状态信息,例如追踪用户在 Activity 中的进程的成员变量。

 

如要保存持久化数据(例如用户首选项或数据库中的数据),您应在 Activity 位于前台时抓住合适机会。如果没有这样的时机,您应在执行 onStop() 方法期间保存此类数据。

 

注意:

  <1> 为了使 Android 系统恢复 Activity 中视图的状态,每个视图必须具有 android:id 属性提供的唯一 ID。

 

   <2> Bundle 对象并不适合保留大量数据,因为它需要在主线程上进行序列化处理并占用系统进程内存。

 

 

 

2.几个方法

onSaveInstanceState方法:保存数据

onPause方法之后onStop方法之前调用

 

 

onRestoreInstanceState方法:取出数据

onStar方法之后onResume方法之前调用

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值