Android开发笔记(三)—Activity篇

news2024/9/27 7:22:35

活动组件Activity

  • 启动和结束
  • 生命周期
  • 启动模式
  • 信息传递
    • Intent
      • 显式Intent
      • 隐式Intent
    • 向下一个Activity发送数据
    • 向上一个Activity返回数据
  • 附加信息
    • 利用资源文件配置字符串
    • 利用元数据传递配置信息
    • 给应用页面注册快捷方式

启动和结束

(1)从当前页面跳到新页面:startActivity(new Intent(源页面.this,目标页面.class))
(2)从当前页面回到上一个页面,相当于关闭当前页面:finish()

生命周期

在这里插入图片描述
onCreate:创建活动。把页面布局加载到内存,进入了初始状态。
onStart:开始活动。把活动页面显示在屏幕上,进入了就绪状态。
onResume:恢复活动。活动页面进入活跃状态,能够与用户正常交互,例如允许响应用户的点击动作、允许用户输入文字等等。
onPause:暂停活动。页面进入暂停状态,无法与用户正常交互。
onStop:停止互动。页面将不在屏幕上显示。
onDestroy:销毁活动。回收活动占用的系统资源,把页面从内存中清除。
onRestart:重启活动。重新加载内存中的页面数据。
onNewIntent:重用已有的活动实例。

注:如果一个Activity已经启动过了,并且存在当前应用的Activity任务栈中,启动模式为singleTask,singleInstance或singleTop(此时已在任务栈顶端),那么在此启动或回到这个Activity的时候,不会创建新的实例,也就是不会执行onCreate方法,而是执行onNewIntent方法。

下图为活动的状态变迁过程:
在这里插入图片描述
打开新页面的方法调用顺序为:
onCreate->onStart->onResume
关闭旧页面的方法调用顺序为:
onPause->onStop->onDestroy

启动模式

(一)启动模式类型
(1)默认启动模式standard

  • 在该模式下,每启动一个Activity就会在栈顶创建一个新的实例,即启动的Activity会依照启动顺序被依次压入Task栈中。
  • 实际开发中,闹钟程序通常使用这种模式。
    在这里插入图片描述

(2)栈顶复用模式singleTop

  • 该模式会判断要启动的Activity实例是否位于栈顶,如果位于栈顶则直接复用,否则创建新的实例。
  • 实际开发中,浏览器的书签、应用支付跳转通常采用这种模式。
  • 适合开启渠道多、多应用开启调用的Activity,通过这种设置在一定条件下可以避免已经创建过的Activity被重复创建,多数通过动态设置使用。
    在这里插入图片描述

(3)栈内复用模式singleTask

  • 与singleTop模式类似,只不过singleTop模式只是针对栈顶的元素,而singleTask下,如果task栈内存在目标Activity实例,则将task内的对应Activity实例之上的所有Activity弹出栈,并将对应Activity置于栈顶,获得焦点。
  • 应用场景:
    程序/浏览器主界面:不希望主界面被创建多次,而且在主界面退出的时候整个App是最好的效果。
    耗费系统资源的Activity:对于那些极其消耗系统资源的Activity,我们可以考虑将其设为singleTask模式,减少资源耗费。

在这里插入图片描述
(4)全局唯一模式singleInstance

  • 在该模式下,我们会为目标Activity创建一个新的Task栈,将目标Activity放入新的Task,并让目标Activity获得焦点。新的Task有且只有这一个Activity实例。如果已经创建过目标Activity实例,则不会创建新的Task,而是将以前创建过的Activity唤醒。无论从哪个任务栈中启动该Activity,该实例在整个系统中只有一个。
  • 实际开发中,来电界面通常使用这种模式。
    在这里插入图片描述

(二)设置Activity的启动模式
(1)静态设置启动模式
打开配置文件AndroidManifest.xml,给activity节点添加属性android:launchMode,属性值填入standard表示采取标准模式,当然不添加属性的话默认就是标准模式standard。
<activity android:name=".MainActivity" android:launchMode="standard"/>
(2)动态设置启动模式
动态设置是通过Java代码设置的,通过Intent动态设置Activity启动模式。

Intent类的启动标志说明
Intent.FLAG_ACTIVITY_NEW_TASK开辟一个新的任务栈,该值类似于launchMode=“standard”;不同之处在于,如果原来不存在活动栈,则FLAG_ACTIVITY_NEW_TASK会创建一个新栈
Intent.FLAG_ACTIVITY_SINGLE_TOP当栈顶为待跳转的活动实例之时,则重用栈顶的实例。该值等同于launchMode=“singleTop”
Intent.FLAG_ACTIVITY_CLEAR_TOP当栈中存在待跳转的活动实例时,则重新创建一个实例,并清除原实例上方的所有实例。该值与launchMode="singleTask"类似,但singleTask采取onNewIntent方法启动原任务,而FLAG_ACTIVITY_CLEAR_TOP采取先调用onDestroy再调用onCreate来创建新任务
Intent.FLAG_ACTIVITY_NO_HISTORY该标志与launchMode=“standard”情况类似,但栈中不保存新启动的活动实例,这样下次无论以何种方式再启动该实例,也要走standard模式的完整流程,即栈中不保存新启动的活动实例
Intent.FLAG_ACTIVITY_CLEAR_TASK该标志非常暴力,跳转到新页面时,栈中的原有实例都被清空。注意该标志需要结合FLAG_ACTIVITY_NEW_TASK使用,即setFlags方法的参数为“Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK”

(三)启动模式的实际应用
(1)在两个活动之间交替跳转
背景介绍:假设活动A有个按钮,点击该按钮会跳到活动B;同时活动B也有个按钮,点击按钮会跳到活动A;从首页打开活动A之后,就点击按钮在活动A与活动B之间轮流跳转。此时活动页面的跳转流程为:首页->活动A->活动B->活动A->活动B->活动A->活动B->…多次跳转之后想回到首页,正常的话返回流程是这样的:…活动B->活动A->活动B->活动A->活动B->活动A->首页,每个箭头都代表按一次返回键,可见要按下许多次返回键才能返回首页。其实在活动A和活动B之间本不应该重复返回,因为回来回去总是这两个页面是没有意义的。照理说每个活动返回一次足矣,同一个地方返回两次已经是多余的了,再返回应当回到首页才是。也就是说,不管过去的时候怎么跳转,回来的时候应该按照这个流程:…活动B->活动A->首页,或者:…活动A->活动B->首页,总之已经返回了的页面,决不再返回第二次。
设计思想
对于不允许重复返回的情况,可以设置启动标志FLAG_ACTIVITY_CLEAR_TOP,即使活动栈里面存在待跳转的活动实例,也回重建该活动的实例,并清除原实例上方的所有实例,保证栈中最多只有该活动的唯一实例,从而避免了无谓的重复返回。于是活动A内部的跳转代码就改成了:

Intent intent=new Intent(ActStartActivity.this, ActFinishActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

当然活动B内部的跳转代码也要设置同样的启动标志:

Intent intent=new Intent(ActFinishActivity.this, ActStartActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);

(2)登录成功后不再返回登录页面
背景介绍:很多App第一次打开都要求用户登录,登录成功再进入App首页,如果这时按下返回键,发现并没有回到上一个登录页面,而是直接退出App了,这又是什么缘故呢?原来用户登录成功后,App便记下用户的登录信息,接下来默认该用户是登录状态,自然不必重新输入用户名和密码。既然默认用户已经登录,哪里还需要回到登录页面?不光登录页面,登录之前的其他页面包括获取验证码、找回密码等页面都不应回去,每次登录成功后,整个App就焕然一新仿佛忘记有登录页面这回事。
设计思想:对于回不去的登录页面情况,可以设置启动标志FLAG_ACTIVITY_CLEAR_TASK,该标志会清空当前活动栈里的所有实例。不过全部清空之后,意味着当前栈没法用了,必须另外找个活动栈才行,也就是同时设置启动标志FLAG_ACTIVITY_NEW_TASK,该标志用于开辟新任务的活动栈,这也就是为什么FLAG_ACTIVITY_CLEAR_TASK要配合着FLAG_ACTIVITY_NEW_TASK使用的原因,如果没有设置FLAG_ACTIVITY_NEW_TASK,则栈内对应的Activity销毁重新创建。
于是离开登录页面的跳转代码变成下面这样:

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

信息传递

Intent

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

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

Intent的组成部分

元素名称设置方法说明与用途
ComponentsetComponent组件,它指定意图的来源与目标
ActionsetAction动作,它指定意图的动作行为
DatasetData即Uri,它指定动作要操纵的数据路径
CategoryaddCategory类别,它指定意图的操作类别
TypesetType数据类型,它指定消息的数据类型
ExtrasputExtras扩展信息,它指定装载的包裹信息
FlagssetFlags标志位,它指定活动的启动标志

显式Intent

显式意图直接指定来源活动与目标活动,属于精确匹配
在构建一个意图对象时,需要指定两个参数,第一个参数表示跳转的来源页面,即“来源Activity.this”;第二个参数表示待跳转的页面,即“目标Activity.class”,具体的意图构建方式有如下3种:
(1)在Intent的构造函数中指定

Intent intent=new Intent(this,ActNextActivity.class);

(2)调用意图对象的setClass方法指定

Intent intent=new Intent();
intent.setClass(this,ActNextActivity.class);

(3)调用意图的setComponent方法指定

Intent intent=new Intent();
ComponentName component=new ComponentName(this,ActNextActivity.class);
intent.setComponent(component);

隐式Intent

没有明确指定要跳转的目标活动,只给出一个动作字符让系统自动匹配,属于模糊匹配
动作名称既可以通过setAction方法指定,也可以通过构造函数Intent(String action)直接生成意图对象。
常见的系统动作如下:

Intent类的系统动作变量名系统动作的常量值说明
ACTION_MAINandroid.intent.action.MAINApp启动时的入口
ACTION_VIEWandroid.intent.action.VIEW向用户显示数据
ACTION_SENDandroid.intent.action.SEND分享内容
ACTION_CALLandroid.intent.action.CALL直接拨号
ACTION_DIALandroid.intent.action.DIAL准备拨号
ACTION_SENDTOandroid.intent.action.SENDTO发送短信
ACTION_ANSWERandroid.intent.action.ANSWER接听电话

1)跳转到自己开发的APP
如果想要跳转到同一项目的不同模块(module),需要在目标模块的清单文件中做如下操作:

<activity
     android:name=".CalculatorActivity"
     android:exported="true">
     <intent-filter>
           <action android:name="android.intent.action.MAIN" />
           <category android:name="android.intent.category.LAUNCHER" />
     </intent-filter>
     <intent-filter>
           <action android:name="android.intent.action.WMY" />
           <category android:name="android.intent.category.DEFAULT" />
     </intent-filter>
</activity>

两个intent-filter表示CalculatorActivity有两种启动方式,第一种是直接在桌面点图标来启动,第二种是通过其他应用来启动。
以及需要在源模块的交互代码中做以下操作:

if(v.getId()==R.id.btn_my){
	Intent intent=new Intent();
    intent.setAction("android.intent.action.WMY");
    intent.addCategory(Intent.CATEGORY_DEFAULT);
    startActivity(intent);
}

注:系统应用因为没有对应的Activity.class,所以只能通过隐式Intent跳转。系统应用就是找不到对应Activity的应用。

2)跳转到手机自带的系统应用
如上面常见的Intent类的系统动作所示,以准备拨号和发短信为例:

String phoneNo="12345";
        Intent intent=new Intent();
        if(v.getId()==R.id.btn_dial){
            //设置意图动作为准备拨号
            intent.setAction(Intent.ACTION_DIAL);
            //声明一个拨号的Uri
            Uri uri= Uri.parse("tel:"+phoneNo);
            intent.setData(uri);
            startActivity(intent);
        }
        else if(v.getId()==R.id.btn_sms){
            intent.setAction(Intent.ACTION_SENDTO);
            Uri uri2=Uri.parse("smsto:"+phoneNo);
            intent.setData(uri2);
            startActivity(intent);
        }

整体代码如下:
ActionUriActivity.java

package com.example.myapplicationtwo;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
public class ActionUriActivity extends AppCompatActivity implements View.OnClickListener {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_action_uri);
        findViewById(R.id.btn_dial).setOnClickListener(this);
        findViewById(R.id.btn_sms).setOnClickListener(this);
        findViewById(R.id.btn_my).setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        String phoneNo="12345";
        Intent intent=new Intent();
        if(v.getId()==R.id.btn_dial){
            //设置意图动作为准备拨号
            intent.setAction(Intent.ACTION_DIAL);
            //声明一个拨号的Uri
            Uri uri= Uri.parse("tel:"+phoneNo);
            intent.setData(uri);
            startActivity(intent);
        }
        else if(v.getId()==R.id.btn_sms){
            intent.setAction(Intent.ACTION_SENDTO);
            Uri uri2=Uri.parse("smsto:"+phoneNo);
            intent.setData(uri2);
            startActivity(intent);
        }
        else if(v.getId()==R.id.btn_my){
            intent.setAction("android.intent.action.WMY");
            intent.addCategory(Intent.CATEGORY_DEFAULT);
            startActivity(intent);
        }
    }
}

activity_action_uri.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"
    android:orientation="vertical">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="5dp"
        android:text="点击以下按钮将向号码12345发起请求"/>
    <Button
        android:id="@+id/btn_dial"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="跳到拨号页面"/>
    <Button
        android:id="@+id/btn_sms"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="跳到短信页面"/>
    <Button
        android:id="@+id/btn_my"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="跳到我的页面"/>
</LinearLayout>

目标APP清单文件AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Experiment01">
        <activity
            android:name=".CalculatorActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.WMY" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>
</manifest>

向下一个Activity发送数据

Intent使用Bundle对象存放待传递的数据信息。
Bundle对象操作各类型数据的读写方法说明如下:

数据类型读方法写方法
整型数getIntputInt
浮点数getFloatputFloat
双精度数getDoubleputDouble
布尔值getBooleanputBoolean
字符串getStringputString
字符串数组getStringArrayputStringArray
字符串列表getStringArrayListputStringArrayList
可序列化序列getSerializableputSerializable

在代码中发送消息包裹,调用意图对象的putExtras方法,即可存入消息包裹:

//ActSendActivity.java
Intent intent=new Intent();
Bundle bundle=new Bundle();
bundle.putString("request_time",DateUtil.getNowTime());//getNowTime是编写好的utils工具包中DateUtil工具库中用于获取当前事件的函数
bundle.putInt("request_count",1);
intent.putExtras(bundle);
startActivity(intent)

在代码中接收消息包裹,调用意图对象的getExtras方法,即可取出消息包裹:

//ActReceiveActivity.java
Bundle bundle=getIntent().getExtras();
String request_time=bundle.getString("request_time");
Int request_count=bundle.getInt("request_count");

向上一个Activity返回数据

处理下一个页面的应答数据,详细步骤如下:
①上一个页面打包好请求数据,调用ActivityResultLauncher方法执行跳转动作。
②下一个页面接收并解析请求数据,进行相应处理。
③下一个页面在返回上一个页面时,打包应答数据并调用setResult方法返回数据包裹。
④上一个页面重写方法onActivityResult ,解析获得下一个页面的返回数据。

注:startActivityForResult方法已经过时。

以请求方Activity与应答方Activity之间的数据传递为例详细描述该过程:
请求方
①ActRequestActivity.java

package com.example.myapplicationtwo;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
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.view.View;
import android.widget.TextView;
import com.example.myapplicationtwo.utils.DateUtil;
public class ActRequestActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String mRequest="你直接给我坐下";
    private ActivityResultLauncher<Intent> register;
    private TextView tv_request,tv_response;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_act_request);
        tv_request=findViewById(R.id.tv_request);
        tv_request.setText("待发送的信息是:" +mRequest);
        tv_response=findViewById(R.id.tv_response);
        findViewById(R.id.btn_request).setOnClickListener(this);
        register = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
            if (result!=null){
                Intent data = result.getData();
                if(data!=null && result.getResultCode()==RESULT_OK){
                    Bundle bundle=data.getExtras();
                    String response_time=bundle.getString("response_time");
                    String response_content=bundle.getString("response_content");
                    String desc=String.format("收到返回信息:\n应答时间为%s\n应答内容为%s",response_time,response_content);
                    //把返回信息的详情显示在文本视图上
                    tv_response.setText(desc);
                }
            }
        });
    }
    @Override
    public void onClick(View v) {
        Intent intent=new Intent(ActRequestActivity.this,ActResponseActivity.class);
        Bundle bundle=new Bundle();
        bundle.putString("request_time", DateUtil.getNowTime());
        bundle.putString("request_content",mRequest);
        intent.putExtras(bundle);
        register.launch(intent);

    }
}

②activity_act_request.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ActRequestActivity"
    android:orientation="vertical">
    <!-->上一个页面发送的内容<-->
    <TextView
        android:id="@+id/tv_request"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <Button
        android:id="@+id/btn_request"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="传送请求数据"/>
    <!-->下一个页面应答的内容<-->
    <TextView
        android:id="@+id/tv_response"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

应答方
①ActResponseActivity.java

package com.example.myapplicationtwo;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import com.example.myapplicationtwo.utils.DateUtil;

public class ActResponseActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String mResponse="真的太没实力了";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_act_response);
        TextView tv_request=findViewById(R.id.tv_request);
        //获取从上一个页面传来的数据
        Bundle bundle=getIntent().getExtras();
        String request_time=bundle.getString("request_time");
        String request_content=bundle.getString("request_content");
        String desc=String.format("收到请求信息:\n请求时间为%s\n请求内容为%s",request_time,request_content);
        //把请求的信息显示在文本视图上面
        tv_request.setText(desc);
        findViewById(R.id.btn_response).setOnClickListener(this);

        TextView tv_response=findViewById(R.id.tv_response);
        tv_response.setText("待返回的消息为:"+mResponse);

    }
    @Override
    public void onClick(View v) {
        //携带应答数据
        Intent intent=new Intent();
        Bundle bundle=new Bundle();
        bundle.putString("response_time",DateUtil.getNowTime());
        bundle.putString("response_content",mResponse);
        intent.putExtras(bundle);
        //携带意图返回上一个页面 RESULT_OK表示处理成功
        setResult(Activity.RESULT_OK,intent);
        //强行结束当前页面 携带数据返回上一个页面
        finish();
    }
}

②activity_act_response.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ActResponseActivity"
    android:orientation="vertical">
    <!-->上一个页面发送的内容<-->
    <TextView
        android:id="@+id/tv_request"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <Button
        android:id="@+id/btn_response"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="传送请求数据"/>
    <!-->下一个页面应答的内容<-->
    <TextView
        android:id="@+id/tv_response"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

运行效果
在这里插入图片描述

附加信息

利用资源文件配置字符串

<!-->values/string.xml<-->
<string name="idea">真的是太没实力了</string>
//MainActivity.java
String idea=getString(R.string.idea);

利用元数据传递配置信息

在Java代码中,获取元数据信息的步骤分为下列三步:

  • 调用getPackageManager方法获得当前应用的包管理器;
  • 调用包管理器的getActivityInfo方法获得当前活动的信息对象;
  • 活动信息对象的metaData是Bundle包裹类型,调用包裹对象的getString即可获得指定名称的参数值;
<!-->AndroidManifest.xml<-->
<activity
    android:name=".MainActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <meta-data android:name="idea" android:value="真的是太没实力了"/>
</activity>
//MainActivity.java
//获取应用包管理器
        PackageManager pm = getPackageManager();
        try {
            //从应用包管理器中获取当前的活动信息
            ActivityInfo info = pm.getActivityInfo(getComponentName(),PackageManager.GET_META_DATA);
            //获取活动附加的元数据信息
            Bundle bundle=info.metaData;
            String idea_meta = bundle.getString("idea");
        } catch (PackageManager.NameNotFoundException e) {
            throw new RuntimeException(e);
        }

给应用页面注册快捷方式

元数据不仅能传递简单的字符串参数,还能传送更加复杂的资源数据,比如说支付宝的快捷方式菜单。
①首先在Project视图下的res目录下新建文件夹xml,在xml文件夹中新建一个values xml file,其名为shortcuts.xml,意为“捷径”。
②在AndroidManifest.xml文件下的主活动中添加元数据,使得长按会弹出之前xml文件下的shortcuts.xml菜单。

<activity
    android:name=".MainActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
         <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts"/>
</activity>

③在shortcuts.xml文件中编写菜单列表内容。
其中shortcutShortLabelshortcutLongtLabel中的内容通过string.xml字符串资源文件定义。
targetPackage为java文件下的文件名,targetClass为捷径跳转的Activity名称,这些待跳转的Activity因为是通过其他Activity启动的,所以需要在清单文件中将它们的enabled属性设置为true

<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
    <shortcut
        android:shortcutId="first"
        android:enabled="true"
        android:icon="@mipmap/ic_launcher"
        android:shortcutShortLabel="@string/first_short"
        android:shortcutLongLabel="@string/first_long">
        <intent
            android:action="android.intent.action.VIEW"
            android:targetPackage="com.example.myapplicationtwo"
            android:targetClass="com.example.myapplicationtwo.ActStartActivity"/>
        <categories android:name="android.shortcut.conversation"/>
    </shortcut>

    <shortcut
        android:shortcutId="second"
        android:enabled="true"
        android:icon="@mipmap/ic_launcher"
        android:shortcutShortLabel="@string/second_short"
        android:shortcutLongLabel="@string/second_long">
        <intent
            android:action="android.intent.action.VIEW"
            android:targetPackage="com.example.myapplicationtwo"
            android:targetClass="com.example.myapplicationtwo.ActRequestActivity"/>
        <categories android:name="android.shortcut.conversation"/>
    </shortcut>

    <shortcut
        android:shortcutId="third"
        android:enabled="true"
        android:icon="@mipmap/ic_launcher"
        android:shortcutShortLabel="@string/third_short"
        android:shortcutLongLabel="@string/third_long">
        <intent
            android:action="android.intent.action.VIEW"
            android:targetPackage="com.example.myapplicationtwo"
            android:targetClass="com.example.myapplicationtwo.ActionUriActivity"/>
        <categories android:name="android.shortcut.conversation"/>
    </shortcut>
</shortcuts>

④效果展示。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据库软考知识

分布式数据库透明性 封锁 加上共享锁之后只能加共享锁&#xff0c;加上排他锁之后&#xff0c;啥锁都不能加。 分布式数据库特性 伪传递定理 SQL函数定义&#xff0c;有点冷 来了奥&#xff0c;更冷 存储过程 很重要&#xff0c;下午第二大题也是数据库

解决QtCreator11及更高版本使用JDK17时无法生成APK

1.修改gradle文件&#xff0c;增加如下内容&#xff1a; DEFAULT_JVM_OPTS"-Xmx5120m --add-exportsjava.base/sun.nio.chALL-UNNAMED \ --add-opensjava.base/java.langALL-UNNAMED \ --add-opensjava.base/java.lang.reflectALL-UNNAMED \ --add-opensjava.base/java.io…

用户优先:确保微信小程序手机号授权在新旧版本中无缝衔接

&#x1f52d; 嗨&#xff0c;您好 &#x1f44b; 我是 vnjohn&#xff0c;在互联网企业担任 Java 开发&#xff0c;CSDN 优质创作者 &#x1f4d6; 推荐专栏&#xff1a;Spring、MySQL、Nacos、Java&#xff0c;后续其他专栏会持续优化更新迭代 &#x1f332;文章所在专栏&…

SQL注入——二次注入漏洞

文章目录 SQL注入——二次注入漏洞1. 二次注入原理2. 二次注入需要具备的两个条件3. 二次注入实例4. 总结 SQL注入——二次注入漏洞 1. 二次注入原理 在第一次插入恶意数据的时候&#xff0c;只是对其中的特殊字符进行了转义&#xff0c;在写入数据库的时候还是原来的字符&am…

9.多线程之定时器与线程池

定时器与线程池 文章目录 定时器与线程池1. 定时器1.1 定时器的工作原理1.2 定时器的使用2.3 实现定时器 2. 线程池2.1 线程池存的优点2.2 线程池的使用2.3 线程池的原理2.3.1 工厂模式2.3.2 ThreadPoolExecutor类 2.4 实现线程池 1. 定时器 定时器也是软件开发中的一个重要组件…

【GEE】Google Earth Engine(GEE)注册详细教程无需教育邮箱

这个专栏真的是纠结了很久&#xff0c;不知道到底要不要分享自己在学习GEE的时候的一些经验和代码。因为本人在日常中使用Python和ENVI多点&#xff0c;虽然GEE也会用但不至于频繁使用&#xff0c;同时针对GEE其实官网给出了很多接口的使用方法&#xff0c;国内外也有很多人分享…

编译正点原子LINUXB报错make: arm-linux-gnueabihf-gcc:命令未找到

编译正点原子LINUXB报错make: arm-linux-gnueabihf-gcc&#xff1a;命令未找到 1.报错内容2.解决办法3./bin/sh: 1: lzop: not found4.编译成功 1.报错内容 make: arm-linux-gnueabihf-gcc&#xff1a;命令未找到CHK include/config/kernel.releaseCHK include/genera…

全面提升企业管理效率,助力企业持续增长——三叠云进销存解决方案

企业在生产经营过程中&#xff0c;高效的进销存管理是企业成功的关键因素之一。它不仅能够优化企业的资金流动&#xff0c;避免库存积压和断货现象&#xff0c;提高客户满意度&#xff0c;而且可以优化供应链&#xff0c;减少运营成本&#xff0c;提高生产和物流效率。三叠云正…

C语言 数据的存储2

如图所示代码&#xff1a; 代码运行结果为&#xff1a; 这是什么原因呢&#xff1f; 解析: 因为unsigned int是无符号整形&#xff0c;而我们的for循环的条件是 所以我们会一直循环下去&#xff0c;至于我们的结果为什么会是 一个unsigned int类型是4个字节&#xff0c;38位&am…

论文范文:论基于架构的软件设计方法及应用

注意:范文只适用于帮助大家打开写作思路,并不能作为素材直接用于平时练习、考试中。考试中直接使用范文的素材,会有被认定为雷同卷的风险。 摘要: 2022年4月,本人所在单位计划研发生态集装箱管理控制平台项目。该平台主要用于与现有公司生态集装箱产品做对接,达到远程控制…

【AI视野·今日Robot 机器人论文速览 第六十期】Mon, 23 Oct 2023

AI视野今日CS.Robotics 机器人学论文速览 Mon, 23 Oct 2023 Totally 26 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Robotics Papers A Review of Prospects and Opportunities in Disassembly with Human-Robot Collaboration Authors Meng Lun Lee, Xiao Lian…

vscode开启emmet语法

需要在setting.json中添加配置 首先进入设置&#xff0c;然后点击右上角 Vue项目添加如下配置 "emmet.syntaxProfiles": { "vue-html": "html", "vue": "html" },React项目添加如下配置 "emmet.includeLanguages&quo…

Google搜索中,搜索关键词的技巧

最近在b站看到一个关于搜索的视频&#xff0c;感觉比较有用&#xff0c;先mark下来 1、巧用限定关键词符号""&#xff0c;也就是用英文的双引号&#xff0c;去搜索包含搜索词及这个搜索词字序的搜索结果。 如搜索 "菊花茶"&#xff0c;这个有用的点在于…

OpenCV官方教程中文版 —— Hough 圆环变换

OpenCV官方教程中文版 —— Hough 圆环变换 前言Hough 圆环变换 前言 目标 • 学习使用霍夫变换在图像中找圆形&#xff08;环&#xff09; • 学习函数&#xff1a;cv2.HoughCircles() Hough 圆环变换 opencv_logo.png&#xff1a; # -*- coding: utf-8 -*- import cv2 …

生态系统服务(InVEST模型)的人类活动、重大工程生态成效评估、论文写作等具体应用

以InVEST模型结合实际项目进行由浅入深的实战技术培训&#xff0c;Ai尚研修针对11期InVEST模型实践技术会议参会学者的特点及需求进行分析&#xff0c;融合课程体系&#xff0c;对接工作实际项目及论文写作&#xff0c;解决参会者关注的重点及实际项目过程问题&#xff0c;课程…

C++新经典 | 记录在最后的高阶知识点

目录 一、函数调用运算符与function类模板 1.函数调用运算符 &#xff08;1&#xff09;函数类型 &#xff08;2&#xff09;可调用对象 2.function类模板 二、万能引用类型 1.万能引用 2.万能引用资格的剥夺与辨认 &#xff08;1&#xff09;const修饰词 &#xff0…

人工智能基础_机器学习011_梯度下降概念_梯度下降步骤_函数与导函数求解最优解---人工智能工作笔记0051

然后我们来看一下梯度下降,这里先看一个叫 无约束最优化问题,,值得是从一个问题的所有可能的备选方案中选最优的方案, 我们的知道,我们的正态分布这里,正规的一个正态分布,还有我们的正规方程,他的这个x,是正规的,比如上面画的这个曲线,他的这个x,就是大于0的对吧,而现实生活…

Java反射调用ashx

这篇文章卡了大概一周&#xff0c;一个是没时间&#xff0c;只能带娃加锻炼间隙挤点时间&#xff0c;一个是碰到了问题卡住了。本篇实现反射调用ashx实现类的基础结构。 首先申明ashx的接口&#xff0c;所有的ashx实现类继承实现该接口的基类 package appcode; import java.i…

dbeaver查看表,解决证书报错current license is non-compliant for [jdbc]

http://localhost:9200/_license { “license” : { “status” : “active”, “uid” : “b91ae0e0-b04d-4e20-8730-cf0bca7b2035”, “type” : “basic”, “issue_date” : “2023-02-22T14:33:27.648Z”, “issue_date_in_millis” : 1677076407648, “max_nodes” : 10…

Leetcode 43. 字符串相乘 中等

题目 - 点击直达 1. 43. 字符串相乘 中等1. 题目详情1. 原题链接2. 题目要求3. 基础框架 2. 思路一 做加法1. 思路分析2. 时间复杂度3. 代码实现 3. 思路二 做乘法1. 思路分析2. 时间复杂度3. 代码实现 1. 43. 字符串相乘 中等 1. 题目详情 给定两个以字符串形式表示的非负整…