记录学习Android基础的心得03:活动activity和意图intent


前言

一花一世界,一叶一追寻。一曲一场叹,一生为一人。活动activity是学习Android的第一个组件,了解其作用,生命周期,回调方法,使用方法是必要的。意图intent作为“通信的使者”,封装了组件之间的“启动意图”,却不与任何组件耦合,通过这种方式可以很好的提高系统的可扩展性和可维护性,需要掌握其各个属性的作用和设置方式。

一、Activity作用及其生命周期

1.Activity作用

众所周知,Android开发采用页面视图和逻辑代码分离的方式进行,在逻辑代码中的activity正代表了一个屏幕,可以往屏幕里塞各种控件,如下是新创建的默认MainActivity:

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

显然,它继承自AppCompatActivity,间接继承Activity基类,打开在线API开发手册
public class Activity
extends ContextThemeWrapper implements LayoutInflater.Factory2, Window.Callback, KeyEvent.Callback, View.OnCreateContextMenuListener, ComponentCallbacks2
已知的直接子类:
AccountAuthenticatorActivity, ActivityGroup, AliasActivity, ExpandableListActivity, FragmentActivity, ListActivity, NativeActivity
已知的间接子类:
ActionBarActivity, AppCompatActivity, LauncherActivity, PreferenceActivity, TabActivity

几乎所有Activity都与用户交互,所以Activity类负责创建一个窗口,可以在其中使用setContentView放置UI。 为了管理应用程序界面中的各组件,需要调用activity的findViewById方法来获取程序界面中的组件,接下来修改各组件的属性和方法即可。不同的Activity可以展示不同的操作界面,多个Activity组成Activity栈,当前活动的Activity位于栈顶。

2.Activity生命周期

正如人的生老病死,Activity也有自己的生命周期。参见官方文档:

在这里插入图片描述
不得不佩服这些API设计大师,他们把Activity从创建到销毁的整个生命中出现的任何情况都考虑到了。
在这里插入图片描述
一般来说,一个活动的生命周期:
onCreate:
创建页面,在第一次创建活动时调用(只会回调一次),把页面上各个元素加载到内存中,所以这里应设置所有常规静态操作:创建视图,将数据绑定到列表等。此方法提供了一个Bundle 参数:savedInstanceState包含活动先前冻结状态(如果存在)。
onRestart:
重启页面,在活动停止之后,再次开始之前调用,重新加载内存中的页面数据。
onStart:
开始页面,把页面显示在屏幕上,活动对用户可见时调用。
onResume:
恢复页面,让页面在屏幕上活动起来,如获得焦点,开启动画,开始任务。
onPause:
暂停页面,在系统将要开始恢复上一个活动时调用,让页面在屏幕上的动作停下来。通常,此方法用于停止动画和可能消耗CPU的其他操作。此方法的实现必须非常快,因为在此方法返回之前,下一个活动将不会恢复。
onStop:
停止页面,当活动不再对用户可见时调用,把页面从屏幕上撤下来(只会回调一次),因为另一个活动已经恢复并且正在覆盖该活动。这可能是由于新活动正在启动,现有活动被带到该活动的前面或该活动被销毁而导致的。
onDestroy:
销毁页面,活动销毁之前最后一个回调的方法,把页面从内存中清除掉。这可能是由于活动即将结束(调用finish,或者因为系统正在临时销毁该活动实例以节省空间。可以使用该isFinishing方法在这两种情况之间进行区分。)
测试
重写所有的回调函数,并添加打印语句,观察三种情况下activity的回调顺序:
1.从竖屏切换到横屏:onCreate ~ onStart ~ onResume ~ onPause ~ onStop ~ onDestroy ~ onCreate ~ onStart ~ onResume,显然activity经历了从完全创建到完全销毁,再完全创建的生命周期。
2.从一个activity启动另一个activity然后点击返回按键:上一个页面onPause ~ 下一个页面onCreate ~ onStart ~ onResume ~上一个页面 onStop 。点击返回键,出现的回调为:下一个页面onPause ~ 上一个页面onReStart ~ onStart ~ onResume ~ 上一个页面 onStop ~ onDestroy。
3.按Home键回到桌面,使用任务管理器又回到此应用:onCreate ~ onStart ~ onResume ~ onPause ~ onStop ~ onReStart ~ onStart ~ onResume。

二、创建Activity及其4种加载模式

1.创建Activity

新建Activity很简单,只需在放置代码的目录下鼠标右键,new ~ Activity ~ Empty Activity,出现Activity配置界面:
在这里插入图片描述
设置好名字和对应的布局文件名字,点击finish,就会自动生成activity和对应的布局文件。android应用要求四大组件都必须在配置文件AndroidManifest.xml中显示进行配置,在这里插入图片描述
我们以鼠标右键这种方式用AS自动生成的组件,AS就已经自动为我们默认配置了,我们只需按照需求修改组件的属性即可。
在activity节点里输入android,AS会显示activity属性如下:在这里插入图片描述
activity常用属性:
name:指定该activity的类名。
icon:指定该activity的图标(位于页面左上角)。
label:指定该activity的标签(位于页面左上角 )。
exported:指定该activity是否允许被其他应用调用。
launchMode:指定该activity的加载模式,该属性可设置为standard,singleInstance,singleTask,singleTop四种模式。

2.Activity的4种加载模式

Android采用Task来管理多个activity,当我们启动一个应用时,就会为之创建一个Task,可以把Task理解成activity栈,以这样的形式来管理:先启动activity的被放在栈底,后启动的activity被放在栈顶。
①standard:
标准模式,这是默认的加载模式。每次通过standard模式启动目标activity时,总会为目标activity创建一个新的实例(即使在栈中已经存在),并将该activity添加到当前Task栈顶。这种模式不会启动新的activity。
②singleTop:
Task栈顶单例模式,与standard模式基本相似。但,当目标activity已经位于Task栈顶时,将不会重复创建目标activity的实例,而是直接复用Task栈顶的目标activity,所以看不到activity之间的跳转。当目标activity没有位于Task栈顶时,此时与standard模式相同(创建新的activity实例)。
③singleTask:
Task内单例模式,在同一个Task栈里只有一个目标activity的实例。当目标activity在栈里不存在实例,系统将会创建目标activity的实例,并将它加入Task栈顶。当目标activity已经位于Task栈顶时,此时与singleTop模式相同。当目标activity在栈里已经存在且没有位于栈顶,此时,系统将会把目标activity上面的所有activity从Task移除,从而使目标activity位于栈顶。
④singleInstance:
全局单例模式,在这种加载模式下,系统保证无论从哪个Task中启动目标activity,只会创建一个目标activity实例,并会使用一个全新的Task栈来加载该activity。当将要启动的目标activity不存在,系统会先创建一个全新的Task,再创建目标activity并加入新的Task栈顶。当要启动的目标activity已经存在,无论它位于哪个应用程序中,位于哪个Task栈中,系统都会把该目标activity所在的Task转到前台,从而使该activity显示出来。注意!采用这种模式加载的Task栈将只包含该activity。

三、Activity的几个重要方法

启动

一个android应用通常有多个activity,但只有一个MainActivity作为程序的入口,而其余的activity则是通过此入口activity启动,有两个方法:

void startActivity(Intent intent):启动一个新activity。
void startActivityForResult(Intent intent, int requestCode):额外需要一个int类型的请求码requestCode来标识新启动的activity,而且会在新启动的activity结束时取回结果。

退出
activity的退出显然也有两种方式:在activity类里面调用

void finish():当你的活动完成并且应该关闭时调用它。
void finishActivity(int requestCode):关闭以 startActivityForResult(Intent, int)开始的activity。

获取结果

当activity退出时,它可以调用setResult(int resultCode, Intent data)调用此方法设置activity将返回给调用者的结果。resultCode可以是标准结果RESULT_CANCELED,RESULT_OK或RESULT_FIRST_USER开始的任何自定义值。
当回到调用者activity时,可以通过重写onActivityResult(int requestCode, int resultCode, Intent data)接收并处理返回结果。请求码requestCode用于区分是哪个activity返回的结果。

以上便是本文的一半内容了,接下来必须了解intent,不然寸步难行。。。
在这里插入图片描述

四、Intent作用

意图intent是要执行的操作的抽象描述。作为“通信的使者”,封装组件之间的“启动意图”,却不与任何组件耦合,通过这种方式可以很好的提高系统的可扩展性和可维护性。它可以被用来startActivity启动Activity,sendBroadcast发送给指定的BroadcastReceiver,startService或者bindService创建Service并与之通信。
综上,intent封装应用程序需要启动某个组件的意图。不仅如此,intent还是应用程序组件之间通信的重要媒介。为此,intent需要完成的工作有三种:第一,需要标明本次通信请求从哪里来,到哪里去,要怎么传送。第二,发送方携带本次通信内容,接收方要对收到的intent进行解包。第三,如果发送方要求判断接收方的处理结果就要负责让接收方传回应答的数据内容。设置好intent的各项属性后,intent又大致分为两种:显式intent和隐式intent。

五、Intent各个属性及其设置方法

打开intent的在线API文档,可以看到:
public class Intent
extends Object implements Parcelable, Cloneable

在Intent Structure栏目下,可以看到intent的7个主要属性:action,component,category,data,type,extra,flag。

1.component
component属性需要一个ComponentName 对象,用于指定此intent的来源类和目标类。由intent此属性的设置与否可分为 显式intent和隐式intent。

public final class ComponentName
extends Object implements Parcelable, Cloneable, Comparable

Public constructors
ComponentName(String pkg, String cls)
创建一个新的组件标识符。
ComponentName(Context pkg, String cls)
从上下文和类名创建新的组件标识符。
ComponentName(Context pkg, Class<?> cls)
从Context和Class对象创建一个新的组件标识符。
ComponentName(Parcel in)
从之前用 writeToParcel(Parcel, int)写入的Parcel中的数据实例化新的ComponentName。
设置方法
指定component属性,可以调用intent对象的:
Intent setComponent (ComponentName component)用ComponentName对象来设置,
也可直接调用setClass(Context, Class );setClassName(Context, String);setClassName(String, String)直接指定来源和目标类名字,自动创建ComponentName对象并设置属性。
还可以在intent的构造函数里指定属性
Intent(Context packageContext, Class<?> cls)为特定组件创建一个意图。
Intent(String action, Uri uri, Context packageContext, Class<?> cls)使用指定的操作和数据为特定组件创建一个意图。

显式intent和隐式intent
显式intent:设置了component属性,直接指定来源类和目标类名,属于精确匹配。因此,配置文件中的目标activity几乎不需要使用 intent-filter子节点。
隐式intent:没有精确指定要跳转的类名,保留缺省值为null,只给出一个动作,定义的目标属于模糊匹配。因此,配置文件中的目标activity需要使用 intent-filter子节点来筛选符合条件的请求,这些请求可以由来源activity设置包含接下来的6个属性的intent。

2.action
此属性定义一个抽象的操作,这个操作具体由哪个组件来完成,这个字符串本身并不管。就好比你游览一个网址,系统会提示选择哪个游览器。需要指出的是,一个intent对象最多只能指定一个action,但目标activity在配置文件中可以指定多个action子节点,就表明该activity能响应多个action属性中的任意一个action,除了内置的标准动作,还可以自定义字符串代表动作,相应的只需在目标activity的配置节点里声明指定的字符串
设置方法
intent对象可以调用
Intent setAction(String action)来设置action属性,还可以在intent的构造函数里指定action
Intent(String action)
用给定的动作创建一个意图。
Intent(String action, Uri uri)
用给定的动作和给定的数据url创建一个intent。
设置要执行的一般操作。

参照文档可以看到此属性为String字符串,而且看到内置了许多标准action,涵盖了几乎所有的动作:
标准activity动作:

ACTION_MAIN:作为主入口点开始,不期望接收数据,应用程序入口。。
常量值:“ android.intent.action.MAIN”

ACTION_VIEW:
将数据显示给用户。 这是对数据执行的最常见操作。
常量值:“ android.intent.action.VIEW”

ACTION_ATTACH_DATA:
用于指示某些数据应附加到某个其他位置。 例如,图像数据可以附加到联系人。 由接收方决定数据的附加位置;而没有指定最终目的地。
常量值:“ android.intent.action.ATTACH_DATA”

ACTION_EDIT:
提供对给定数据的显式可编辑访问。
常量值:“ android.intent.action.EDIT”

ACTION_PICK:
从数据中选择一个项目,返回选定内容。
常量值:“ android.intent.action.PICK”

ACTION_CHOOSER:
显示活动选择器,允许用户在继续之前选择他们想要的内容。 当您尝试使用多个可能的匹配启动一个活动时,可以将其用作系统显示的标准活动选择器的替代方法。
常量值:“android.intent.action.CHOOSER”

ACTION_GET_CONTENT:
允许用户选择特定类型的数据返回。 这与ACTION_PICK不同,因为这里我们只是说需要什么类型的数据,而不是用户可以从中选择的现有数据的 URI。ACTION_GET_CONTENT可以允许用户在运行时创建数据(例如拍摄照片或录制声音),让他们浏览网页并下载所需的数据等。如果调用者可以处理多个返回的项目(用户执行多个选择),那么它可以指定EXTRA_ALLOW_MULTIPLE来指示这一点。
常量值:“ android.intent.action.GET_CONTENT”

ACTION_DIAL:
发送数据中指定的号码。 在拨号页面显示用户正在拨打的号码,允许用户明确发起呼叫。
常量值:“ android.intent.action.DIAL”

ACTION_CALL:
对由数据指定的某人进行呼叫。
常量值:“ android.intent.action.CALL”

ACTION_SEND:
将一些数据提供给给其他人。 没有指定数据传送给谁; 这个动作的接收者要求用户在哪里发送数据。
当启动SEND通常时,通常应该将其包装在选择器中(通过createChooser(Intent,CharSequence)),这将为用户提供适当的界面以选择如何发送数据,并允许您指定提示,指示他们正在做什么。
常量值:“ android.intent.action.SEND”

ACTION_SENDTO:
将消息发送给由数据指定的人员。
常量值:“ android.intent.action.SENDTO”

ACTION_ANSWER:
处理来电。
常量值:“ android.intent.action.ANSWER”

ACTION_INSERT:
将空项目插入给定的容器中。
常量值:“ android.intent.action.INSERT”

ACTION_DELETE:
从其容器中删除给定的数据。也可用于卸载程序。
常量值:“ android.intent.action.DELETE”

ACTION_RUN:
无论如何运行数据。
常量值:“ android.intent.action.RUN”

ACTION_SYNC:
执行数据同步。
常量值:“ android.intent.action.SYNC”

ACTION_PICK_ACTIVITY:
选择一个有意向的活动,返回初始的类。
常量值:“ android.intent.action.PICK_ACTIVITY”

ACTION_SEARCH:
执行搜索。
常量值:“ android.intent.action.SEARCH”

ACTION_WEB_SEARCH:
执行网页搜索。
常量值:“android.intent.action.WEB_SEARCH”

ACTION_FACTORY_TEST:
工厂测试的主要入口点。仅在设备在工厂测试计数器中引导时使用。
常量值:“ android.intent.action.FACTORY_TEST”

标准广播动作:
这些是预期接收广播定义的现行标准操作(通常通过registerReceiver(BroadcastReceiver, IntentFilter)或清单中的receiver标记)。
在这里插入图片描述
见名知意,这就不过多复制粘贴了,太无聊了!
ACTION_TIME_TICK
ACTION_TIME_CHANGED
ACTION_TIMEZONE_CHANGED
ACTION_BOOT_COMPLETED
ACTION_PACKAGE_ADDED
ACTION_PACKAGE_CHANGED
ACTION_PACKAGE_REMOVED
ACTION_PACKAGE_RESTARTED
ACTION_PACKAGE_DATA_CLEARED
ACTION_PACKAGES_SUSPENDED
ACTION_PACKAGES_UNSUSPENDED
ACTION_UID_REMOVED
ACTION_BATTERY_CHANGED
ACTION_POWER_CONNECTED
ACTION_POWER_DISCONNECTED
ACTION_SHUTDOWN

3.category
类别也是一个普通的字符串。这个属性用于为action动作增加额外的附加数据信息,通常与action结合使用,一个intent对象可以包含多个category属性
设置方法
通过调用intent对象的
Intent addCategory (String category)
来为其添加这个属性,可以多次调用来添加不同的类别。

intent内置了大量的category常量,参见官方文档:

CATEGORY_DEFAULT:
在启动操作时,通常不会在Intent中显式设置此值 ,因为这是默认的值
常量值:“android.intent.category.DEFAULT”

CATEGORY_BROWSABLE:
浏览器安全地调用的活动必须支持这个类别。
常量值:“android.intent.category.BROWSABLE”

CATEGORY_TAB:
指定目标activity作为TabActivity的选项卡。
常量值:“android.intent.category.TAB”

CATEGORY_ALTERNATIVE:
设置是否应将活动视为用户当前正在查看的数据的替代操作。
常量值:“android.intent.category.AlTERNATIVE”

CATEGORY_LAUNCHER:
目标activity显示在Task栈顶中。
常量值:“android.intent.category.LAUNCHER”

CATEGORY_INFO:
提供关于它所在的包的信息。
常量值:“android.intent.category.INFO”

CATEGORY_HOME:
是app启动时显示的第一个activity。
常量值:“android.intent.category.HOME”

CATEGORY_PREFERENCE:
此activity是一个设置面板。
常量值:“android.intent.category.PREFERENCE”

CATEGORY_TEST:
用作测试(不是普通用户体验的一部分)。
常量值:“android.intent.category.TEST”

CATEGORY_CAR_DOCK:
手机插入汽车插座时运行的activity。
常量值:“android.intent.category.CAR_DOCK”

4.extra
当一个activity启动另一个activity时,常常会有一些数据需要传过去,这时我们就要用到这个extra属性。这个属性需要设置一个Bundle (包裹)对象:
public final class Bundle
extends BaseBundle implements Cloneable, Parcelable
包裹Bundle 操作起来就像map一样,采用get/put操作键值对。
但是,通常不需要在代码中显式声明Bundle 对象来携带数据,intent提供了多个简易重载的方法来携带额外的数据。当调用了简便的方法后,如果有Bundle 对象,则直接往里塞数据,如果这个extra属性没有创建Bundle 对象,则这些简易方法直接创建一个新的Bundle 对象,然后把这些数据放在Bundle 对象里面。
设置方法
分三种:
①基本数据类型的存取:
Intent putExtra(String name, 基本类型value)
基本类型 get基本类型Extra(String name)
从intent中存取基本类型数据。

②实现了Serializable接口的自定义数据类型:
Serializable getSerializableExtra(String name)
Intent putExtra(String name, Serializable value)
向intent中存取实现了Serializable接口的数据。

③使用Bundle对象存取数据:
Bundle getExtras()
Intent putExtras(Bundle extras)
向intent中存取Bundle 数据。

5.data
data属性用于指定向action提供操作的数据,例如联系人数据库中的人员记录,例如action/data对:
ACTION_DIAL content:// contacts / people / 1-显示电话拨号界面并填入电话信息。
ACTION_VIEW tel:123-显示带有给定号码的电话拨号界面。

设置这个属性需要一个 Uri对象 。Uri全称为universal resource identifier通用资源识别号,一个URI引用包括一个URI和一个数据片段:
public abstract class Uri
extends Object implements Parcelable, Comparable
常用其几个静态方法来构造Uri对象:
static Uri fromFile(File file)
static Uri parse(String uriString)
其中uriString通常有这种格式:
schema://host:port/path
这4个域都可以单独设置,而且还可以进行模糊匹配。比如,
当目标activity的intent-filter的data节点里只指定了schema,那么,intent对象的data属性中只要schema域相同,即使其他域随便设置,也能启动目标activity。
当目标activity的intent-filter的data节点里只指定了schema和host,那么,intent对象的data属性中只要schema域和host相同,即使其他域随便设置,也能启动目标activity。
同理,剩下两种情况也是如此。注意,要让data节点起作用,必须设置一个action节点
设置方法
Intent setData(Uri data)
设置这个intent的data属性。

6.type
指定特定数据的显式类型(MIME类型)。这种MIME类型可以是任何自定义的MIME类型类型,只要符合abc/xyz格式的字符串即可。
data和type两个属性会相互覆盖。如果先设置type属性后设置data属性,那么data属性会覆盖type属性。如果希望intent既有data属性又有type属性,那么应该调用intent的setDataAndType方法设置intent的data以及显式的MIME数据类型。在配置文件中,type属性并不是一个单独的子节点,而是通过date节点中设置。只有当这个data节点的type和intent的type相对应的时候才能够启动该组件。
设置方法
Intent setDataAndType(Uri data, String type)
设置intent的data以及显式的MIME数据类型。
setType(String type)
设置一个显式的MIME数据类型。

7.flag
这个属性可以为该intent添加一些额外的控制,可以用来设置activity栈的操作方式。
查看文档,看到一些常见flag,FLAG_ACTIVITY_ 标志全部用于Context.startActivity(),FLAG_RECEIVER_ *标志全部用于Context.sendBroadcast():

FLAG_ACTIVITY_CLEAR_TOP
如果已设置,并且正在启动的活动已在当前任务中运行,则不会启动该活动的新实例,而是关闭其上的所有其他活动,并将此Intent交付给(现在开启顶部)旧活动作为一个新的意图。相当于activity四种加载模式里的singleTask。

FLAG_ACTIVITY_NEW_TASK
默认的flag,用于创建一个新的activity。

FLAG_ACTIVITY_SINGLE_TOP
如果已设置,则如果活动已在历史堆栈的顶部运行,则不会启动该活动。相当于activity四种加载模式里的singleTop。
设置方法
Intent setFlags (int flags)为intent设置额外的标志。
Intent addFlags (int flags)为intent添加额外的标志(或与现有的标志值)。


总结

本文讲了Android第一大组件activity以及组件之间的“通信员”intent,这些知识基础且简单,就没有给出具体的测试代码,若想测试的话,有如下思路:创建几个activity,配置其不同的属性,然后使用不同的intent来启动目标activity,最后在目标activity结束返回来源activity时可以获取其处理结果。接下来的一篇文章总结Android的5大存储方式,涉及到第二大组件ContentProvider内容提供器,这是个人觉得最难学的一个组件。。。

在这里插入图片描述
最后问大家一个问题:有啥办法来保持专注认真的做事情?

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

搬砖工人_0803号

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值