文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

【Android】Activity

2022-06-06 14:09

关注

Content1. 创建一个Activity的流程2. 启动另一个Activity3. Activity生命周期4. Activity的四种launchMode5. Intent 和 Intent 过滤器6. 与其他应用交互7. 允许其他应用启动您的 Activity附:task与back栈 总结自老师的文档 1. 创建一个Activity的流程

1.1. 设计并实现用户接口
衍生自 View 类的视图,控制 Activity 中特定的矩形空间,例如按钮
衍生自 ViewGroup 类的视图,是布局,例如线性布局
利用视图定义布局的最常见方法是借助保存在你的应用资源内的 XML 布局文件

1.2. 配置manifest
1.2.1. 在 manifest 中声明 activity


1.2.2. 配置使用 intent 过滤器
过滤器的作用就是声明其他 app 组件是如何激活该 activity 的
下面过滤器声明本 activity 对"main"动作进行响应,并处于"launcher"这个类别中


1.2.3. 声明权限

android:permission="com.google.socialapp.permission.SHARE_POST"	//定义权限
	//声明权限

1.3. 启动 Activity
(显式Intent)一个 Activity 启动另一个名为 SignInActivity 的 Activity:

Intent intent = new Intent(this, SignInActivity.class);
//从 this 启动 SignInActivity
startActivity(intent);

(隐式Intent)还可以对要执行的操作进行描述,若有多个 Activity 可以处理该 Intent,则由用户选择
如果你想允许用户发送电子邮件,可以创建以下 Intent:

Intent intent = new Intent(Intent.ACTION_SEND);	//这个和等同于 intent.setAction
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);

启动并获得返回结果

private void pickContact() {
   // Create an intent to "pick" a contact, as defined by the content provider URI
   Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);
   startActivityForResult(intent, PICK_CONTACT_REQUEST);
}
//PICK_CONTACT_REQUEST,主调和被调之间的暗号,自定义的常量
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
   // If the request went well (OK) and the request was PICK_CONTACT_REQUEST
   if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) {
       // Perform a query to the contact's content provider for the contact's name
       Cursor cursor = getContentResolver().query(data.getData(), new String[] {Contacts.DISPLAY_NAME}, null, null, null);
       if (cursor.moveToFirst()) { // True if the cursor is not empty
           int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);
           String name = cursor.getString(columnIndex);
           // Do something with the selected contact's name...
       }
   }
}
//resultCode == Activity.RESULT_OK,被调正确执行并返回正确结果
//requestCode == PICK_CONTACT_REQUEST,请求码,通过暗号判断结果是返回给谁的

1.4. 关闭一个Activity
可以使用

finish()
方法或者
finishActivity (int requestCode)
来关闭一个 activity,
但是我们不建议这么做,因为activity有其生命周期,系统会对activity的生命周期进行管理

2. 启动另一个Activity

代码出现错误 记得 import 对应的类

2.1. 响应 Send 按钮
在相应的 MainActivity.java 中添加方法 如

sendMessage()

为了匹配
android:onClick
属性值,该方法必须满足:
1.是 public
2.返回值为 void
3.有且仅有一个 View 作为参数

2.2. 构建一个Intent
Intent 构造方法的第二个参数为系统发送Intent的目标,为某应用组件的Class 也就是被启动的组件的类名
例:显式Intent 通过 putExtra 方法添加 “额外" 数据信息

public static final String EXTRA_MESSAGE = "com.example.myfirstapp.MESSAGE";
public void sendMessage(View view) {
   Intent intent = new Intent(this, DisplayMessageActivity.class);
   EditText editText = (EditText) findViewById(R.id.editText);
   String message = editText.getText().toString();
   //将这个文本字符串以键值对的形式附加到 Intent 中,
   //通常我们用应用的包名作为前缀,以保证键的唯一性
   intent.putExtra(EXTRA_MESSAGE, message);
   //通过 intent 启动另一个 activity,同时传递数据
   startActivity(intent);
}

2.3. 创建第二个 Activity

File > New > Activity > EmptyActivity
或者项目里右击 > New > Activity > EmptyActivity
注 LauncherActivity 的意思是主 Activity ,发射台

2.4. 显示消息
通过 getStringExtra 方法提取 Intent 传递的额外数据

//获取启动本 activity 的 Intent
Intent intent = getIntent();
//从该 Intent 中提取传递过来的数据
String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);
TextView textView = findViewById(R.id.textView);
textView.setText(message)

2.5. 添加向上导航
就是指明该 Activity 的逻辑父项


3. Activity生命周期

Activity 的三个稳定状态:继续 (Resumed)、暂停 (Paused)、停止 (Stopped)
六个生命周期方法:onCreate(), onStart(), onResume(), onPause(), onStop(), 和 onDestroy()

3.1. 实现生命周期回调方法

3.2. 调用onCreate()方法启动Activity
onCreate()执行结束后,系统立刻调用 onStart()和 onResume()方法,
你的Activity不会停留在 Created 和 Started 状态

3.3. Activity生命周期的最后一个回调方法onDestroy()
大部分的app不需要实现该方法,因为已经在onPause()和onStop()中执行了大部分的清理工作
特殊情况,在 onCreate() 中调用 finish(),系统立即调用 onDestroy() 而不会调用其它的生命周期方法

3.4. 暂停及重启一个Activity
暂停状态,并未被完全遮盖,仍可见
onPause()方法中应该执行尽量简单的操作

3.5. 停止和重启activity
停止状态完全遮盖,不可见
会释放几乎所有的不再需要的资源
每次你的activity变得可见的时候都会调用onStart()方法,只有在activity从stopped状态中恢复的时候才调用onRestart()方法

3.6. 保存 Activity 状态
用户不知道系统销毁 Activity 后又对其进行了重建
确保有关 Activity 状态的重要信息得到保留:onSaveInstanceState()
当你的activity开始stop的时候,系统会调用onSaveInstanceState(),系统会向该方法传递一个 Bundle
可以对 Bundle 使用 putString() 和 putInt() 等方法以名称-值对形式保存有关 Activity 状态的信息

保存 Activity 状态
static final String STATE_SCORE = "playerScore";
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // 保存用户当前的游戏状态
    savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
    // 总是首先调用父类中的onSaveInstanceState方法
    super.onSaveInstanceState(savedInstanceState);
}

恢复你的 Activity 状态
当用户离开你的activity时,系统调用这个方法并传递一个Bundle对象,如果系统必须重建该activity实例的时候,会把同一个Bundle对象传递给onRestoreInstanceState()和onCreate()方法

恢复 Activity 状态(两种方法) 1.必须检查一下Bundle是否是null,若null,系统会创建一个新的实例而不是重建该activity
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // 总是首先调用父类中的 onCreate方法
    // 检查我们是否是在重建以前销毁的本 Activity的实例
    if (savedInstanceState != null) {
        // 从保存的状态中恢复成员的值
        mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
    } else {
        // 新实例中的变量可能需要用默认值进行初始化
    }
}
2.该方法在onStart()方法之后被调用
只在有保存的数据需要恢复的时候用,不必检查Bundle
public void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    // 从保存实例中恢复状态变量值
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
}

3.7. 重建一个activity
新建和重建 用onCreate()
每次用户旋转屏幕的时候,你的activity都会销毁并重建

为了恢复你的 activity 中 view 的状态,该 view 必须有一个唯一的ID
如果小部件没有 ID,则系统无法保存其状态

3.8. 协调 Activity
启动第二个 Activity 的过程与停止第一个 Activity 的过程存在重叠

现有 Activity A、B,A停止,B启动的过程如下
1.A 执行 onPause()
2.B 执行 onCreate、onStart、onResume (Activity B 现在具有用户焦点)
3.然后,若 A 在屏幕上不再可见,则其 onStop() 方法执行

3.9. Activity 生命周期回调方法汇总表
在从 onPause() 返回时到 onResume() 被调用时 之间,系统可以终止 Activity
如果系统在紧急情况下必须恢复内存,则可能不会调用 onStop() 和 onDestroy()
因此,应该使用 onPause() 向存储设备写入至关重要的持久性数据(例如用户编辑)
不过,你应该对 onPause() 调用期间必须保留的信息有所选择,因为该方法中的任何阻止过程都会妨碍向下一个 Activity 的转变并拖慢用户体验

4. Activity的四种launchMode

一个 task 就是一个用户用于完成某项工作的 activity 集合
这些 activity 以栈 (back stack) 来进行管理

4.1. standard(默认)

不管有没有已存在的实例,都生成新的实例(activity 可以被多次实例化)

4.2. singleTop

如果发现有对应的Activity实例正位于栈顶,则重复利用,不再生成新的实例

4.3. singleTask

如果发现有对应的Activity实例,则使此Activity实例之上的其他Activity实例统统出栈,使此Activity实例成为栈顶对象,显示到屏幕前 若无实例,系统创建一个新的 task 并且实例化 activity 为新 task 的根

4.4. singleInstance

这种模式限定同一个task只能有一个activity (除此之外和 singleTask 相同),因此,这种模式一般用在一个app是由一个activity完成的情况 5. Intent 和 Intent 过滤器

Intent 是一个消息传递对象,可以使用它从其他应用组件请求操作

5.1. Intent 类型

显式 Intent:按名称(完全限定类名)指定要启动的组件 隐式 Intent :没有组件名称,而是声明要执行的操作,从而允许其他应用中的组件来处理它 显式 Intent 始终会传递给其目标,无论组件声明的 Intent 过滤器如何均是如此
如果没有为 Activity 声明任何 Intent 过滤器,则 Activity 只能通过显式 Intent 启动
不要为服务声明 Intent 过滤器,
使用隐式 Intent 启动服务存在安全隐患,因为你无法确定哪些服务将响应 Intent,且用户无法看到哪些服务已启动

5.2. 构建 Intent
组件名称、操作、数据、类别;Extra、标志
用 setDataAndType() 同时设置 URI 和 MIME 类型

5.2.1. 显式 Intent 示例
// 因为是在 Activity中执行,因此,'this'是指本 Activity
// fileUrl是一个字符串 URL, 比如  "http://www.example.com/image.png"
Intent downloadIntent = new Intent(this, DownloadService.class);
downloadIntent.setData(Uri.parse(fileUrl));
startService(downloadIntent);
5.2.2. 隐式 Intent 示例
注:若没有 Activity 接收 Intent,应用会崩溃,所以需要判断一下
// 使用字符串创建文本消息
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType("text/plain");
//系统并没有使用 URI,但已声明 Intent 的数据类型,用于指定 extra 携带的内容
// 验证是否有 activity处理该 Intent
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(sendIntent);
}
5.2.3. 强制使用应用选择器(同6.1.3)
强制打开对话框,让用户自己选择
Intent intent = new Intent(Intent.ACTION_SEND);
// UI中的文字要使用字符串资源 something like "Share this photo with"
String title = getResources().getString(R.string.chooser_title);
// Create intent to show the chooser dialog 强制创建应用选择器
Intent chooser = Intent.createChooser(intent, title);
// Verify the original intent will resolve to at least one activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(chooser);
}

5.3. 接收隐式 Intent

过滤器中的测试(需全部通过)
action
:在 name 属性中,声明接受的 Intent 操作,必须是文本字符串
data
:使用一个或多个指定数据 URI 各个方面(scheme、host、port、path 等)和 MIME 类型的属性,声明接受的数据类型
category
:在 name 属性中,声明接受的 Intent 类别,必须是文本字符串 为了接收隐式 Intent,必须将 CATEGORY_DEFAULT 类别包括在 Intent 过滤器中 (原因见5.5.2) 防止其他开发者显式访问该组件,针对该组件将
exported
属性设置为
"false"
启动器图标,ACTION_MAIN 和 CATEGORY_LAUNCHER 配对使用,Activity 才会显示在应用启动器中

5.4. 使用待定 Intent(略)*
5.5. Intent 解析

5.5.1. Action 测试
注:filter 中至少一个 action,否则所有 intent 都不能通过测试
通过:至少匹配其中一个 Action 5.5.2. 类别测试
通过:Intent 中的类别是过滤器中类别的子集,不声明类别也可通过
注:Android 会自动将 CATEGORY_DEFAULT 类别应用于
传递给 startActivity() 和 startActivityForResult() 的 所有隐式 Intent 5.5.3. 数据测试
每个 元素均可指定 URI 结构和数据类型(MIME 媒体类型)
URI 的每个部分均包含单独的 scheme 方案、host 主机、port 端口 和 path 路径 属性
://:/
注:如果没有指定scheme,host会被忽略
如果没有指定host,则port会被忽略
如果没有指定scheme和host,则path会被忽略 6. 与其他应用交互

6.1. 把用户转向另一个应用

6.1.1. 构建隐含 Intent
Uri 数据
通常,系统基于所包含的 Uri 数据确定 Intent 需要的相应 MIME 类型
若 Intent 不包含 Uri,应使用 setType() 指定与 Intent 关联的数据的类型。
设置 MIME 类型可进一步指定哪些类型的 Activity 应接收该 Intent
查看网页:
Uri webpage = Uri.parse("http://www.android.com");
Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);

可以通过 putExtra 来添加额外的数据

6.1.2. 验证是否存在接收 Intent 的应用

PackageManager packageManager = getPackageManager();
List activities = packageManager.queryIntentActivities(intent, 0);	//0处:PackageManager.MATCH_DEFAULT_ONLY
boolean isIntentSafe = activities.size() > 0;
if (isIntentSafe) {
    startActivity(intent);
}
6.1.3. 显示应用选择器(同5.2.3)

6.2. 获取 Activity 的返回结果
响应的 Activity 必须设计为返回结果,如下:

public void returnTOMain(View view) {
    EditText editText = (EditText)findViewById(R.id.ap_et_inputPhoneNumber);
    String phoneNumber = editText.getText().toString();
    Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse(phoneNumber));
    setResult(Activity.RESULT_OK, result);
    finish();
}

6.3. 启动activity
startActivityForResult(intent, REQUEST_CODE)
第二个参数,用于标识你的请求

6.4. 接收结果

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // Check which request we're responding to
    if (requestCode == PICK_CONTACT_REQUEST) {
        // Make sure the request was successful
        if (resultCode == RESULT_OK) {
            TextView textView = (TextView)findViewById(R.id.ma_tv_phoneNumber);
            textView.setText(data.getDataString());
        }
    }
}
7. 允许其他应用启动您的 Activity

7.1. 添加 Intent 过滤器

Action:对要执行的操作命名的字符串。通常是平台定义的值之一 Data:若无需声明关于数据的具体信息 Uri(比如,你的 Activity 处理其他类型的"额外"数据而不是 URI 时),可只指定 android:mimeType 属性声明您的 Activity 处理的数据类型,比如 text/plain 或 image/jpeg Category:通常与用户手势或 Activity 启动的位置有关 若有两对操作和数据的行为相斥,则需另创过滤器

7.2. 处理您的 Activity 中的 Intent
通常应在 onCreate() 和 onStart() 中执行 getIntent()

Intent intent = getIntent();
Uri data = intent.getData();
// Figure out what to do based on the intent type
if (intent.getType().indexOf("image/") != -1) {
    // Handle intents with image data ...
} else if (intent.getType().equals("text/plain")) {
    // Handle intents with text ...
}

7.3. 返回结果
只管调用 setResult,若 Intent 调用的是 startActivity,会自动忽略

// Create intent to deliver some kind of result data
Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri"));
setResult(Activity.RESULT_OK, result);
finish();
附:task与back栈 当用户启动一个新的task或者是使用Home按钮回到Home屏,task可以作为一个整体移入后台。当在后台的时候,task中的所有activity都停止了,但是back栈还保持完整,只是失去焦点而已 多个 task 处于后台时,系统可能会销毁后台 activity 来收回内存,这会引起 activity 状态的丢失 activity 停止时,系统会保持它的状态 Activity可以被多次实例化,甚至在其他task中 保存 activity 的状态
实现 onSaveInstanceState() 回调方法来预先保存它的状态,以便重建 管理 task
back 按钮作用:返回到前一个 activity

2.1. 定义加载(launch)模式

两种方式
1.在 manifest 中定义
2.在 Intent 中包含标志
后者优先级更高,且二者有些模式不相通

2.2. 使用manifest文件
四个模式,launchMode 属性的四种值

不管activity是在新的task中,还是在同一个task中,back按钮都能把前一个activity带到前台。然而,如果你以singleTask来启动一个activity,而已经有该activity的实例在后台task中,则整个后台task会来到前台

2.3. 使用Intent标志

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
FLAG_ACTIVITY_NEW_TASK = singleTask FLAG_ACTIVITY_SINGLE_TOP = singleTop FLAG_ACTIVITY_CLEAR_TOP,与singleTask不同的是 不创建新的 task

2.4. 处理affinity
affinity表示一个activity属于哪个task

taskAffinity 属性的默认值为清单中定义的包名 affinity 在两种环境下起作用
1.当 intent 启动一个 activity 的时候包含 FLAG_ACTIVITY_NEW_TASK 标志
2.当一个 activity 的属性 allowTaskReparenting 设置为 true 的时候(可以移动)

2.5. 清除back栈
用户离开 task 时间较长

alwaysRetainTaskState,根 activity 设置该属性值为 true
总是保持该栈中所有 activity 的状态 clearTaskOnLaunch,立即清除除根外的所有 activity finishOnTaskLaunch,同上,不过只针对一个 activity

2.6. 启动一个task
action.MAIN 和 category.LAUNCHER 配对使用

End.

Earnest~ 原创文章 92获赞 186访问量 2万+ 关注 私信 展开阅读全文
作者:Earnest~


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯