Android四大组件之Activity

  • Android里边有四大组件的概念:即Activity、Service、Broadcast Receiver、Content Provider,而这四大组件中相对于iOS来讲 类似于Activity 对应Controller、 Broadcast Receiver 类似于 NSNotificationCenter,另两个Service 和 Content Provider 在iOS并没有可以与之对应的组件,平台的差异性由此可以体现出来。

  • 本文记录Activity的相关知识以及与iOS的某些方面的异同:

一 生命周期:

官方文档.png
  • onCreate函数 ():函数是你进行初始化的地方,这个也是执行setContentView(View)函数的地方,setContentView(View)函数可以传入一个由XML编制的UI界面,可以使UI和具体实现完全分离。

  • onStart函数:该方法在 onCreate() 方法之后被调用, 当Activity被显示到屏幕上的时候调用此方法.

  • onResume()函数:在 Activity 从 Pause 状态转换到 Active 状态时被调用,,也就是能够获得用户的焦点之前调用此方法.

  • onRestart()函数:当Activity被停止后又被再次启动之前调用此方法.接着将调用onStart()方法.

  • onPause()函数:当第一个Activity通过Intent启动第二个Activity的时候,将调用第一个Activity的onPause()方法.然后调用第二个Activity的onCreate(),onStart(),onResume()方法,接着调用第一个Activity的onStop()方法.如果Activity重新获得焦点,则将调用onResume()方法;如果此Activity进入用户不可见状态,那么将调用onStop()方法.

  • onStop()函数:当第一个Activity被第二个Activity完全覆盖,或者被销毁的时候会调用此方法.如果此Activity还会与用户进行交互,将调用onRestart方法();如果此Activity将被销毁,那么将调用onDestroy()方法.

  • onDestroy()函数:Activity被销毁之前调用此方法.或者是调用finish()方法结束Activity的时候调用此方法.可以在此方法中进行收尾工作,比如释放资源等.

注意:重写某个Activity的这些回调方法的时候需要首先在第一行调用基类Activity的相应的回调方法.比如super.onCreate(),super.onStart()等等.

而iOS的生命周期如下,基本是一样的:

  • alloc: 创建对象,分配空间
  • init (initWithNibName): 初始化对象,初始化数据
  • loadView: 从nib载入视图 ,通常这一步不需要去干涉。除非你没有使用xib文件创建视图
  • viewDidLoad: 载入完成,可以进行自定义数据以及动态创建其他控件
  • viewWillAppear: 视图将出现在屏幕之前,马上这个视图就会被展现在屏幕上了
  • viewDidAppear 视图已在屏幕上渲染完成

当一个视图被移除屏幕并且销毁的时候的执行顺序,这个顺序差不多和上面的相反

  • viewWillDisappear 视图将被从屏幕上移除之前执行
  • viewDidDisappear 视图已经被从屏幕上移除,用户看不到这个视图了
  • dealloc 视图被销毁,此处需要对你在init和viewDidLoad中创建的对象进行释放

可以看出 其实Android和iOS的生命周期可以说是一一对应的

二 通信

通信的方式有很多种,例如:Intent、静态变量、SharedPreference等,此处暂时只讲Intent的方式通信,类比iOS 的

  • Android中的Activity依靠Intent的通信通信方式如下:

Intent是Android四大组件(Activity、Service、BroadcastReceiver、ContentProvider)之间通信的纽带,在Intent中携带数据也是四大组件之间数据通信最常用、最普通的方式。常规写法如下:

//创建用于封装数据的Bundle对象
Bundle bundle = new Bundle();
bundle.putString("name", "奥卡姆");
bundle.putInt("age", 25);

Intent intent = new Intent(MainActivity.this, SecondActivity.class);
//将Bundle对象嵌入Intent中
intent.putExtras(bundle);

下边的为比较简洁的方式

//创建Intent对象
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
//程序自动创建Bundle,然后将对Intent添加的数据装载在Bundle中,对用户透明
intent.putExtra("name", "奥卡姆");
intent.putExtra("age", 25);
startActivity(intent);

然后再第二个Activity中获取数据:

//intent要用this的getIntent()获取
Intent intent = getIntent();
//用intent.getXXXExtra("key-name")或是intent.getXXXExtra("key-name", default-value)获取值
String name = intent.getStringExtra("key1");
int age = intent.getIntExtra("key2", 0);
  • iOS中的Controller(其实View也是类似)通信方式如下:
    iOS的Controller中的通信方式就不依赖于另一个媒介了,可以实例化第二个Controller对象的时候,可以获取到属性直接赋值即可,非常方便。如下
// 实例化对象
let vc = SecondViewContoller()
// 给该对象的属性赋值
 vc.str="second String"
// 跳转
self.navigationController?.pushViewController(vc, animated: true);

三 注册(Android特有)

所有的活动即activity必须要在AndroidManifest.xml中进行注册才能生效
在 application标签下声明添加

    <activity
            android:name=".MainActivity"
            android:label="This is MainActivity" >
            <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="This is SecondActivity" >
        </activity>
  • name:指定注册的活动,为com.exampleactivitytest.MainActivity的缩写,由于<manifest>标签中已经通过package属性指明了程序的包名是com.example.activitytest,所以这里就简略写了.

  • label: 指定活动中标题栏的内容

  • <intent-filter>
    <activity>标签的内部的<intent-filter>标签下的
    <action android:name= "android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" />两句声明。
    用于把该Activity作为本程序的主活动,即点击应用图标后首先打开的activity
    若不是主活动,不需配置<intent-filter>标签里的内容
    若应用程序中没有声明任何一个活动作为主活动,该仍可正常安装的,只是无法在启动器中看到或者打开这个程序。一般都是作为第三方服务供其他的应用在内部进行调用的,类似某些应用快捷支付服务。

Q: 为什么Activity都必须要在AndroidManifest文件中注册呢
A: 官方回答:每个应用的根目录中都必须包含一个 AndroidManifest.xml 文件(且文件名精确无误)。 清单文件向 Android 系统提供应用的必要信息,系统必须具有这些信息方可运行应用的任何代码。此外,清单文件还可执行以下操作:

  • 为应用的 Java 软件包命名。软件包名称充当应用的唯一标识符。
  • 描述应用的各个组件,包括构成应用的 Activity、服务、广播接收器和内容提供程序。它还为实现每个组件的类命名并发布其功能,例如它们可以处理的 Intent 消息。这些声明向 Android 系统告知有关组件以及可以启动这些组件的条件的信息。
  • 确定托管应用组件的进程。
  • 声明应用必须具备哪些权限才能访问 API 中受保护的部分并与其他应用交互。还声明其他应用与该应用组件交互所需具备的权限
  • 列出 Instrumentation 类,这些类可在应用运行时提供分析和其他信息。这些声明只会在应用处于开发阶段时出现在清单中,在应用发布之前将移除。
  • 声明应用所需的最低 Android API 级别
  • 列出应用必须链接到的库

四 Activity的任务栈

应用内的Activity是被任务栈Task来管理的,一个Task中的Activity可以来自不同的应用,同一个应用的Activity也可能不在同一个Task中。默认情况下,任务栈依据栈的后进先出原则管理Activity,但是Activity可以设置一些“特权”打破默认的规则,主要是通过在AndroidManifest文件中的属性android:launchMode或者通过Intent的flag来设置。

  • standard:默认的启动模式,该模式下会生成一个新的Activity,同时将该Activity实例压入到栈中(不管该Activity是否已经存在在Task栈中,都是采用new操作)。例如: 栈中顺序是A B C D ,此时D通过Intent跳转到A,那么栈中结构就变成 A B C D A,点击返回按钮的 显示顺序是 D C B A,依次摧毁。

  • singleTop:在singleTop模式下,如果当前Activity D位于栈顶,此时通过Intent跳转到它本身的Activity(即D),那么不会重新创建一个新的D实例(走onNewIntent()),所以栈中的结构依旧为A B C D,如果跳转到B,那么由于B不处于栈顶,所以会新建一个B实例并压入到栈中,结构就变成了A B C D B。应用实例:三条推送,点进去都是一个activity。

  • singleTask: 在singleTask模式下,Task栈中只能有一个对应Activity的实例。例如:现在栈的结构为A B C D,此时D通过Intent跳转到B(走onNewIntent()),则栈的结构变成了:A B。其中的C和D被栈弹出销毁了,也就是说位于B之上的实例都被销毁了。如果系统已经存在一个实例,系统就会将请求发送到这个实例上,但这个时候,系统就不会再调用通常情况下我们处理请求数据的onCreate方法,而是调用onNewIntent方法。通常应用于首页,首页肯定得在栈底部,也只能在栈底部。

  • singleInstance: singleInstance模式下会将打开的Activity压入一个新建的任务栈中。例如:Task栈1中结构为:A B C,C通过Intent跳转到了D(D的启动模式为singleInstance),那么则会新建一个Task 栈2,栈1中结构依旧为A B C,栈2中结构为D,此时屏幕中显示D,之后D通过Intent跳转到D,栈2中不会压入新的D,所以2个栈中的情况没发生改变。如果D跳转到了C,那么就会根据C对应的启动模式在栈1中进行对应的操作,C如果为standard,那么D跳转到C,栈1的结构为A B C C,此时点击返回按钮,还是在C,栈1的结构变为A B C,而不会回到D。

Intent Flag 启动模式

  • 1、Intent.FLAG_ACTIVITY_NEW_TASK: 使用一个新的task来启动Activity,一般用在service中启动Activity的场景,因为service中并不存在Activity栈。
  • 2、Intent.FLAG_ACTIVITY_SINGLE_TOP : 类似andoid:launchMode="singleTop"
  • 3、Intent.FLAG_ACTIVITY_CLEAR_TOP :类似andoid:launchMode="singleTask"
  • 4、Intent.FLAG_ACTIVITY_NO_HISTORY :使用这种模式启动Activity,当该Activity启动其他Activity后,该Activity就消失了,不会保留在task栈中。例如A B,在B中以这种模式启动C,C再启动D,则当前的task栈变成A B D。

清空任务栈

  • 1、clearTaskOnLaunch: 每次返回该Activity时,都将该Activity之上的所有Activity都清除。通过这个属性可以让task每次在初始化的时候都只有这一个Activity。
  • 2、finishOnTaskLaunch: clearTaskOnLaunch作用在别的Activity身上,而finishOnTaskLaunch作用在自己身上。通过这个属性,当离开这个Activity所在的task,那么当用户再返回时,该Activity就会被finish掉。
  • 3、alwaysRetainTaskState:如果将Activity的这个属性设置为true,那么该Activity所在的task将不接受任何清理命令,一直保持当前task状态,相当于给了task一道”免死金牌”。

五 IntentFilter的匹配模式

  • (1) IntentFilter中的过滤信息有action、category、data;
    为了匹配过滤列表,需要同时匹配过滤列表中的action、category、data信息,否则匹配失败。一个过滤列表中的action、category、data可以有多个,所有的action、category、data分别构成不同类别,同一类别的信息共同约束当前类别的匹配过程。只有一个Intent同时匹配action类别、category类别和data类别才算完全匹配,只有完全匹配才能成功启动目标Activity。此外,一个Activity中可以有多个intent-filter,一个Intent只要能匹配任何一组intenf-filter即可成功启动对应的Activity。
<intent-filter>
    <action android:name="com.aokamu.a" />
    <action android:name="com.aokamu.b" />

    <category android:name="com.ankamu.category.a" />
    <category android:name="com.ankamu.category.b" />
    <category android:name="android.intent.category.DEFAULT" />

    <data android:mimeType="text/plain" />
</intent-filter>
  • (2) action匹配规则
    只要Intent中的action能够和过滤规则中的任何一个action相同即可匹配成功,action匹配区分大小写。

  • (3) category匹配规则
    Intent 中如果有 category 那么所有的 category 都必须和过滤规则中的其中一个category相同,如果没有category的话那么就是默认的category,即android.intent.category.DEFAULT,所以为了Activity能够接收隐式调用,配置多个category的时候必须加上默认的category

  • (4) data匹配规则
    data匹配规则:Intent中必须含有data数据,并且data数据能够完全匹配过滤规则中的某一个data。
    如果要为Intent指定完整的data,必须要调用setDataAndType方法!

六 一些关于Activity的技巧

  • 1、锁定Activity屏幕的运行方向
<activity android:name=".EX01"
 android:label="@string/app_name" 
 android:screenOrientation="portrait">// 竖屏 , 值为 landscape 时为横屏
 </activity>
  • 2、全屏的Activity
// 设置全屏模式
 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 
    WindowManager.LayoutParams.FLAG_FULLSCREEN); 
 // 去除标题栏
 requestWindowFeature(Window.FEATURE_NO_TITLE);
  • 3、在Activity的title中加入进度条
// 不明确进度条
 requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); 
 setContentView(R.layout.main); 
 setProgressBarIndeterminateVisibility(true); 

 // 明确进度条
 requestWindowFeature(Window.FEATURE_PROGRESS); 
 setContentView(R.layout.main); 
 setProgress(5000);

安卓相关文章阅读

Android四大组件之Service
Android四大组件之Activity

参考:《Android开发艺术探索》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容