我是靠谱客的博主 深情项链,最近开发中收集的这篇文章主要介绍Android四大组件之ActivityAndroid四大组件之Activity,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

Android四大组件之Activity

作者:白璐
日期:2020/2/22

文章目录

  • Android四大组件之Activity
    • 概述
    • 活动程序(Activity)
      • Activity简介
      • Activity生命周期
      • Intent(意图)
      • 创建一个Activity
      • Activity的启动模式
      • Activity的其他属性
      • 拓展学习
        • Activity任务与任务管理栈
        • ActivityManager
        • am start的使用方法

概述

Android应用程序是由下列4个组件构成,分别是:

  • 活动程序(Activity)
  • 服务程序(Service)
  • 广播接收器(Broadcast Receiver)
  • 内容提供器(Content Provider)

活动程序(Activity)

Activity简介

Activity是一个Android的应用组件,它提供屏幕进行交互。每个Activity都会获得一个用于绘制其用户界面的窗口,窗口可以充满哦屏幕也可以小于屏幕并浮动在其他窗口之上。
  一个应用通常是由多个彼此松散联系的Activity组成,一般会指定应用中的某个Activity为主活动,也就是说首次启动应用时给用户呈现的Activity。将Activity设为主活动的方法,如下面代码所示需要在AndroidManifest.xml文件中添加以下内容:

<application>
     ....
    <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
     </activity>
     ....
</application>     

当然Activity之间可以进行互相跳转,以便执行不同的操作。每当新Activity启动时,旧的Activity便会停止,但是系统会在堆栈也就是返回栈中保留该Activity。当新Activity启动时,系统也会将其推送到返回栈上,并取得用户的操作焦点。当用户完成当前Activity并按返回按钮是,系统就会从堆栈将其弹出销毁,然后回复前一Activity。
  当一个Activity因某个新Activity启动而停止时,系统会通过该Activity的生命周期回调方法通知其这一状态的变化。Activity因状态变化每个变化可能有若干种,每一种回调都会提供执行与该状态相应的特定操作的机会。

Activity生命周期

下图中展示了activity的重要的状态改变路径。矩形中的代表你可以在活动在两种状态间改变时你可以实现的回调方法去执行想要的操作。而带有颜色的椭圆形代表着activity的主要状态。
activity生命周期

各生命周期状态说明

方法描述
onCreate()当Activity第一次创建时调用。该方法(如果有)会提供给你一个包含之前活动的冻结状态信息bundle包。
onStart()当Activity被展示在用户眼前时调用。如果活动出现在前台紧接着是onResume(),如果活动直接隐藏则紧接着是onStop()。
onRestart()当Activity被停止后调用,在重新开始之前
onResume()当Activity将开始与用户进行交互时调用。在这个时间点你的活动将会在活动堆栈的顶端,用户输入将会访问它。
onPause()当系统将要恢复一个之前的活动。这是一个有代表性的常常用于提交未被存储的改动信息为持久数据,停止动画和消耗CPU的东西等。实现该方法必须要特别的迅速,因为在此方法返回之前,下一个活动将不会恢复。如果活动将返回到前台则接下来调用onResume(),如果要隐藏到用户看不见的地方时,则调用onStop();
onStop()当另一个活动被恢复且完全覆盖该活动,而该Activity将不在展示给用户时调用。这种情况将发生在一个新的活动将被开始,一个退出的活动将被恢复,又或者该活动将要被销毁。如果该活动将恢复与用户交互则调用onRestart(),如果该活动将被销毁则调用onDestory()。
onDestory()Activity被销毁钱最后一个被调用的方法。这个方法将会发生因为活动将会结束(在活动中调用finish()方法,或者系统临时销毁该实例节约空间。你可以使用isFinishing()方法区别这两种场景)。

阶段状态
一个Activity从本质上讲拥有4种状态:
Activity4种主要状态.png

  • 运行 :如果当前的activity在前台界面上时(堆栈顶端)。
  • 暂停:如果activity被另一个非全屏活动强占焦点并覆盖时(如弹窗dialog),它将会暂停。一个暂停的活动也是完全活跃的(它的所有的状态和成员信息将会保留,但activity本身将不会再依附于WindowsManager了),在内存极度缺乏的状态会被系统杀死。
  • 停止:如果activity完全被另一个全屏活动遮挡住时,它将会停止。该活动也仍保留全部的状态和成员信息,但将会被隐藏起来不再展示给用户,并且当内存在其他地方被需要时该活动就将会被系统杀死。
  • 重启:如果activity处于暂停或者停止状态,系统将会在内存中终止该活动无论是结束活动或者杀死进程。当它再一次展示给用户时,它必须是完全重启并且恢复到之前的状态。

状态转换
Activity状态转换
  上图中我们可以看到Activity在生命周期状态进行转换的过程中,activity本身是在什么时候调用的onSaveInstanceState()方法与onRestoreInstanceState()方法来进行重要信息的存储与恢复的。因为在蜂巢版本之前onSaveInstanceState()方法只有在activity异常退出时才会调用,所以我们应该在onPause()方法中进行信息持久化存储的操作,生命周期可以调用onSaveInstanceState()方法来进行信息持久化存储的操作。

常见情况下生命周期的回调
(A与B表示不同的Activity)

情况描述
第一次启动AonCreate() -> onStart() -> onResume()
从 A 跳转到 BA_onPause() -> B_onCreate() -> B_onStart() -> B_onResume() -> A_onStop()
从 B 再次回到 AB_onPause() -> A_onRestart() -> A_onStart() -> A_onResume() -> B_onStop()
用户按 home 键onPause() -> onStop()
按 home 键后回到应用onRestart() -> onStart() -> onResume()
用户按电源键屏保onPause() -> onStop()
用户按电源键亮屏onRestart() -> onStart() -> onResume()
用户按 back 键回退onPause() -> onStop() -> onDestroy()

异常情况下生命周期详解
  当 Activity 在运行过程中发生一些情况时,生命周期流程也会发生变化。常见的异常情况有两种,一种是资源配置改变;另一是内存不足导致生命周期流程发生变化。

  1. 资源配置改变导致 Activity 重建
       资源配置最常见的情况就是横竖屏切换导致资源的变化,当程序启动时,会根据不同的配置加载不同的资源,例如横竖屏两个状态对应着两张不同的资源图片。如果在使用过程中屏幕突然旋转,那么 Activity 就会因为系统配置发生改变而销毁重建,加载合适的资源。
  2. 低优先级 Activity 由于内存不足被杀死
      后台可以同时运行多个任务,当设备的内存空间不足时,系统为了保证用户的体验,会按照进程优先级将一些低优先级的进程杀死以会回收内存资源,后台 Activity 就有可能会被销毁。
    系统回收进程的优先级:
    (1) 前台进程
      持有用户正在交互的 Activty,即生命周期处于 onResume 状态的活动。该进程有绑定到正在交互的 Activity 的 service 或前台 service。
    (2) 可见进程
      这种进程虽然不在前台,但是仍然可见。该进程持有的 Activity 执行了 onPause 但未执行 onStop 。例如原活动启动了一个 dialog 主题的 Activity,但此时原活动并非完全不可见。该进程有 service 绑定到可见的或前台 Activity。
    (3)服务进程
      进程中持有一个 service,同时不属于上面两种情况。
    (4)后台进程
      不属于上面三种情况,但进程持有一个不可见的 Activity,即执行了 onStop 但未执行 onDestory 的状态。
    (5)空进程
      不包含任何活跃的应用组件,作用是加快下次启动这个进程中组件所需要的时间,优先级低。

异常情况下的处理
  在发生异常情况后,用户再次回到 Activity,原 Activity 会重新建立,原已有的数据就会丢失,比如用户操作改变了一些属性值,重建之后用户就看不到之前操作的结果,在异常的情况下如何给用户带来好的体验,有两种办法。

  1. 数据保存
      第一种就是系统提供的 onSaveInstanceStateonRestoreInstanceState 方法,onSaveInstanceState 方法会在 Activity 异常销毁之前调用,用来保存需要保存的数据,onRestoreInstanceState 方法在 Activity 重建之后获取保存的数据。
      在活动异常销毁之前,系统会调用 onSaveInstanceState,可以在 Bundle 类型的参数中保存想要的信息,之后这个 Bundle 对象会作为参数传递给 onRestoreInstanceStateonCreate 方法,这样在重新创建时就可以获取数据了。
      关于 onSaveInstanceState 与 onRestoreInstanceState 方法需要注意的一些问题:
      1. onSaveInstanceState 方法的调用时机是在 onStop 之前,与 onPause 没有固定的时序关系。而 onRestoreInstanceState 方法则是在onStart 之后调用。
      2. 正常情况下的活动销毁并不会调用这两个方法,只有当活动异常销毁并且有机会重现展示的时候才会进行调用,除了资源配置的改变外,activity 因内存不足被销毁也是通过这两个方法保存数据。
      3. 在 onRestoreInstanceStateonCreate 都可以进行数据恢复工作,但是根据官方文档建议采用在 onRestoreInstanceState 中去恢复。
      4. 在 onSaveInstanceStateonRestoreInstanceState 这两个方法中,系统会默认为我们进行一定的恢复工作,具体地讲,默认实现会为布局中的每个 View 调用相应的 onSaveInstanceState() 方法,让每个视图都能提供有关自身的应保存信息。Android 框架中几乎每个小部件都会根据需要实现此方法,以便在重建 Activity 时自动保存和恢复付 UI 所做的任何可见更改。例如 EditText 中的文本信息、ListView 中的滚动位置等。也可以通过 android:saveEnabled属性设置为 “false”或通过调用 setSaveEnabled() 方法显式阻止布局内的视图保存其状态,通常不会将该属性停用,除非想要以不同方式恢复 Activity IU 的状态。
      5. onSaveInstanceState() 常见的触发场景有:横竖屏切换、按下电源键、按下菜单键、切换到别的 Activity 等;onRestoreInstanceState() 常见的触发场景有:横竖屏切换、切换语言等等。
  2. 防止重建
      在默认情况下,资源配置改变会导致活动的重新创建,但是可以通过对活动的 android:configChanges 属性的设置使活动防止重新被创建。
    android:configChanges 属性值
属性值含义
mccSIM 卡唯一标识IMSI(国际移动用户标识码)中的国家代码,由三位数字组成,中国为:460,这里标识 mcc 代码发生了变化
mncSIM 卡唯一标识 IMSI(国际移动用户标识码)中的运营商代码,有两位数字组成,中国移动 TD 系统为 00 ,中国联通为 01,电信为 03,此项标识 mnc 发生了改变
locale设备的本地位置发生了改变,一般指的是切换了系统语言
touchscreen触摸屏发生了改变
keyboard键盘类型发生了改变,比如用户使用了外接键盘
keyboardHidden键盘的可访问性发生了改变,比如用户调出了键盘
navigation系统导航方式发生了改变
screenLayout屏幕布局发生了改变,很可能是用户激活了另外一个显示设备
fontScale系统字体缩放比例发生了改变,比如用户选择了个新的字号
uiMode用户界面模式发生了改变,比如开启夜间模式 -API8 新添加
orientation屏幕方向发生改变,比如旋转了手机屏幕
screenSize当屏幕尺寸信息发生改变(当编译选项中的 minSdkVersion 和 targeSdkVersion 均低于 13 时不会导致 Activity 重启 ) API 13 新添加
smallestScreenSize设备的物理尺寸发生改变,这个和屏幕方向没关系,比如切换到外部显示设备 -API13 新添加
layoutDirection当布局方向发生改变的时候,正常情况下无法修改布局的 layoutDirection 的属性 -API17 新添加

可以在属性中声明多个配置值,方法使用 “|” 字符分割这些配置值。

API 级别 13 或更高版本的应用时,若要避免由于设备方向改变(横竖屏切换)而导致运行时重启,则除了 “orientation” 值之外,还必须添加“screenSize”值。
  当其中一个配置发生变化时,Activity 不会重启。相反,Activity 会收到对 onConfigurationChanged() 的调用。向此方法传递 Configuration 对象指定新设备配置。可以通过读取 Configuration 中的字段,确定新配置,然后通过更新界面中使用的资源进行适当的更改。

关于 Activity 的不常用的回调方法

  1. onPostCreate()
      onPostCreate() 方法是指 onCreate() 方法彻底执行完毕的回调。一般我们都没有实现这个方法,它的作用是在代码开始运行之前,调用系统做最后的初始化工作。现在知道的做法是使用 ActionBarDrawerToggle 时在屏幕旋转的时候在 onPostCreate() 中同步下状态。
  2. onPostResume()
      onPostResume()onPostCreate() 方法类似,onPostResume() 方法在 onResume()方法彻底执行完毕的回调。 onCreate()方法中获取某个 View 的高度和宽度时,返回的值是 0 ,因为这个时候 View 可能还没初始化好,但是在 onPostResume()中获取就不会有问题,因为 onPostResume() 是在 onResume()彻底执行完毕的回调。
  3. onContentChanged()
      当 Activity 的布局改动时,即 setContentView() 或者 addContentView()方法执行完毕时就会调用该方法。所以,Activity 中 View 的 findViewById() 方法都可以放到该方法中。
  4. onUserInteraction()
      Activity 无论分发按键事件、触摸事件或者轨迹球事件都会调用 Activity#onUserInteraction()。如果想知道用户用某种方式和你正在运行的 activity 交互,可以重写 Activity#onUserInteraction()。所有调用 Activity#onUserLeaveHint() 的回调都会首先回调 Activity#onUserInteraction()
      Activity 在分发各种事件的时候会调用该方法,注意:启动另一个 activity ,Activity#onUserInteraction()会被调用两次,一次是 activity 捕获到事件,另一次是调用Activity#onUserLeaveHint() 之前会调用 Activity#onUserInteraction()
      可以用这个方法来监控用户有没有与当前的 Activity 进行交互。
  5. onUserLeaveHint()
      当用户的操作使一个 activity 准备进入后台时,此方法会像 activity 的生命周期的一部分被调用。例如,当用户按下 Home 键,Activity#onUserLeaveHint()将会被调用。但是当来电导致 activity 自动占据前台(系统自动切换),Activity#onUserLeaveHint() 将不会被回调。
      一般监听返回键,是重写 onKeyDown()方法,但是 Home 键和 Menu 键就不好监听,但是可以在 onUserLeaveHint()方法中监听。

Intent(意图)

Android中提供了Intent机制来协助应用间的交互与通讯,Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。Intent不仅可用于应用程序之间,也可用于应用程序内部的 Activity / Service之间的交互。因此,Intent在这里起着一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦。
intent
1. Intent作用

Intent是一个将要执行的动作的抽象的描述,一般来说是作为参数来使用,由 Intent来协助完成 Android各个组件之间的通讯。比如说调用startActivity()来启动一个Activity,或者由broadcaseIntent()来传递给所有感兴趣的BroadcaseReceiver,再或者由startService() / bindservice()来启动一个后台的 service。所以可以看出来,Intent 主要是用来启动其他的 activity 或者 service,所以可以将 intent 理解成 activity 之间的粘合剂。

Intent作用的表现形式为:

  • 启动Activity
    通过Context.startActvity() / Activity.startActivityForResult()启动一个Activity;
  • 启动Service
    通过Context.startService()启动一个服务,或者通过Context.bindService()和后台服务交互;
  • 发送Broadcast
    通过广播方法Context.sendBroadcasts() / Context.sendOrderedBroadcast() / Context.sendStickyBroadcast()发给Broadcast Receivers

2. Intent种类

  • 显式Intent
    显式,即直接指定需要打开的activity对应的类。

1)构造方法传入Component,最常用的方式:

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

2)setComponent方法

Intent intent = new Intent();    
intent.setClass(this, SecondActivity.class);  
//或者intent.setClassName(this, "com.example.app.SecondActivity");  
//或者intent.setClassName(this.getPackageName(),"com.example.app.SecondActivity");            
startActivity(intent);  

3)setClass / setClassName方法

Intent intent = new Intent();    
intent.setClass(this, SecondActivity.class);  
//或者intent.setClassName(this, "com.example.app.SecondActivity");  
//或者intent.setClassName(this.getPackageName(),"com.example.app.SecondActivity");            
startActivity(intent);  

显式Intent通过Component可以直接设置需要调用的Activity类,可以唯一确定一个Activity,意图特别明确,所以是显式的。设置这个类的方式可以是Class对象(如SecondActivity.class),也可以是包名加类名的字符串(如"com.example.app.SecondActivity")。

  • 隐式Intent
    隐式,不明确指定启动哪个Activity,而是设置Action、Data、Category,让系统来筛选出合适的Activity。筛选是根据所有的<intent-filter>来筛选。

下面以Action为例:
  AndroidManifest.xml文件中,首先被调用的Activity要有一个带有<intent-filter>并且包含<action>的Activity,设定它能处理的Intent,并且category设为"android.intent.category.DEFAULT"。action的name是一个字符串,可以自定义,为了防止应用程序之间互相影响,一般命名方式是包名+Action名,例如这里设成为"com.example.app.Test"

<activity  
    android:name="com.example.app.SecondActivity">  
    <intent-filter>  
        <action android:name="com.example.app.Test"/>  
        <category android:name="android.intent.category.DEFAULT"/>  
    </intent-filter>  
</activity>  

然后,在MainActivity,才可以通过这个action name找到上面的Activity。下面两种方式分别通过setAction和构造方法方法设置Action,两种方式效果相同。
1)setAction方法

Intent intent = new Intent();  
intent.setAction("com.example.app.Test");  
startActivity(intent);  

2)构造方法直接设置Action

Intent intent = new Intent("com.example.app.Test");  
startActivity(intent);  

3. Intent属性

Intent对象大致包括7大属性:Action(动作)、Data(数据)、Category(类别)、Type(数据类型)、Component(组件)、Extra(扩展信息)、Flag(标志位)。其中最常用的是Action属性和Data属性。

  • Action:用来表现意图的行动
    一个字符串变量,可以用来指定Intent要执行的动作类别。常见的action有:

Activity Actions:

类型作用
ACTION_MAIN表示程序入口
ACTION_VIEW自动以最合适的方式显示Data
ACTION_EDIT提供可以编辑的
ACTION_PICK选择一个一条Data,并且返回它
ACTION_DAIL显示Data指向的号码在拨号界面Dailer上
ACTION_CALL拨打Data指向的号码
ACTION_SEND发送Data到指定的地方
ACTION_SENDTO发送多组Data到指定的地方
ACTION_RUN运行Data,不管Data是什么
ACTION_SEARCH执行搜索
ACTION_WEB_SEARCH执行网上搜索
ACRION_SYNC执同步一个Data
ACTION_INSERT添加一个空的项到容器中

Broadcast Actions:

类型作用
ACTION_TIME_TICK当前时间改变,并即时发送时间,只能通过系统发送。调用格式"android.intent.action.TIME_TICK"
ACTION_TIME_CHENGED设置时间。调用格式"android.intent.action.TIME_SET"
  • Data:表示与动作要操纵的数据
    一个URI对象是一个引用的data的表现形式,或是data的MIME类型;data的类型由Intent的action决定。

  • Category:用来表现动作的类别
    一个包含Intent额外信息的字符串,表示哪种类型的组件来处理这个Intent。任何数量的Category 描述都可以添加到Intent中,但是很多intent不需要category,下面列举一些常用的category:

类型作用
CATEGORY_DEFAULT把一个组件Component设为可被implicit启动的
CATEGORY_LAUNCHER把一个action设置为在顶级执行。并且包含这个属性的Activity所定义的icon将取代application中定义的icon
CATEGORY_BROWSABLE当Intent指向网络相关时,必须要添加这个类别
CATEGORY_HOME使Intent指向Home界面
CATEGORY_PREFERENCE定义的Activity是一个偏好面板Preference Panel
  • Type:指定数据类型
    一般Intent的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型而不再进行推导。

  • Component:目的组件
    指定Intent的目标组件名称,当指定了这个属性后,系统将跳过匹配其他属性,而直接匹配这个属性来启动对应的组件。

  • Extra:扩展信息
    Intent可以携带的额外 key-value 数据,你可以通过调用putExtra()方法设置数据,每一个 key对应一个 value数据。你也可以通过创建 Bundle对象来存储所有数据,然后通过调用putExtras()方法来设置数据。

类型作用
EXTRA_BCC存放邮件密送人地址的字符串数组
EXTRA_CC存放邮件抄送人地址的字符串数组
EXTRA_EMAIL存放邮件地址的字符串数组
EXTRA_SUBJECT存放邮件主题字符串
EXTRA_TEXT存放邮件内容
EXTRA_KEY_EVENT以KeyEvent对象方式存放触发Intent 的按键
EXTRA_PHONE_ NUMBER存放调用ACTION_CALL 时的电话号码
  • Flag:期望这个意图的运行模式
    用来指示系统如何启动一个Activity,可以通过setFlags()或者addFlags()可以把标签flag用在Intent中。
类型作用
FLAG_ACTIVITY_CLEAR_TOP相当于SingleTask
FLAGE_ACTIVITY_SINGLE_TOP相当于SingleTop
FLAG_ACTIVITY_NEW_TASK类似于SingleInstance
FLAG_ACTIVITY_NO_HISTORY当离开该Activity后,该Activity将被从任务栈中移除

4. Intent用法

  • 调用拨号程序
// 调用拨打电话,给10010拨打电话
Uri uri = Uri.parse("tel:10010");
Intent intent = new Intent(Intent.ACTION_DIAL, uri);
startActivity(intent);
// 直接拨打电话,需要加上权限 <uses-permission id="android.permission.CALL_PHONE" /> 
Uri callUri = Uri.parse("tel:10010"); 
Intent intent = new Intent(Intent.ACTION_CALL, callUri); 
  • 发送短信或彩信
 // 给10010发送内容为“Hello”的短信
Uri uri = Uri.parse("smsto:10010");
Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
intent.putExtra("sms_body", "Hello");
startActivity(intent);
 // 给10010发送内容为“Hello”的短信
// 发送彩信(相当于发送带附件的短信)
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra("sms_body", "Hello");
Uri uri = Uri.parse("content://media/external/images/media/23");
intent.putExtra(Intent.EXTRA_STREAM, uri);
intent.setType("image/png");
startActivity(intent);
  • 通过浏览器打开网页
// 打开百度主页
Uri uri = Uri.parse("https://www.baidu.com");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
  • 发送电子邮件
// 给someone@domain.com发邮件
Uri uri = Uri.parse("mailto:someone@domain.com");
Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
startActivity(intent);
// 给someone@domain.com发邮件发送内容为“Hello”的邮件
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, "someone@domain.com");
intent.putExtra(Intent.EXTRA_SUBJECT, "Subject");
intent.putExtra(Intent.EXTRA_TEXT, "Hello");
intent.setType("text/plain");
startActivity(intent);
// 给someone@domain.com发邮件发送内容为“Hello”的邮件
// 给多人发邮件
Intent intent=new Intent(Intent.ACTION_SEND);
String[] tos = {"1@abc.com", "2@abc.com"}; // 收件人
String[] ccs = {"3@abc.com", "4@abc.com"}; // 抄送
String[] bccs = {"5@abc.com", "6@abc.com"}; // 密送
intent.putExtra(Intent.EXTRA_EMAIL, tos);
intent.putExtra(Intent.EXTRA_CC, ccs);
intent.putExtra(Intent.EXTRA_BCC, bccs);
intent.putExtra(Intent.EXTRA_SUBJECT, "Subject");
intent.putExtra(Intent.EXTRA_TEXT, "Hello");
intent.setType("message/rfc822");
startActivity(intent);
  • 显示地图与路径规划
 // 打开Google地图中国北京位置(北纬39.9,东经116.3)
Uri uri = Uri.parse("geo:39.9,116.3");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
// 路径规划:从北京某地(北纬39.9,东经116.3)到上海某地(北纬31.2,东经121.4)
Uri uri = Uri.parse("http://maps.google.com/maps?f=d&saddr=39.9 116.3&daddr=31.2 121.4");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
  • 播放多媒体
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.parse("file:///sdcard/foo.mp3");
intent.setDataAndType(uri, "audio/mp3");
startActivity(intent);

Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, "1");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
  • 选择图片
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, 2);
  • 拍照
 // 打开拍照程序
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 1);
 // 取出照片数据
Bundle extras = intent.getExtras();
Bitmap bitmap = (Bitmap) extras.get("data");
  • 获取并剪切图片
// 获取并剪切图片
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
intent.putExtra("crop", "true"); // 开启剪切
intent.putExtra("aspectX", 1); // 剪切的宽高比为12
intent.putExtra("aspectY", 2);
intent.putExtra("outputX", 20); // 保存图片的宽和高
intent.putExtra("outputY", 40);
intent.putExtra("output", Uri.fromFile(new File("/mnt/sdcard/temp"))); // 保存路径
intent.putExtra("outputFormat", "JPEG");// 返回格式
startActivityForResult(intent, 0);
// 剪切特定图片
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setClassName("com.android.camera", "com.android.camera.CropImage");
intent.setData(Uri.fromFile(new File("/mnt/sdcard/temp")));
intent.putExtra("outputX", 1); // 剪切的宽高比为1:2
intent.putExtra("outputY", 2);
intent.putExtra("aspectX", 20); // 保存图片的宽和高
intent.putExtra("aspectY", 40);
intent.putExtra("scale", true);
intent.putExtra("noFaceDetection", true);
intent.putExtra("output", Uri.parse("file:///mnt/sdcard/temp"));
startActivityForResult(intent, 0);
  • 打开手机应用市场
// 打开手机应用市场,直接进入该程序的详细页面
Uri uri = Uri.parse("market://details?id=" + packageName);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
  • 安装程序
String fileName = Environment.getExternalStorageDirectory() + "/myApp.apk";   
Intent intent = new Intent(Intent.ACTION_VIEW);   
intent.setDataAndType(Uri.fromFile(new File(fileName)),
"application/vnd.android.package-archive");   
startActivity(intent);  
  • 卸载程序
Uri uri = Uri.parse("package:" + packageName);   
Intent intent = new Intent(Intent.ACTION_DELETE, uri);
startActivity(intent);
  • 进入设置界面
// 进入系统设置界面
Intent intent = new Intent(android.provider.Settings.ACTION_SETTINGS);
startActivity(intent);

创建一个Activity

1. 在清单文件中声明Activity
  每次新建的Activity都需要在AndroidManifest文件中添加如下内容,并将元素添加为元素的子项

<manifest ... >
  <application ... >
      <activity android:name=".MainActivity " />
      <activity android:name=".ExampleActivity" />
      ...
  </application ... >
  ...
</manifest >

2. 创建Activity的子类
  要创建Activity,必须创建Activity的子类。在子类中实现Activity在生命周期的各种状态之间转变时例如创建 Activity、停止 Activity、恢复 Activity 或销毁 Activity 时)系统调用的回调方法。Android Studio中新建项目默认创建的代码为

public class MainActivity extends AppCompatActivity {

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

onCreate()方法:必须实现的方法,系统在创建Activity时调用此方法。您应该在实现内初始化Activity的必要组件,必须在此方法调用setContentView(),用来定义Activity用户界面布局(XML文件)
3. 启动Activity
  该部分用于描述如何启动Activity。作为主活动,在应用开启的时候就会系统创建,而用户不仅仅只需要主活动界面,用户需要界面的跳转,而界面的跳转也是其他活动界面(Activity)启动。
  在该部分仅仅只提及利用显示Intent方式跳转活动,代码如下

Intent intent = new Intent(this, ExampleActivity.class);
startActivity(intent);
//this,为本Acitivity的上下文;第二个参数为你要跳转的目的Activity.class

4. 结束Activity
  通过调用Activity的finish()方法来结束Activity还可以通过调用finishActivity()结束之前启动的活动。
  你通过 MainActivity 来启动 ActivityA (使用 startActivityForResult方法),那么你在 MainActivity 这个类中需要重写 onActivityResult() 这个方法,
然后,你可以在 onActivityResult() 中通过 finishActivity() 方法去结束掉 ActivityA

Activity的启动模式

AndroidManifest.xml文件中为Activity配置相应的launchMod属性可以设置Activity的启动模式,共如下四种模式:

  • standard
  • singleTask
  • singleTop
  • singleInstance
android:launchMode=[“standard” | “singleTop” | “singleTask” | “singleInstance”]

默认值是“standard”。

接下来对四种启动模式进行详细分析。
1. standard模式(标准启动模式)
  该模式下每次启动Activity都会重新创建Activity实例,在这种模式下谁启动了这个Actvitiy,那么这个Activity与被启动的Activity位于启动它的Activity的栈中。
2. singleTop模式(栈顶复用模式)
  该模式下如果Activity已经位于栈顶,那么该Activity不会重新创建,同时它的OnNewIntent方法会被调用,通过方法的参数可以取出其中的信息,并且在这种模式如果这个Actvitiy不位于栈顶,那么这个Activity依然会被重新创建。
3. singleTask模式(栈内复用模式)
  只要Activity实例在一个栈中存在,那么再次启动该Activity时不会重新创建实例,并且系统也会回调其OnNewIntent方法,并且该模式下有清除栈顶实例的效果,即会将与singleTask模式下的该Activity同一个栈中的栈顶的所有Activity实例全部出栈。
4. singleInstance模式(单实例模式)
  单实例模式具备singleTask模式的所有的特性,此外具有此模式的Activity只能单独位于一个任务栈中。

Intent中activity相关的6个Flag比较重要:
1. FLAG_ACTIVITY_NEW_TASK
与启动模式中的“singleTask”行为相同。
2. FLAG_ACTIVITY_SINGLE_TOP
与启动模式中的“singleTop”行为相同。
3. FLAG_ACTIVITY_CLEAR_TASK
必须要与FLAG_ACTIVITY_NEW_TASK配合使用,这个activity新启动一个栈,原来栈被清空,栈中的activity也被销毁。
4. FLAG_ACTIVITY_CLEAR_TOP
A B C D四个activity在一个栈中,用此flag启动B,原来的B被唤出来,CD被clear。不能与FLAG_ACTIVITY_SINGLE_TOP同用。可以和FLAG_ACTIVITY_NEW_TASK同用。
5. FLAG_ACTIVITY_NO_HISTORY
当离开activity并不可见时,此activity会从栈中移除并不留下记录。
6. FLAG_ACTIVITY_REORDER_TO_FRONT
重新排列栈中activity的顺序。如:栈中有A B C D四个activity,用此flag启动B,原来的B被唤起到栈顶。重新排序后顺序:A C D B

Activity的其他属性

android:taskAffinity="string"

android:allowTaskReparenting=["true" | "false"]

android:alwaysRetainTaskState=["true" | "false"]

android:clearTaskOnLaunch=["true" | "false"]

android:finishOnTaskLaunch=["true" | "false"]

android:noHistory=["true" | "false"]

这些属性都是在Manifest中定义的,下面分别来介绍一下。

1、 先来说说taskAffinity属性:task的亲属关系,设置的字符串应该是另一个task名,通常情况下是一个application的名称。拥有相同taskAffinity的activity同属于一个task,从用户角度来看是属于同一个应用程序(application)。一个task的亲属关系取决于task的根activity。
  它是个很重要的属性,它会配合其他属性和flag共同影响activity的行为。首先它与“singleTask”模式或FLAG_ACTIVITY_NEW_TASK Flag配合,启动后此activity会属于另一个task,task名就是taskAffinity的设置值。其次,它会和allowTaskReparenting属性配合使用,详见allowTaskReparenting
  默认情况下,一个application中的所有activity同属于一个亲属关系。如果想让activity不属于任一个task,那么把taskAffinity的值设为空吧。如果你不设它,那么系统会为你默认为所属application的名称,也就是在manifest中的package名。

2、 allowTaskReparenting:与字面理解相同,本属性允许activity重新指定Task。默认值是false。通常情况下我们不设置此属性,activity在生命周期中只属于一个Task。而设置成true后,需要与taskAffinity属性配合使用,当原来的task转到后台,亲属task转到前台,那么此时activity就会属于当前的task。

3、 alwaysRetainTaskState:总是保留task的状态。默认值是false。此时会遵循系统的清理栈的行为。如果设置为true,系统会保留栈中所有activity及其状态,当用户再次回来的时候,发现一切如初。

4、 clearTaskOnLaunch:当再次启动task时,系统会清理掉除了根activity以外的所有activity。默认值是false。

5、 finishOnTaskLaunch:这个属性与上面的clearTaskOnLaunch很像,不过它是指单个activity的,而不是整个栈。当设置为true时,task重启后,这个activity就不显示了。默认值为false。优先级高于allowTaskReparenting

6、 noHistory:如果设置true,当离开activity并不可见时,此activity会从栈中移除并不留下记录。默认值为false。与上面FLAG_ACTIVITY_NO_HISTORY行为相同。

拓展学习

Activity任务与任务管理栈

ActivityManager

am start的使用方法

最后

以上就是深情项链为你收集整理的Android四大组件之ActivityAndroid四大组件之Activity的全部内容,希望文章能够帮你解决Android四大组件之ActivityAndroid四大组件之Activity所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(45)

评论列表共有 0 条评论

立即
投稿
返回
顶部