【安卓基础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 的值

 


<activity
    android: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() {
    @Override
    public 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 -->
<TextView
    android: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");
    // 然后,你可以将接收到的字符串显示在界面上,例如,使用TextView
    TextView textView = findViewById(R.id.textView);
    textView.setText("接收到消息1: " + message1 +" 接收到消息2: "+ message2);
}

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


<!-- activity_receiver.xml -->
<TextView
    android: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 {
    @Override
    protected 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() {
            @Override
            public void onClick(View v) {
                // 处理按钮点击事件的代码
                Intent intent = new Intent(ActivityA.this, ActivityB.class);
                intent.putExtra("key", "B你好,我是A,你最近过的怎么样?");
                startActivityForResult(intent, 1); // 1是请求码,可以是任何整数,用于标识请求
            }
        });
    }
    
    //接收B返回过来的数据,并展示
    @Override
    protected 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">

    <TextView
        android:id="@+id/activity_a_textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="A接收到B返回的消息将会显示在这里" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <Button
            android: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 {
    @Override
    protected 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() {
            @Override
            public 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">
    <TextView
        android:id="@+id/activity_b_textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="B接收到A的消息将会显示在这里" />
    <Button
        android: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);
                    }
                }
            });
    
    @Override
    protected 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 {
    @Override
    protected 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 语法。


<TextView
    android: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-data
            android: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 {

    @Override
    protected 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.mfbz.cn/a/405166.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

VSCode The preLaunchTask ‘C/C++: clang++ 生成活动文件‘ terminated with exit code -1

更改tasks.json文件里面的type为shell 选择g 选择g&#xff0c;然后点回到text.c&#xff0c;按下F5. 得到结果。 文中内容参考: 从零开始手把手教你配置属于你的VS Code_哔哩哔哩_bilibili https://blog.csdn.net/qq_63872647/article/details/128006861

基于springboot+vue的桂林旅游景点导游平台(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

从扩散模型基础到DIT

Diffusion model 扩散模型如何工作&#xff1f; 输入随机噪声和文本内容&#xff0c;通过多次预测并去除图片中的噪声后&#xff0c;最终生成清晰的图像。 以上左边这张图&#xff0c;刚开始是随机噪声&#xff0c;999为时间序列。 为什么不直接预测下一张图片呢&#xff1f;…

java 面向对象-上

1.构造器&#xff08;或构造方法&#xff09;&#xff1a; Constructor 构造器的作用&#xff1a; 1.创建对象 2.初始化对象的信息 2.使用说明&#xff1a; * 1.如果没显式的定义类的构造器的话&#xff0c;则系统默认提供一个空参的构造器 * 2.定义构造器的格式&#xff1a…

python OpenCV:seamlessClone泊松融合

一、seamlessClone函数的用法 翻译 https://www.learnopencv.com/seamless-cloning-using-opencv-python-cpp/ def seamlessClone(src, dst, mask, p, flags, blendNone): # real signature unknown; restored from __doc__"""seamlessClone(src, dst, mask, …

RM电控讲义【定时器篇】

HAL库最显著的特点是基于结构体从而利用句柄进而简化代码。 定时器初始化&#xff1a; TIM6_DAC_IRQn是STM32G431单片机中定时器TIM6的中断请求名。TIM6是STM32G431的一个基本定时器&#xff0c;具有基本的定时功能。当累加的时钟脉冲数超过预定值时&#xff0c;TIM6能触发中断…

C语言-指针初学速成

1.指针是什么 C语言指针是一种特殊的变量&#xff0c;用于存储内存地址。它可以指向其他变量或者其他数据结构&#xff0c;通过指针可以直接访问或修改存储在指定地址的值。指针可以帮助我们在程序中动态地分配和释放内存&#xff0c;以及进行复杂的数据操作。在C语言中&#…

如何快速卸载windows电脑的一些软件?

本系列是一些电脑常规操作的普及&#xff0c;有需要借鉴即可 注&#xff1a;每个电脑都会有差异&#xff0c;参考即可。 其实大部分软件你删除桌面上的图标不等于删除&#xff0c;因为桌面上的那个图标就是一个简单的快捷方式而已。 在这里插入图片描述 那如何正确的卸载软件呢…

数据安全:超越威胁搜寻,监控数据流和用户行为

网络安全曾经是建立在严格协议和反应措施之上的堡垒&#xff0c;现在正在经历变革。随着数字环境变得更加复杂和数据驱动&#xff0c;对保护数字资产采取细致入微的方法的需求比以往任何时候都更加明显。这种演变标志着与传统威胁检测的背离&#xff0c;转向强调上下文并抢占用…

windows下快速安装nginx 并配置开机自启动

1、下载地址&#xff1a;http://nginx.org/en/download.html 2、启动nginx 注意⚠️ 不要直接双击nginx.exe&#xff0c;这样会导致修改配置后重启、停止nginx无效&#xff0c;需要手动关闭任务管理器内的所有nginx进程。 在nginx.exe目录&#xff0c;打开命令行工具&#xf…

缓存篇—缓存击穿

在很多场景下&#xff0c;我们的业务通常会有几个数据会被频繁地访问&#xff0c;比如秒杀活动&#xff0c;这类被频地访问的数据被称为热点数据。 如果缓存中的某个热点数据过期了&#xff0c;此时大量的请求访问了该热点数据&#xff0c;就无法从缓存中读取&#xff0c;直接…

AD24-蛇形走线

一、单端蛇形走线 1、公差参数 2、布线-网络等长调节 3、参数说明 ①手工输入绕线的长度 ②参照个网络的长度绕线 ③按照自身设置的规绕线&#xff08;一般选用) 4、调节 5、最后 二、差分蛇形走线 1、布线-差分对网络等长调节 2、如在选中的时候出现问题&#xff0c;按CtrlD…

安卓游戏开发之音频技术优劣分析

一、引言 在安卓游戏开发中&#xff0c;音频处理技术扮演着至关重要的角色&#xff0c;它不仅能够增强游戏的沉浸感和玩家体验&#xff0c;还能通过声音效果传达关键的游戏信息。以下将对几种常见的安卓游戏音频处理技术进行优劣分析&#xff0c;并结合应用场景来阐述其特点。 …

自学Python第十八天-自动化测试框架(二):DrissionPage、appium

自学Python第十八天-自动化测试框架&#xff08;二&#xff09;&#xff1a;DrissionPage、appium DrissionPage环境和安装配置准备工作简单的使用示例控制浏览器收发数据包模式切换 浏览器模式创建浏览器对象访问页面加载模式none 模式技巧 获取页面信息页面交互查找元素ele()…

C 嵌入式系统设计模式 09:硬件适配器模式

本书的原著为&#xff1a;《Design Patterns for Embedded Systems in C ——An Embedded Software Engineering Toolkit 》&#xff0c;讲解的是嵌入式系统设计模式&#xff0c;是一本不可多得的好书。 本系列描述我对书中内容的理解。本文章描述访问硬件的设计模式之二&…

【C语言】程序编译链接详解

目录 一、程序的翻译环境和执行环境 二、编译链接过程 2.1、程序编译过程 2.2、程序编译链接的阶段 2.2.1、预处理 2.2.2、编译 2.2.3、汇编 2.2.4、链接 2.2.5、整体过程 三、运行环境 一、程序的翻译环境和执行环境 在ANSI C的任何一种实现中&#xff0c;存在两个不…

odoo16-API(Controller)带有验证访问的接口

odoo16-API&#xff08;Controller&#xff09;带有验证访问的接口 目前我使用odoo原生的登录token来验证登陆的有效性 废话不多说直接上代码 # 测试获取session_id import requests class GetOdooData(http.Controller):def getOdooToken(self):# http://localhost:8123访问…

要赢,且不止一次,2024创维汽车势不可挡!

随着除夕钟声的敲响&#xff0c;创维汽车迎来了全新的一年。过往取得的成绩已成为了历史&#xff0c;全新的未来还有待奋斗者们去开创。为辞旧迎新&#xff0c;创维汽车于2月22日及2月23日召开了“新春启航&#xff0c;共谋发展”营销会议&#xff0c;为2024做下全新布局。 创维…

【xss跨站漏洞】xss漏洞利用工具beef的安装

安装环境 阿里云服务器&#xff0c;centos8.2系统&#xff0c;docker docker安装 前提用root用户 安装docker yum install docker 重启docker systemctl restart docker beef安装 安装beef docker pull janes/beef 绑定到3000端口 docker run --rm -p 3000:3000 janes/beef …

【若依(ruoyi)】Java---如何在Apifox上传params参数--延伸--如何在Apifox上传Map类型参数

在使用若依开发过程中写接口的时候想在params中添加参数,但是使用params.key这种形式在后端是接收不到传过来的参数的,于是百般调研(百度),终于找到一个解决办法,就是在参数前后加上%5B和%5D,这两个参数会被编译为"["和"]",于是就对得上了,后端成功接受到参…