Android四大组件之一 活动

活动(Activity)是一种可包含用户界面的组件,主要用于和用户交流;是Android四大组件之一;一个app可以看到的界面大多数是由activity组成的。关于Activity的总结主要分为Activity的生命周期、四种启动方式、启动创建原理三个方面。主要参考书籍《第一行代码》、《Android开发与艺术探索》。
一、Activity创建、重要方法、生命周期
1.Android四大组件必须在AndroidManifest.xml中声明

<!--.MainActivity的“.”是应用的包名-->
<activity android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

2.Activity的一些重要方法

package com.mrdouya.myactivity;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends Activity {

    private final String TAG = "MrDouYa";

    /**
    *Activity在创建的时候调用,用于初始化资源绑定布局
    */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG,"MainActivity--> onCreate!");
    }

    /**
    *Activity正在被启动的时候调用,已经可见但是不能和用户进行交互,在后台
    */
    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG,"MainActivity--> onStart!");
    }

    /**
    *Activity在“重新”启动的时候调用,从不可见到可见的状态下调用
    */
    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d(TAG,"MainActivity--> onRestart!");
    }

    /**
    *Activity表示已经处于前台,可见并且可以和用户进行交互,在前台
    */
    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG,"MainActivity--> onResume!");
    }

    /**
    *Activity正在停止,从可见变为不可见的过程,
    *无法和用户进行交互,转向后台
    *1.可能出现直接调用onResume方法,在前台
    *2.可能出现谈框,处于可见后台
    */
    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG,"MainActivity--> onPause!");
    }

    /**
    *Activity表示已经处于后台,不可见,处于暂停状态
    */
    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG,"MainActivity--> onStop!");
    }

    /**
    *Activity开始销毁
    */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG,"MainActivity--> onDestroy!");
    }

    /**
    *Activity被非正常情况下销毁时,调用,用于保存一些Activity数据
    */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.d(TAG,"MainActivity--> onSaveInstanceState!");
    }

    /**
    *Activity被非正常情况下销毁后,重新启动后调用,用于从onSaveInstanceState保存一些数据中恢复
    */
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.d(TAG,"MainActivity--> onRestoreInstanceState!");
    }

    /**
    *Activity在singleTask、singleTop等启动模式下调用
    */
    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Log.d(TAG,"MainActivity--> onNewIntent!");
    }
}

3.Activity的生命周期
3.1正常启动、关闭
在onStart之后开始可见,在onStop之前不可见,均在后台;在onResume可以和用户交互,在onPause不能和用户交互,在前台;onCreate创建初始化,onDestroy毁灭;6个方法高度对称,如log1;在第一个Activity处于onResume时,打开第二个Activity以及第一个Activity被重新启动,会调用生命周期的流程如log2。
log1:

2019-01-03 14:20:46.869 4276-4276/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onCreate!
2019-01-03 14:20:46.876 4276-4276/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onStart!
2019-01-03 14:20:46.887 4276-4276/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onResume!
2019-01-03 14:21:08.148 4276-4276/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onPause!
2019-01-03 14:21:08.556 4276-4276/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onStop!
2019-01-03 14:21:08.557 4276-4276/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onDestroy!

log2:

2019-01-03 19:06:39.704 5576-5576/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onCreate!
2019-01-03 19:06:39.706 5576-5576/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onStart!
2019-01-03 19:06:39.717 5576-5576/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onResume!
//点击启动第二个Activity
2019-01-03 19:06:44.861 5576-5576/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onClick!
2019-01-03 19:06:44.884 5576-5576/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onPause!
2019-01-03 19:06:44.939 5576-5576/com.mrdouya.myactivity D/MrDouYa: SecondActivity-->onCreate
2019-01-03 19:06:44.976 5576-5576/com.mrdouya.myactivity D/MrDouYa: SecondActivity-->onStart
2019-01-03 19:06:44.987 5576-5576/com.mrdouya.myactivity D/MrDouYa: SecondActivity-->onResume
2019-01-03 19:06:45.485 5576-5576/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onSaveInstanceState!
2019-01-03 19:06:45.487 5576-5576/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onStop!
//重新调用第一个Activity,这里没有打印第二个Activity的销毁过程
2019-01-03 19:06:55.885 5576-5576/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onRestart!
2019-01-03 19:06:55.887 5576-5576/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onStart!
2019-01-03 19:06:55.888 5576-5576/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onResume!

生命周期流程图:
在这里插入图片描述
3.2非正常的启动关闭
导致Activity非正常的生命周期的情况有很多,比如横竖屏旋转、手机空间不足被系统回收、Activity的配置改变等等!这些会使Activity销毁或者重新构建,从下面的log可以看到发生这些情况时的生命周期以及方法调用,会在onDestroy前调用onSaveInstanceState保存信息,在重建Activity在onResume调用onCreate、onRestoreInstanceState恢复信息。Activity的信息保存、恢复的数据都是放在Bundle中的,后续在探索,另外在onCreate方法中恢复数据需要对Bundle进行非空判断,onRestoreInstanceState方法则不需要,google更推荐使用后者。系统资源不足时会优先级依次回收后台不可见Activity、后台可见的(当前Acitvity弹出的对话框)、前台Activity。

2019-06-19 15:42:22.734 4451-4451/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onPause!
2019-06-19 15:42:22.736 4451-4451/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onStop!
2019-06-19 15:42:22.738 4451-4451/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onSaveInstanceState!
2019-06-19 15:42:22.738 4451-4451/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onDestroy!
2019-06-19 15:42:22.882 4451-4451/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onCreate!
2019-06-19 15:42:22.890 4451-4451/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onStart!
2019-06-19 15:42:22.891 4451-4451/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onRestoreInstanceState!
2019-06-19 15:42:22.894 4451-4451/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onResume!

生命周期流程图:
在这里插入图片描述
当然有方法可以,让Activity在资源配置发生变化时不去重新构建,主要是对它在Androidmanifest.xml中的属性配置,增加configChanges属性中对应的资源变化,多个属性时可以用|链接。当配置了这些属性之后当资源发生变化时不会调用onSaveInstanceState、onRestoreInstanceState方法,而是调用onConfigurationChanged方法,主要有如下几种配置:

//这里是切换横竖屏、隐藏键盘、语言切换还会有很多如mccmnc、屏幕大小等等
android:configChanges="orientation|keyboardHidden|locale"
//log中显示调用onConfigurationChanged方法
2019-06-19 16:20:20.007 6606-6606/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onConfigurationChanged!

3.3常用思维以及处理方式
不宜在onPause、onStop方法中处理耗时任务。

二、Activity的两种启动方法、四种启动模式
主要是从两个维度启动Acitvity,分别是启动模式和启动方法总结。启动方法是以显示或者隐式的方法启动Activity,两者均是先获取Intent对象,将Intent对象传入startActivity方法中启动;区别在与前者是直接制定启动那个Activity,后者通过一些filter去匹配需要启动的Acticity。Activity有standed、singleTop、singleTask、singleInstance四种模式,这直接影响栈activity的存储情况以及activity的关闭开启的先后顺序。
1.启动方法(隐式、显示)
1.1显示启动
主要是startActivity方法中明确指定启动那个Activity

Intent intent = new Intent(this,SecondActivity.class);
startActivity(intent);

1.2隐式启动
需要我们在Intent对象添加过滤器(action、category、data),只有IntentFilter中的过滤信息完全匹配时才可以启动,它们启动规则如下:

//action
//Intent中有且必须至少一个action与intentfilter中action规则一致,区分大小写,前者包含于后者

//Category
//1.默认"android.intent,category.DEFAULT"
//2.当Intent中可以没有Category,如果存在Category那么就必须包含在Intentfilter中的category中(Intent为Intentfilter的子集)

//data
//1.Intent中有且必须至少一个data,并且data要包含于Intentfilter定义的规则内,前者包含于后者
//2.两部份组成:mimeType(媒体类型)和URI
//3.URI的组成:<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
//Scheme指定URI的模式,如:http、file、content等
//Host主机名,如:www.baidu.com
//Port端口,如:80、8086等
//Path指地址,完整路径
//PathPattern指地址,完整路径可带通配符,注意“*”要写成“\\*”,"\"要写成“\\\\”
//patPrefix路径的前缀信息

1.3启动方式的注意
两种启动方式共存时,以显示启动为主。我们在隐式启动时应该判断是否有Acitvity符合条件。ActivityManager中的queryIntentActivities、resolveActivity以及Intent中的resolveActivity,两个resolveActivity都会在没找到符合匹配条件的Activity时返回null。Service的启动也有同样的方法去判断,源码如下:

//ActivityManager,返回成功匹配的Activity的信息,flags设置为MATCH_DEFAULT_ONLY,为了匹配<category android:name="android.intent.category.DEFAULT"/>
4095      public abstract List<ResolveInfo> queryIntentActivities(Intent intent,
4096              @ResolveInfoFlags int flags);
4047      public abstract ResolveInfo resolveActivity(Intent intent, @ResolveInfoFlags int flags);
//Intent.java
7914      public ComponentName resolveActivity(@NonNull PackageManager pm) {
7915          if (mComponent != null) {
7916              return mComponent;
7917          }

1.4startActivityForResult期待返回结果的启动方式
MainActivity.class
启动方法:

case R.id.bt_second_start_activity:
    String data = "Hello Second Activity!";
    Intent mIntent = new Intent(this,SecondActivity.class);
    mIntent.putExtra("Data",data);
    //相比较startActivity多了一个请求码参数
    startActivityForResult(mIntent,1);

回调方法:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode){
        case 1:
            //“1”为启动时的请求码,RESULT_OK是SecondActivity传递的结果码
            if(resultCode == RESULT_OK){
                String ss = data.getStringExtra("Result");
                Log.d(TAG,"MainActivity--> onActivityResult, "+ss);
            }
        default:

    }

}

SecondActivity.class

@Override
public void onCreate( Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //获取MainActivity的intent,并通过它获取数据
    Intent mIntent = getIntent();
    String ss = mIntent.getStringExtra("Data");
    Log.d(TAG,"SecondActivity-->onCreate "+ss);
}

/**
 * 点击返回键时调用
 * intent给需要返回的数据
 * setResult方法很重要,设置结果码,以及回传的intent
 * super.onBackPressed();可以注释掉否则会提前结束或者将操作写在它之前
 */
@Override
public void onBackPressed() {
    //新建Intent回传数据
    Intent intent = new Intent();
    intent.putExtra("Result","Thanks MainActivity");
    //setResult方法添加结果码以及返回数据
    setResult(Activity.RESULT_OK,intent);
    //super.onBackPressed();
    Log.d(TAG,"SecondActivity-->onBackPressed "+Activity.RESULT_OK);
    finish();
}

log:

2019-09-06 08:56:22.318 25131-25131/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onCreate!
2019-09-06 08:56:22.335 25131-25131/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onStart!
2019-09-06 08:56:22.337 25131-25131/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onResume!
2019-09-06 08:56:45.008 25131-25131/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onPause!
2019-09-06 08:56:45.056 25131-25131/com.mrdouya.myactivity D/MrDouYa: SecondActivity-->onCreate Hello 
Second 
2019-09-06 08:56:45.091 25131-25131/com.mrdouya.myactivity D/MrDouYa: SecondActivity-->onStart
2019-09-06 08:56:45.094 25131-25131/com.mrdouya.myactivity D/MrDouYa: SecondActivity-->onResume
2019-09-06 08:56:45.658 25131-25131/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onStop!
2019-09-06 08:56:45.660 25131-25131/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onSaveInstanceState!
2019-09-06 08:56:49.281 25131-25131/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onActivityResult, Thanks 
MainActivity
2019-09-06 08:56:49.282 25131-25131/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onRestart!
2019-09-06 08:56:49.284 25131-25131/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onStart!
2019-09-06 08:56:49.286 25131-25131/com.mrdouya.myactivity D/MrDouYa: MainActivity--> onResume!

onBackPressed()源码:

3133      public void onBackPressed() {
3134          if (mActionBar != null && mActionBar.collapseActionView()) {
3135              return;
3136          }
3137  
3138          FragmentManager fragmentManager = mFragments.getFragmentManager();
3139  
3140          if (fragmentManager.isStateSaved() || !fragmentManager.popBackStackImmediate()) {
3141              finishAfterTransition();
3142          }
3143      }
3144  

5725      public void finishAfterTransition() {
5726          if (!mActivityTransitionState.startExitBackTransition(this)) {
5727              finish();//被finish掉了
5728          }
5729      }

2、四种启动模式
Android是使用任务栈管理activity的,并且任务栈是“先进后出”的类型,来个形象一点的例子冰糖葫芦,串的时候第一个在最下面,最后一个在最上面;吃的时候从上面吃到下面从最后一个到第一个。我们可以将每个冰糖葫芦理解为一个Activity的实例,竹签理解为任务栈。standard、singleTop、singleTask、singleInstance四种activity的启动模式对任务栈进行优化管理。
(1)、standard标准模式(系统默认模式)
每打开一个activity都会重新创建一个实例
(2)、singleTop栈顶复用模式
如果打开的activity正处于栈顶时,将不会重新创建实例
(3)、singleTask栈内复用模式
先检查是否有适合实例的任务栈,在检查是否有实例。没有适合的任务栈会重建栈;不管正在启动的activity是否处于栈顶,只要栈内存在实例就会将其置于栈顶
(4)、singleInstance单实例模式
新启动的activity将会独立的在一个任务栈中,后续启动都将不会创建新的实例
注意:singleTop、singleTask都不会调用onCreate、onStart方法会调用onNewIntent方法;非Activity类型的context(application context)使用standard模式启动时可能会报错,因为该context没有任务栈,需要给Activity设置一个标志位FLAG_ACITVITY_NEW_TASK

3、Activity的Flag
Activity的标记位有很多,可以配合启动模式使用,它可以设置它的启动模式、运行状态管理等。使Activity不会出现在历史Activity列表中的标记位:FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值