【安卓基础4】Activity(二)

🏆作者简介:|康有为| ,大四在读,目前在小米安卓实习,毕业入职

🏆安卓学习资料推荐:

        视频:b站搜动脑学院 视频链接 (他们的视频后面一部分没再更新,看看前面也挺好的)

        书籍:《第一行代码》(第3版) by 郭霖 (z-lib.org)

        思维导图: https://www.processon.com/view/link/62427cb2e0b34d0730e20e00(来自动脑学院)

🏆持续学习安卓知识中,共勉,我的【安卓】专栏中还有其他文章,持续更新中,欢迎关注

 

目录

一、Activity四大启动模式

任务栈

默认启动模式 Standard

栈顶复用模式 SingleTop

栈内复用模式 SingleTask

单实例模式 SingleInstance

组合示例

启动模式的一般使用场景

启动模式设置方法

1. 清单文件Manifest

2. 动态设置

二、在活动之间传递消息

Intent

Intent是什么?

Intent的组成部分

显示Intent

隐式Intent

启动内部Activity

主要特征:

用法示例:

向下一个Activity传递数据

putExtra()传字符串

使用 Bundle

上一个Activity返回数据

使用startActivityForResult (Android11开始 不推荐)

使用ActivityResultContract

三、为活动补充附加信息

利用资源文件配置字符串

利用元数据传递配置信息

给应用页面注册快捷方式


一、Activity四大启动模式

任务栈

在分别描述四种启动模式的特性前,需先引出一个概念:任务栈(也可以叫返回栈),它是一种先进后出的数据结构。

每个Activity都依附着任务栈运行,系统在创建Activity前会先创建一个ActivityRecord对象,用于映射该Activity,并将ActivityRecord对象压入任务栈中并处于栈顶,然后再通过ActivityRecord对象生成Activity实例。每当我们按下Back键或调用finish()方法去销毁一个Activity时,处于栈顶的Activity就会出栈,前一个入栈的Activity就会重新处于栈顶的位置。系统总会显示处于栈顶的Activity给用户。

一部正在运行app的安卓手机中,会有一个前台任务栈和0个或多个后台任务栈。当前在手机上运行的窗口,会有一个前台的任务栈,而处于后台的任务列表,每一个都对应着一个后台任务栈。当用户将后台应用重新切换至前台时,也伴随着将当前运行的前台任务栈移至后台,将系统下一秒想要运行的后台任务栈切换至前台运行的过程。

可以通过配置的方式指定Activity想要依附的任务栈:


<activity android:name=".MainActivity"android:taskAffinity="com.jamgu.test">
</activity>

通过在AndroidManifest.xml文件中设置,给MainActivity设置想要的任务栈是名为“com.jamgu.test”的任务栈。如果不设置,Activity默认所需任务栈的名字为程序的包名,即默认会将MainActivity压入与程序包名相同的任务栈。

某App先后打开两个活动,此时活动栈的变动情况如下图所示。

依次结束已打开的两个活动,此时活动栈的变动情况如下图所示。

  1. Standard:标准模式
  2. SingleTop:栈顶复用模式
  3. SingleTask:栈内复用模式
  4. SingleInstance:单实例模式

默认启动模式 Standard

该模式可以被设定,不在manifest设定时候,Activity 的默认模式就是standard。在该模式下,启动的Activity会依照启动顺序被依次压入Task栈中,按返回的就出栈:

栈顶复用模式 SingleTop

在该模式下,如果栈顶Activity为我们要新建的Activity(目标Activity),那么就不会重复创建新的Activity。

应用场景

适合开启渠道多、多应用开启调用的Activity,通过这种设置可以避免已经创建过的Activity被重复创建,多数通过动态设置使用。

栈内复用模式 SingleTask

与singleTop模式相似,只不过 singleTop模式是只是针对栈顶的元素,而singleTask模式下,如果task栈内存在目标Activity实例,则将task内的对应Activity实例之上的所有Activity 弹出栈,并将对应Activity置于栈顶,获得焦点。

应用场景

程序主界面:  我们肯定不希望主界面被创建多次,而且在主界面退出的时候退出整个App是最好的效果。

耗费系统资源的Activity:  对于那些及其耗费系统资源的Activity,我们可以考虑将其设为singleTask模式,减少资源耗费。(视频 很耗费资源)

单实例模式 SingleInstance

也可以说“全局唯一模式”

在该模式下,我们会为目标Activity创建一个新的Task栈,将目标Activity放入新的Task,并让目标Activity获得焦点。新的Task有且只有这一个Activity实例。―如果已经创建过目标Activity 实例,则不会创建新的Task,而是将以前创建过的Activity唤醒。

组合示例

看一个示例,Activity3设置为singleInstance,Activity1和Activity2默认(standard)。

下图程序流程中,黄色的代表Backround(后台)的Task,蓝色的代表Foreground(前台) 的Task。

返回时会先把Foreground的Task 中的Activity 弹出,直到Task销毁,然后才将Background的Task 唤到前台,所以最后将Activity3销毁之后,会直接退出应用。

启动模式的一般使用场景

standard 标准模式

默认的启动模式,适用于应用的大多数场景。

singleTop 栈顶复用模式

为了满足特定功能,不需要重复创建显示的页面

登录页面、WXPayEntryActivity、WXEntryActivity 、推送通知栏

singleTask 栈内复用模式

适用于重复创建比较耗性能的页面

主页面(Fragment的containerActivity)、WebView页面、扫一扫页面、电商中:购物界面,确认订单界面,付款界面

singleInstance 单实例模式

这个启动模式我们一般用不到,系统级应用使用该模式比较多。

系统Launcher(启动器)、锁屏键、来电显示等系统应用

启动模式设置方法

实际开发中需要将 xml文件的设置方法 和 动态的设置方法结合起来用

1. 清单文件Manifest

Manifest文件中正确设置 android:launchMode 属性

standard(默认值):无需特殊设置,因为它是默认值。

singleTop、singleTask、singleInstance:修改launchMode 的值

 


<activityandroid:name=".YourActivity"android:launchMode="singleTop">
</activity>

2. 动态设置

除了在清单文件中设置,还能动态的设置。

启动标志的取值说明如下:

  • Intent.FLAG_ACTIVITY_NEW_TASK:开辟一个新的任务栈
  • Intent.FLAG_ACTIVITY_SINGLE_TOP:当栈顶为待跳转的活动实例之时,则重用栈顶的实例
  • Intent.FLAG_ACTIVITY_CLEAR_TOP:当栈中存在待跳转的活动实例时,则重新创建一个新实例,

并清除原实例上方的所有实例

  • Intent.FLAG_ACTIVITY_NO_HISTORY:栈中不保存新启动的活动实例
  • Intent.FLAG_ACTIVITY_CLEAR_TASK:跳转到新页面时,栈中的原有实例都被清空

在Java代码中,你可以使用 Intent 对象来动态设置Activity的启动模式。在创建Intent的时候,可以通过 setFlags() 方法设置标志位来达到设置启动模式的效果。以下是一些示例代码:

standard模式:


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

singleTop模式:


Intent intent = new Intent(this, YourActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);

singleTask模式:


Intent intent = new Intent(this, YourActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);

singleInstance模式:


Intent intent = new Intent(this, YourActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);

在上述代码中,Intent.FLAG_ACTIVITY_SINGLE_TOP 表示 singleTop 模式,Intent.FLAG_ACTIVITY_NEW_TASKIntent.FLAG_ACTIVITY_CLEAR_TASK 组合表示 singleTask 模式。请根据需要选择适当的标志位。

二、在活动之间传递消息

Intent

Intent是什么?

翻译:意图,Intent是各个组件之间信息沟通的桥梁,它用于Android各组件之间的通信,主要完成下列工作:

  • 标明本次通信请求从哪里来、到哪里去、要怎么走。
  • 发起方携带本次通信需要的数据内容,接收方从收到的意图中解析数据。
  • 发起方若想判断接收方的处理结果,意图就要负责让接收方传回应答的数据内容。

Intent的组成部分

显示Intent

显式Intent,直接指定来源活动与目标活动,属于精确匹配。

Intent有多个构造函数的重载,Intent(ContextpackageContext,Class<?>cls)是其中一个。

这个构造函数接收两个参数,第一个参数Context要求提供一个启动活动的上下文,第二个参数Class则是指定想要启动的目标活动,通过这个构造函数就可以构建出Intent意图

在构建 Intent 时,第一个参数可以选择: thisActivityName.thisgetApplicationContext()

使用 getApplicationContext() 表明你希望使用应用程序的全局上下文来启动 ThirdActivity。这在一些特定场景下可能是合适的,但在其他情况下,你可能需要使用 thisActivityName.this 作为上下文,具体取决于你的需求和上下文的生命周期。

它有三种构建方式:

1.在Intent的构造函数中指定。


Intent intent = new Intent(this, ActNextActivity.class);
startActivity(intent);//启动目标活动

2.调用意图对象的setClass方法指定。


Intent intent = new Intent;
intent.setClass(this,ActNextActivity.class);
startActivity(intent);//启动目标活动

3.调用意图对象的setComponent方法指定。


Intent intent = new Intent();
ComponentName component = new ComponentName(this,ActNextActivity.class);
intent.setComponent(component);
startActivity(intent);//启动目标活动

隐式Intent

相比于显式Intent,隐式Intent则含蓄了许多,它并不明确指出我们想要启动哪那一个活动,而是指定了一系列更为抽象的action和category等信息,然后交由系统去分析这个Intent,并帮我们找出合适的活动去启动。

请注意,使用隐式Intent时,系统会寻找匹配给定动作和数据的组件。如果有多个组件匹配,系统将提供一个选择框,让用户选择要使用的应用程序。因此,隐式Intent提供了更大的灵活性,但也需要谨慎使用以确保得到预期的结果。

启动内部Activity

通过在标签下配置intent-filter:的内容,可以指定当前活动能够响应的actioncategory,打开AndroidManifest.xml,添加如下代码:

使用intent的另一个构造函数,直接将action的字符串传进去。


Intent intent = new Intent("android.intent.action.Button2");
//运行intent对象的实例
startActivity(intent);

启动外部Activity

使用隐式Intent,我们不仅可以启动自己程序内的活动,还可以启动其他程序的活动,这使得Android多个应用程序之间的功能共享成为了可能。比如说你的应用程序中需要展示一个网页,这时你没有必要自己去实现一个浏览器(事实上也不太可能),而是只需要调用系统的浏览器来打开这个网页就行了。


button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Intent intent = new Intent(Intent.ACTION_VIEW);intent.setData(Uri.parse("http://www.baidu.com"));startActivity(intent);}
});

这里我们首先指定了Intent的action是Intent.ACTION VIEW,这是一个Android系统内置的动作,其常量值为android.intent.action.VIEW。然后通过Uri.parse()方法,将一个地址字符串解析成一个Uri对象,再调用Intent的setData()方法将这个Uri对象传递进去。

主要特征:

  1. Action(动作): Intent 的动作是指要执行的操作,例如 ACTION_VIEW 用于查看数据,ACTION_SEND 用于发送数据等。
  2. Data(数据): 通过setData()setType()方法设置,指定要处理的数据的URI或MIME类型。
  3. Category(类别): 可选的,用于限定组件的类型,例如 Intent.CATEGORY_BROWSABLE 表示可以通过浏览器打开。

用法示例:

1.打开网页:


Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.example.com"));
startActivity(intent);

2.发送邮件:

Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_EMAIL, new String[]{"recipient@example.com"});
intent.putExtra(Intent.EXTRA_SUBJECT, "Subject");
intent.putExtra(Intent.EXTRA_TEXT, "Body of the email");
startActivity(intent);

 3.查看地图位置


Uri locationUri = Uri.parse("geo:0,0?q=latitude,longitude(label)");
Intent intent = new Intent(Intent.ACTION_VIEW, locationUri);
startActivity(intent);

4.拨打电话


Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:+123456789"));
startActivity(intent);

5.发送文本消息


Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse("smsto:" + Uri.encode("12345")));
intent.putExtra("sms_body", "Hello, how are you?");
startActivity(intent);

6.启动自定义组件(也就是上面讲的 启动内部Activity)


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

向下一个Activity传递数据

就是从A 跳到 B时,A发送给B的数据。上一个Activity指的就是A,下一个Activity指的就是B。

核心:

  • 使用Intent来传输,使用putExtra()方法将数据添加到Intent中。
  • 使用getIntent().getExtras() 获取数据

可以直接在putExtra() 方法里面传字符串,也可以使用 Bundle

putExtra()传字符串

在发送方Activity中传递字符串:

// 在发送方Activity中
String messageToSend = "你好,这是信息!";
Intent intent = new Intent(this, ReceiverActivity.class);
intent.putExtra("key", messageToSend);
startActivity(intent);

在接收方Activity中获取并显示字符串:


// 在接收方Activity中的onCreate()方法或其他适当的地方
Intent receivedIntent = getIntent();
String receivedMessage = receivedIntent.getStringExtra("key");// 然后,你可以将接收到的字符串显示在界面上,例如,使用TextView
TextView textView = findViewById(R.id.textView);
textView.setText(receivedMessage);

确保在接收方Activity的布局文件(例如activity_receiver.xml)中包含一个TextView,以便显示接收到的字符串:


<!-- activity_receiver.xml -->
<TextViewandroid:id="@+id/textView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="接收的信息会展示在这里" />

 

使用 Bundle

使用 Bundle 可以更方便地传递多个数据项,因为你可以在Bundle中存储多个键值对。此外,Bundle 还提供了不同的数据类型的方法,以满足不同类型的数据传递需求。

在发送方Activity中传递字符串:


// 在发送方Activity中
String messageToSend1 = "你好,这是信息1!";
String messageToSend2 = "你好,这是信息2!";
Intent intent = new Intent(this, ReceiverActivity.class);Bundle bundle = new Bundle();
bundle.putString("key1", messageToSend1);
bundle.putString("key2", messageToSend2);
intent.putExtras(bundle);
startActivity(intent);

在接收方Activity中获取并显示字符串:


// 在接收方Activity中的onCreate()方法或其他适当的地方
Intent intent = getIntent();
Bundle bundle = intent.getExtras();if (bundle != null) {String message1 = bundle.getString("key1");String message2 = bundle.getString("key2");// 然后,你可以将接收到的字符串显示在界面上,例如,使用TextViewTextView textView = findViewById(R.id.textView);textView.setText("接收到消息1: " + message1 +" 接收到消息2: "+ message2);
}

同样,确保在接收方Activity的布局文件中包含一个TextView,以便显示接收到的字符串。


<!-- activity_receiver.xml -->
<TextViewandroid:id="@+id/textView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="接收的信息会展示在这里" />

上一个Activity返回数据

意思就是,从A跳到B,A发送给B数据,B处理完这些数据后,B再返回给A数据。

核心:

  • 从A 发消息并跳转到 B 就是用 startActivity(intent);
  • 从A 发消息并跳转到 B,并接收B的返回的消息,就是用方法 startActivityForResult(intent, 1);
  • 从 Android 11 开始,Google 不再推荐使用 startActivityForResult() 方法,而是建议使用 ActivityResultContract API 来更灵活地进行 Activity 之间的数据传递。

示例:

A中有个按钮,点击就跳转到B,并给B发消息。B中有个按钮,接受到消息后,点击按钮就返回给A消息。

使用startActivityForResult Android11开始 不推荐)

在Activity A中发送消息:


public class ActivityA extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_a);Button myButton = findViewById(R.id.activity_a_button);myButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 处理按钮点击事件的代码Intent intent = new Intent(ActivityA.this, ActivityB.class);intent.putExtra("key", "B你好,我是A,你最近过的怎么样?");startActivityForResult(intent, 1); // 1是请求码,可以是任何整数,用于标识请求}});}//接收B返回过来的数据,并展示@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);TextView resultTextView = findViewById(R.id.activity_a_textView) ;if (requestCode == 1) { // 判断请求码是否是你发送请求时设定的if (resultCode == RESULT_OK) { // 判断B返回的结果是否成功String returnedData = data.getStringExtra("response_message");// 在这里处理从B返回的数据resultTextView.setText("B返回:" + returnedData);}}}
}

activity_a.xml 中布局


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".ActivityA"android:orientation="vertical"><TextViewandroid:id="@+id/activity_a_textView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="A接收到B返回的消息将会显示在这里" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/activity_a_button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="跳转到B" /></LinearLayout></LinearLayout>

在Activity B中返回消息:


public class ActivityB extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_b);TextView textView = findViewById(R.id.activity_b_textView);//接收A发过来的消息,并显示出来Bundle bundle = getIntent().getExtras();String str = bundle.getString("key");textView.setText("接收到A的消息: " + str);Button myButton = findViewById(R.id.activity_b_button);myButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 点击按钮,返回给A消息Intent intent = new Intent();Bundle bundle = new Bundle();bundle.putString("response_message","Hi,A,我最近很好,你呢");intent.putExtras(bundle);setResult(RESULT_OK,intent);finish();}});}
}

activity_b.xml 中布局


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".ActivityB"android:orientation="vertical"><TextViewandroid:id="@+id/activity_b_textView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="B接收到A的消息将会显示在这里" /><Buttonandroid:id="@+id/activity_b_button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="返回消息" />
</LinearLayout>

使用ActivityResultContract

只需要替换上面ActivityA的代码


package com.example.chapter03;import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;public class ActivityA extends AppCompatActivity {private TextView resultTextView ;//接收B返回过来的数据,并展示private final ActivityResultLauncher<Intent> activityLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),result -> {if (result.getResultCode() == RESULT_OK) {Intent data = result.getData();if (data != null) {String responseMessage = data.getStringExtra("response_message");resultTextView.setText("从B返回的数据: " + responseMessage);}}});@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_a);resultTextView = findViewById(R.id.activity_a_textView);//点击按钮,发送数据给B,并等待B传回数据Button goToBButton = findViewById(R.id.activity_a_button);goToBButton.setOnClickListener(v -> {Intent intent = new Intent(ActivityA.this, ActivityB.class);intent.putExtra("key", "B你好,我是A,你最近过的怎么样?");activityLauncher.launch(intent);});}
}

三、为活动补充附加信息

利用资源文件配置字符串

在 Android 中,你可以使用资源文件(如 res/values/strings.xml)来配置字符串,以便在 Activity 中引用这些字符串。这样的做法有助于代码的维护和国际化支持。以下是一些简单的步骤:

1.在 res/values/strings.xml 中定义字符串:

strings.xml 文件中,你可以定义应用中使用的所有字符串。例如:


<resources><string name="app_name">MyApp</string><string name="welcome_message">Welcome to my app!</string>
</resources>

2.在 Activity 中引用字符串:

在你的 Activity 中,你可以通过调用 getString(R.string.string_name) 来引用字符串。例如:


public class MyActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);String welcomeMessage = getString(R.string.welcome_message);// 现在,welcomeMessage 变量包含 "Welcome to my app!"}
}

这种做法的好处在于,如果你决定在应用中更改欢迎消息,你只需要在 strings.xml 文件中进行修改,而不需要修改代码中的硬编码字符串。

配置文件中的代码是不需要编译的,而java代码是需要编译的

如果需要在 XML 布局文件中引用字符串,也可以使用 @string/string_name 语法。


<TextViewandroid:id="@+id/welcomeTextView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/welcome_message" />

利用元数据传递配置信息

在 Android 中,你可以使用元数据(metadata)来传递配置信息。元数据是一种在 AndroidManifest.xml 文件中定义的键值对,可以在应用的组件(如 Activity、Service、BroadcastReceiver 等)中访问。以下是一些步骤,演示如何使用元数据传递配置信息:


1.在 AndroidManifest.xml 文件中定义元数据:

<application><activity> 或其他组件的标签中,可以使用 <meta-data> 元素定义键值对。


<application><activity android:name=".MainActivity"><meta-dataandroid:name="com.example.app.CONFIG_KEY"android:value="your_configuration_value" /><!-- 其他 activity 相关配置 --></activity><!-- 其他组件和配置 -->
</application>

在上述例子中,CONFIG_KEY 是元数据的键,your_configuration_value 是相应的值。

2.在 Activity 中读取元数据:

你可以在 Activity 中使用 getPackageManager().getApplicationInfo().metaData 获取应用的元数据,然后检索你定义的键值对。


import android.content.pm.ApplicationInfo;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);try {ApplicationInfo appInfo = getPackageManager().getApplicationInfo(getPackageName(), android.content.pm.PackageManager.GET_META_DATA);String configValue = appInfo.metaData.getString("com.example.app.CONFIG_KEY");// 在这里使用配置值// ...} catch (Exception e) {e.printStackTrace();}}
}

注意:在使用 getApplicationInfo() 方法时,需要处理 PackageManager.NameNotFoundException 异常。

这样,你就可以通过在 AndroidManifest.xml 文件中定义的元数据来传递配置信息。这种方法对于在应用启动时读取一些配置信息非常有用。如果需要在运行时动态更新配置信息,可能需要考虑其他的方案,比如使用 SharedPreferences 或其他配置管理方式。

给应用页面注册快捷方式

元数据不仅能传递简单的字符串参数,还能传送更复杂的资源数据,比如支付宝的快捷方式菜单。

  1. 在res下创建一个xml的文件夹
  2. 在xml文件夹里面创建一个shortcuts.xml文件
  3. 在清单文件AndroidMainfest.xml 的 主Activity标签里面定义快捷方式

元数据的meta-data标签除了前面说到的name属性和value属性,还拥有resource属性, 该属性可指定一个XML文件,表示元数据想要的复杂信息保存于XML数据之中。

利用元数据配置快捷菜单的步骤如下所示:

  • 在res/values/strings.xml添加各个菜单项名称的字符串配置
  • 创建res/xml/shortcuts.xml,在该文件中填入各组菜单项的快捷方式定义(每个菜单 对应哪个活动页面)。
  • 给activity节点注册元数据的快捷菜单配置

具体实现步骤请看视频讲解: 2022 最新 Android 基础教程,从开发入门到项目实战,看它就够了,更新中 P45

也可以看这篇博客:Android 长按APP图标弹出快捷方式(shortcuts)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/485465.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软考29-上午题-【数据结构】-排序

一、排序的基本概念 1-1、稳定性 稳定性指的是相同的数据所在的位置经过排序后是否发生变化。若是排序后&#xff0c;次序不变&#xff0c;则是稳定的。 1-2、归位 每一趟排序能确定一个元素的最终位置。 1-3、内部排序 排序记录全部存放在内存中进行排序的过程。 1-4、外部…

YOLOv5推理时出现:assert im0 is not None, f‘Image Not Found {path}‘

一、问题展示 Traceback (most recent call last):File "/media/hadoop/yolov5-7.0/detect.py", line 259, in <module>main(opt)File "/media/hadoop//yolov5-7.0/detect.py", line 254, in mainrun(**vars(opt))File "/home/hadoop/anaconda…

ChatGPT调教指南 | 咒语指南 | Prompts提示词教程(一)

在我们开始探索人工智能的世界时&#xff0c;了解如何与之有效沉浸交流是至关重要的。想象一下&#xff0c;你手中有一把钥匙&#xff0c;可以解锁与OpenAI的GPT模型沟通的无限可能。这把钥匙就是——正确的提示词&#xff08;prompts&#xff09;。无论你是AI领域的新手&#…

npm/nodejs安装、切换源

前言 发现自己电脑上没有npm也没有node很震惊&#xff0c;难道我没写过代码么&#xff1f;不扯了&#xff0c;进入正题哈哈…… 安装 一般没有npm的话会报错&#xff1a; 无法将“npm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称而且报这个错&#xff0c;我们执行…

python专业版破解激活(超详细)

python专业版破解激活 1.下载pycharm应用程序 这里我使用的版本是pycharm-professional-2023.3.2 下载pycharm程序的连接为&#xff1a; 百度网盘 请输入提取码 提取码为&#xff1a;nym0 2.安装 选择安装路径 下一步 这里全选 下一步 这里直接点击安装就可&#xff0c;其…

Java学习笔记2024/2/22

面向对象进阶部分学习方法&#xff1a; 特点&#xff1a; 逻辑性没有那么强&#xff0c;但是概念会比较多。 记忆部分重要的概念&#xff0c;理解课堂上讲解的需要大家掌握的概念&#xff0c;多多练习代码。 今日内容 复习回顾 static关键字 继承 教学目标 能够掌握st…

守护绿色屏障:智能高压森林应急消防泵|恒峰智慧科技

在茂密的森林中&#xff0c;树木蓊郁&#xff0c;绿意盎然。这里是大自然赋予我们的宝贵财富&#xff0c;是我们人类赖以生存的重要资源。然而&#xff0c;随着人类活动的增加&#xff0c;森林火灾频发&#xff0c;给我们的生活带来了极大的威胁。为了保护这片绿色屏障&#xf…

缓存篇—缓存雪崩、缓存击穿、缓存穿透

缓存异常会面临的三个问题&#xff1a;缓存雪崩、击穿和穿透。 其中&#xff0c;缓存雪崩和缓存击穿主要原因是数据不在缓存中&#xff0c;而导致大量请求访问了数据库&#xff0c;数据库压力骤增&#xff0c;容易引发一系列连锁反应&#xff0c;导致系统奔溃。不过&#xff0…

ChatGPT在数据处理中的应用

ChatGPT在数据处理中的应用 今天的这篇文章&#xff0c;让我不断体会AI的强大&#xff0c;愿人类社会在AI的助力下走向更加灿烂辉煌的明天。 扫描下面二维码注册 ​ 数据处理是贯穿整个数据分析过程的关键步骤&#xff0c;主要是对数据进行各种操作&#xff0c;以达到最终的…

【命令行工具kubectl】

如何在k8s的任意节点使用用kubectl # 正常在node节点上是无法执行kubectl命令 [rootk8s-node-01 ~]# kubectl get pods The connection to the server localhost:8080 was refused - did you specify the right host or port?1、将master节点中/etc/kubernetes/,admin.conf拷…

五分钟了解Python中的函数

函数&#xff1a;函数是组织好的&#xff0c;可重复使用的&#xff0c;用来实现单一&#xff0c;或相关联功能的代码段。 函数的定义 定是函数使用def关键字 def myfunc(x):if x > 0:return x else:return -x 空函数 def emptyfunc():pass 参数检查 def checkfunc(x):i…

2024 Sora来了!“手机Agent智能体”也来了!

近日&#xff0c;Open AI发布了能够根据文本生成超现实视频的工具Sora&#xff0c;多款震撼视频引爆科技圈刷屏&#xff0c;热度持续发酵占据AI领域话题中心&#xff0c;被认为是AGI实现过程里的重大里程碑事件。新一轮的人工智能浪潮给人类未来的生产和生活方式带来巨大而深远…