7天入门Android开发之第2天——四大组件之活动

一、活动是什么

        活动(Activity)是 Android 应用程序中的一个重要组件,它代表用户界面上的单个窗口,通常会填充整个屏幕。通过活动,可以创建各种各样的用户界面,并控制界面的行为。活动可以包含各种 UI 元素,例如按钮、文本框、图像等,以及与用户交互的逻辑,比如响应用户的点击、触摸等操作。通过定义不同的活动,可以实现应用程序中的各种功能和界面。

二、创建一个活动

        在上一节我们只是创建了一个HelloWorld项目,在界面上显示Hello world字符串。其实在着项目中android studio已经为我们创建了一个活动,就是通过这个活动来显示Hello world字符串。现在原来的HelloWorld项目中来重新创建一个活动。

        1)鼠标右键点击com.example.helloworld在出现的侧边栏选择New再点击Activity,最后出现的侧边栏就是活动的样式,可以选择自己相适应的活动减少开发时间,选择Empty Views Activity就好

  

图2-1 创建活动

        2)出现这个界面,其中Activity为活动名,,勾选Generate a Layout File,表示创建layout作为活动界面,Layout Name 表示创建layout文件的文件名,Launcher Activity表示是否将该活动作为主活动,也就是作为第一个显示的界面,暂时不要勾选;package name 表示该活动存放在那个包下面;Source Language表示使用那种开发语言,Java即可;点击finish,完成活动的创建。

图2-2 设置活动属性

        3)活动创建后可以再com.example。helloworld下面看到FirstActivist,现在点击运行会发现界面仍然是之前的Hello world字符串,如图2我们的FirstActivity是没有添加任何控件的,应该是空白的,仍然显示的是之前Android studio创建的活动,那怎么才能显示刚才创建的活动呢。首先先说第一种办法,在Androidmanifests.xml中修改。将Android studio自动注册的部分,如下

        <activityandroid:name=".FirstActivity"android:exported="false" /><activityandroid:name=".MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity>

图2-3 原始Androidmanifests.xml

修改为如下,可以看到只是将

         <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

修改了位置,以及android:exported设置为true,,这些语句就是将程序入口点设置为当前活动,有且只能有一个不然程序找不到入口点,Android 12 中,如果一个活动(Activity)可启动,则必须将其导出(exported),这样它才能被其他应用程序调用,android:exported必须设置为true。

        <activityandroid:name=".FirstActivity"android:exported="true" /><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter><activityandroid:name=".MainActivity"android:exported="true"></activity>

图2-4 修改后Androidmanifests.xml

现在我们来点击运行可看到如图2-7

            

           图 2-6 原始显示活动                                    图2-7 修改后显示FirstActivity活动

三、给活动添加控件

        刚才我们创建活动的时Generate a Layout File,创建完活动即可在res/layout下面看到我们创建的xml文件,如图2-8,通过这个文件可以为这个界面添加各种各样的控件,

图2-8

1)常用布局

        打开activity_first.xml文件,点击右上角split就看看见创建控件后的界面的样式了,如图2-9

图 2-9

在中间编辑区可以看到Android studio自动生成的布局为

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".FirstActivity"></androidx.constraintlayout.widget.Con

我们来详细解释每一行

<?xml version="1.0" encoding="utf-8"?>表示这个是xml文件使用utf-8编码;

<androidx.constraintlayout.widget.ConstraintLayout 表示使用ConstraintLayout布局

xmlns:android="http://schemas.android.com/apk/res/android声明了 Android 的命名空间,使得在文件中可以使用 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指定了 ConstraintLayout 的宽度和高度分别与父容器的宽度和高度相匹配,填满整个屏幕。

tools:context=".FirstActivity"指定了与这个布局文件相关联的 Activity 类的名称,这在布局预览中很有用。

我们暂时不用ConstraintLayout布局,使用LinearLayout布局,LinearLayout 是一个在垂直或水平方向排列子视图的布局容器。将之前的代码情况,重新修改如下

<?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"android:orientation="vertical"tools:context=".FirstActivity"></LinearLayout>

可以看到添加了一个orientation字段用来表示布局时垂直还是水平,使用垂直布局。

2)添加控件

        之前的布局是空白的,现在往布局里面添加一个按钮控件。

        android:layout_width="match_parent"  //宽度填充到界面最大
        android:layout_height="wrap_content" //高度适应文字大小
        android:id="@+id/btn"                           //控件id,不可重复
        android:text="Button"/>                        //按钮名

<?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"android:orientation="vertical"tools:context=".FirstActivity"><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/btn"android:text="Button"/></LinearLayout>

        现在再添加一个按钮与上一个按钮水平,现在android:layout_width="wrap_content"和android:layout_height="wrap_content"都调到适应文字大小,并且两个按钮都被限制在LinearLayout中使用 android:orientation="horizontal"水平布局。

<?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"android:orientation="vertical"tools:context=".FirstActivity"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/btn"android:text="Button"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/btn2"android:text="Button"/></LinearLayout>
</LinearLayout>

可以看到两个按钮在同一水平线上了,但是感觉怪怪的,我们现在让这两个按钮一个按钮占一行的1/2.

android:layout_width="0dp"                                        //默认值
android:layout_height="wrap_content"                        //高度适应文字大小
android:layout_weight="1"                         //如果一个 LinearLayout 中的多个子视图都设置了 layout_weight 属性,它们会根据各自的权重值来分配剩余空间。权重值越大,分配到的空间就越多。也就是说layout_weight总和假如为2,这个值就表示1/2,占一半的空间。

<?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"android:orientation="vertical"tools:context=".FirstActivity"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><Buttonandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:id="@+id/btn"android:text="Button"/><Buttonandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:id="@+id/btn2"android:text="Button"/></LinearLayout>
</LinearLayout>

 3)在代码使用按钮控件

        现在已经创建好了控件,如何在代码中使用它呢?回到FirstActivity.Java文件中添加如下代码

package com.example.helloworld;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.view.View;
import android.widget.Button;public class FirstActivity extends AppCompatActivity {private Button btn ,btn2;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_first);btn = findViewById(R.id.btn);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {}});btn2 = findViewById(R.id.btn2);btn2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {}});}
}

        在活动中,可以通过 finaViewById()方法获取到在布局文件中定义的元素,这里我们传人R.id.btn,来得到按钮的实例,这个值是刚才在 first_layout.xml 中通过 android:id 属性指定的。findViewById()方法返回的是一个View对象,我们需要向下转型将它转成 Button 对象。得到按钮的实例之后,我们通过调用set0nclickListener()方法为按钮注册一个监听器点击按钮时就会执行监听器中的 onClick()方法。现在我们就可以点击按钮实现某种功能了。

4)Toast在活动中的使用

        Toast是一个在Android中非常方便的一种提醒方式,它可以在屏幕上短暂显示提示信息。

        使用Toast也非常简单,只要使用其中的静态方法makeText获取到Toast的实例,再通过show方法将提示信息显示出来。

package com.example.helloworld;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;public class FirstActivity extends AppCompatActivity {private Button btn ,btn2;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_first);btn = findViewById(R.id.btn);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(FirstActivity.this,"这是第一个按钮",Toast.LENGTH_SHORT).show();}});btn2 = findViewById(R.id.btn2);btn2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(FirstActivity.this,"这是第二个按钮",Toast.LENGTH_SHORT).show();}});}
}

    

 四、使用Intent跳转活动

        从之前学的知识知道只有在<intent-filter>标签内设置为主活动才可以显示界面,那么怎么才能从当前活动跳转到另外一个活动呢?在Android可以使用intent跳转活动。Intent 大致可以分为两种:显式Intent和隐式Intent,我们主要学习一下显式Intent 如何使用。

1)创建SecondActivity

        右键com.example.helloworld新建Activity,不创建layout文件,点击finish完成创建。

2)创建layout文件

         右键layout文件夹,点击XML 新建Layout XML文件

 设置layout详细信息,点击finish完成创建。

layout File Name :Layout 名字

Root Tag :使用布局样式

在activity_second.XML添加一个按钮控件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/btn3"android:text="Button3"/></LinearLayout>

 在SecondActivity中添加

package com.example.helloworld;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;public class SecondActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);Toast.makeText(SecondActivity.this,"这是第二个界面",Toast.LENGTH_SHORT).show();Button btn3 = findViewById(R.id.btn3);btn3.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {}});}
}

3)使用Intent跳转

        回到FirstActivity,在第一个按钮点击事件中添加

package com.example.helloworld;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;public class FirstActivity extends AppCompatActivity {private Button btn ,btn2;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_first);Toast.makeText(FirstActivity.this,"这是第一个界面",Toast.LENGTH_SHORT).show();btn = findViewById(R.id.btn);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(FirstActivity.this,SecondActivity.class);startActivity(intent);}});btn2 = findViewById(R.id.btn2);btn2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {}});}
}

在SecondActivity,在第三个按钮点击事件中添加

package com.example.helloworld;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;public class SecondActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);Toast.makeText(SecondActivity.this,"这是第二个界面",Toast.LENGTH_SHORT).show();Button btn3 = findViewById(R.id.btn3);btn3.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(SecondActivity.this,FirstActivity.class);startActivity(intent);}});}
}

点击运行,在FirstActivity中点击第一个按钮会进入SecondActivit点击SecondActivitS中的按钮会回到FirstSecond。但是这个时候我们会发现,如果点击返回的话,会回到上个活动界面,因为android 默认为栈的方式,每打开一个界面就会将这个活动压入栈中,点击返回时,将会从顶层逐个出栈。

5)使用intent传递信息

        当使用Intent跳转到另外一个活动时,也可以将一些重要信息传递给下个活动。同时广播也可以使用Intent,暂时先了解。

        修改FirstActivity第一个按钮点击事件

  btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(FirstActivity.this,SecondActivity.class);intent.putExtra("House",1);intent.putExtra("Name","Ryan");startActivity(intent);}});

        修改SecondActivity

package com.example.helloworld;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;public class SecondActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);Toast.makeText(SecondActivity.this,"这是第二个界面",Toast.LENGTH_SHORT).show();Intent intent = getIntent();int house = intent.getIntExtra("House",-1);Log.d("Test", String.valueOf(house));String str = intent.getStringExtra("Name");Log.d("Test", str);Button btn3 = findViewById(R.id.btn3);btn3.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(SecondActivity.this,FirstActivity.class);startActivity(intent);finish();}});}
}

可以在日志看到成功将信息传递给下一个活动了

五、活动的生命周期

1)活动状态

  每个活动在它的生命周期将会有四个状态

        1.运行状态

        当活动在栈顶的时候,对用户可见时,为运行状态

        2.暂停状态

        当活动不在处于栈顶时,但是仍然可见,这个时候为暂停状态,一般来说,系统不会回收这种状态的活动,

        3.停止状态

        当活动不可见时,就处于停止状态,这个时候如果内存不够的话,系统很有可能回收。

        4.销毁状态

        当活动从栈内出栈的时候,活动就为销毁状态。

2)活动的生命周期

        Android中回调了七个方法,包含了活动的创建到销毁的生命周期

        1.onCreate:活动第一次被创建时调用,在这里可以实现一些初始化操作;

        2.onStart:活动由不可见到可见时调用。

        3.onResum: 活动和用户交互的时候调用,此时活动处于栈顶。

        4.onPause:活动将要启动另外一个活动时调用,在这个函数里面不能进行耗时操作。

        5.onStop:活动由可见到不可见时调用,注意如果是启动一个对话框式,那么onStop不会调用,只会调用onPause;

        6.onDeatroy: 活动被销毁之前调用,并且之后的状态改为销毁状态;

        7.onRestart:活动在停止状态到运行状态之前调用。

        简单来说就是下面三类

        完整生存期:onCreate到onDestroy

        可见生存期:onResum到onPause

        前台生存期:onStart到onStop

3)体验活动的生命周期

        重新创建LifeCycle工程,点击右上角file,新建工程,命名为LifeCycle,具体步骤参考上面。 

        1.创建活动

        在activity_main.xml中添加一个Button一个TextView,这两个控件的操作很相同。宽度都是match_parent表示填充满所占空间。android:layout_height,android:layout_weight,设置高度占比。android:text设置文本。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="10"android:gravity="center"android:text="主界面"/><Buttonandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:id="@+id/btn_1"android:text="打开对话框"/></LinearLayout>

        接下来我们在com.example.lifecycle包上右键添加一个活动,活动名为DialogActivity,点击finish完成创建。

        在activity_dialog.xml也添加一个按钮和一个TextView,并采用LinearLayout布局。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:text="对话框"/><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/btn_2"android:text="关闭"/></LinearLayout>

        接下来完善主活动和对话框活动的代码,在主活动中我将所有的生命周期都写了出来,在活动进入某个时期时将会回调这个对应的函数。

MainActivity.java

package com.example.lifecycle;import androidx.appcompat.app.AppCompatActivity;import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;public class MainActivity extends AppCompatActivity {private static final String TAG = "LifeCycleLog";private Context mContext;private Button btn_1;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Log.d(TAG, "onCreate: ");mContext = getApplicationContext();btn_1 = findViewById(R.id.btn_1);btn_1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent  = new Intent(MainActivity.this,DialogActivity.class);startActivity(intent);}});}@Overrideprotected void onStart() {super.onStart();Log.d(TAG, "onStart: ");}@Overrideprotected void onResume() {super.onResume();Log.d(TAG, "onResume: ");}@Overrideprotected void onStop() {super.onStop();Log.d(TAG, "onStop: ");}@Overrideprotected void onPause() {super.onPause();Log.d(TAG, "onPause: ");}@Overrideprotected void onRestart(){super.onRestart();Log.d(TAG, "onRestart: ");}@Overrideprotected void onDestroy() {super.onDestroy();Log.d(TAG, "onDestroy: ");}
}

DialogActivity.java

package com.example.lifecycle;import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;public class DialogActivity extends AppCompatActivity {private  Button btn_2;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_dailog);btn_2 = findViewById(R.id.btn_2);btn_2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {finish();}});}
}

         最重要的一点修改Androidmanifests.xml将对话框活动下添加一句,如不添加这一句,将不显示对话框,显示为完整的活动。

        <activityandroid:name=".DialogActivity"android:theme="@style/Theme.AppCompat.Dialog"/>

        2.运行效果

        现在我们运行程序查看效果,刚点击运行时程序出现主界面时效果如下,

        再点击按钮打开对话框,此时运行效果如下,可以看到当对话框弹出来的时候,活动进入了onPause阶段,此时活动未停止,不进入onStop,若直接打开一个活动完全覆盖主上一个活动则会进入onStop。

        点击对话框的关闭,效果如下,并没有进入onStart.

        现在点击home键,效果如下,界面完全看不到了,活动为停止状态         返回app,效果如下,活动重新启动,活动onResume交互状态

        最后,点击返回键,查看效果,点击返回键相当于finish().

 六、活动的启动模式

        之前我们提到的返回栈的概念就是处于标准模式下,活动出栈入栈的方式。活动总共有四种启动模式:standard,singleTop,singleTask,singleInstance。

1)standard模式

        创建新项目ActivityMode,在activity_main.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=".MainActivity"><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/btn"android:text="btn"/></LinearLayout>

        在主活动中完善按钮点击事件,实现方式很奇怪,在点击按钮打开自身,我们先不谈这些,主要着重于standard模式。

package com.example.activitymode;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Log.d("standard", "onCreate: ");Button btn = findViewById(R.id.btn);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(MainActivity.this,MainActivity.class);startActivity(intent);}});}
}

      现在我们点击运行,再按按钮四次,可以看到如下现象,可以看到onCreate被调用了四次,而且并没有调用onDestroy,所有创建四个实例,现在点击返回按钮,需要一个活动出栈,即需要点击四次才能退出程序。

 

2)singleTop模式

        standard模式下有时候挺让人想不明白,一个活动处于栈顶,为什么返回这个活动还要在创建一个实例呢,能不能让已经处于栈顶时的活动直接打开呢,这就要用到第二种模式singleTop模式了

        继续在ActivityMode项目下修改,在Androidmanifests.xml文件下添加singleTop

         <activityandroid:name=".MainActivity"android:launchMode="singleTop"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity>

        现在运行发现无论点多少次也只会创建一个实例。 但是这个模式下,如果活动未处于栈顶启动该活动的话,仍然会创建一个实例。

3)singleTask模式 

        singleTop解决了重复创建栈顶的问题,但是活动不在栈顶还是会创建实例。使用singleTask就会很好的解决这些问题。

        仍然在ActivityMode项目下,再添加一个SecondActivity活动。

activity_second.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=".MainActivity"><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/btn2"android:text="btn2"/></LinearLayout>

SecondActivity.java

package com.example.activitymode;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;public class SecondActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);Log.d("singleTask", "onCreate: ");Button button = findViewById(R.id.btn2);button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent i = new Intent(SecondActivity.this,MainActivity.class);startActivity(i);}});}@Overrideprotected  void onDestroy(){super.onDestroy();Log.d("singleTask", "onDestroy: ");}
}

        修改MainActivity.java

package com.example.activitymode;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Log.d("singleTask", "onCreate:");Button btn = findViewById(R.id.btn);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(MainActivity.this,SecondActivity.class);startActivity(intent);}});}@Overrideprotected  void onDestroy(){super.onDestroy();Log.d("singleTask", "onDestroy: ");}
}

        最后在Androidmanifests.xml修改为singleTask      

         <activityandroid:name=".MainActivity"android:exported="true"android:launchMode="singleTask"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity>

          现在运行查看现象,可以看到即使不处于栈顶,当返回时也不会再创建新的实例。

4)singleInstance模式

        singleInstance模式简单来说,使用了singleInstance模式的活动是存在于一个独立的返回栈中,

        在ActivityMode项目中添加ThirdActivity活动不需要做什么操作,然后修改SecondActivity活动,点击按钮进入ThirdActivity活动

package com.example.activitymode;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;public class SecondActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);Log.d("singleInstance:", "SecondActivity:"+String.valueOf(getTaskId()));Button button = findViewById(R.id.btn2);button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent i = new Intent(SecondActivity.this,ThirdActivity.class);startActivity(i);}});}@Overrideprotected  void onDestroy(){super.onDestroy();Log.d("singleInstance", "SecondActivity_onDestroy: ");}
}

        修改MainActivity,在onCreate中打印当前的返回栈Id

package com.example.activitymode;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Log.d("singleInstance", "MainActivity:"+String.valueOf(getTaskId()));Button btn = findViewById(R.id.btn);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(MainActivity.this,SecondActivity.class);startActivity(intent);}});}@Overrideprotected  void onDestroy(){super.onDestroy();Log.d("singleInstance", "onDestroy: ");}
}

        修改Androidmanifests.xml文件,在SecondActivity中添加singleInstance模式

        <activityandroid:name=".ThirdActivity"android:exported="false" /><activityandroid:name=".SecondActivity"android:launchMode="singleInstance"android:exported="false" /><activityandroid:name=".MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity>

        现在运行,在MainActivity活动中点击按钮进入SecondActivity,在SecondActivity点击按钮进入ThirdActivity活动,可以在日志如下日志,发现被我们折了singleInstance模式的SecondActivity模式是单独的返回栈Id

        到ThirdActivity活动中,点击系统返回键,发现直接进入了MainActivity活动,再带年纪返回键,又会跑到SecondActivity活动中,在SecondActivity活动中点击返回才可以完全退出程序。因为MainActivity和ThirdActivity处于同一返回栈,当从ThirdActivity返回时,这单独的栈内没有其他的活动,就会从另一返回栈找到栈顶活动返回,此时MainActivity处于栈顶,进而当MainActivity点击返回时,从当前返回栈找到SecondActivity活动,最后再在SecondActivity点击返回键全部活动都出栈,退出程序。

七、小结

        在Android应用开发中,活动(Activity)是至关重要的组件,它负责管理用户界面的呈现和用户与应用程序之间的交互。通过活动,可以创建应用程序的各种界面,包括主屏幕、设置界面、登录界面等,并实现用户与这些界面的交互行为,比如点击按钮、输入文本等。此外,活动还管理着应用程序的生命周期,即从创建到销毁的整个过程中的各个状态变化,开发者可以在不同的生命周期方法中执行相应的操作,例如初始化资源、保存数据、更新UI等。通过返回栈的管理,可以在不同的活动之间进行导航和切换,从而构建出流畅的应用程序导航体验。活动还可以与其他组件进行交互,如通过启动服务来执行后台任务,通过注册广播接收器接收系统事件等。所有,活动的学习与掌握至关重要。

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

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

相关文章

上传文件至linux服务器失败

目录 前言异常排查使用df -h命令查看磁盘使用情况使用du -h --max-depth1命令查找占用空间最大的文件夹 原因解决补充&#xff1a;删除文件后&#xff0c;磁盘空间无法得到释放 前言 使用XFTP工具上传文件至CentOS服务器失败 异常 排查 使用df -h命令查看磁盘使用情况 发现磁盘…

运维开发工程师教程之MongoDB单机版设置

MongoDB单机版设置 一、创建虚拟机 在VMware Workstation软件中新建一个虚拟机&#xff0c;具体操作步骤如下&#xff1a; ①运行VMware Workstation软件&#xff0c;进入到主界面&#xff0c;单击“创建新的虚拟机”来创建新的虚拟机&#xff0c;如图3-1所示。 图3-1 VMware…

springboot3项目练习详细步骤(第二部分:文章分类模块)

新增文章分类 接口文档 业务实现 参数校验 文章分类列表 接口文档 业务实现 获取文章分类详情 接口文档 业务实现 更新文章分类 接口文档 业务实现 分组校验 问题 概念 实现步骤 总结 删除文章分类 接口文档 业务实现 该模块大部分请求的路径相同&…

使用idea管理docker

写在前面 其实idea也提供了docker的管理功能&#xff0c;比如查看容器列表&#xff0c;启动容器&#xff0c;停止容器等&#xff0c;本文来看下如何管理本地的docker daemon和远程的dockers daemon。 1&#xff1a;管理本地 双击shift&#xff0c;录入service&#xff1a; …

电脑设置在哪里打开?Window与Mac双系统操作指南

随着科技的不断发展&#xff0c;电脑已经成为我们日常生活和工作中不可或缺的一部分。然而&#xff0c;对于许多初学者来说&#xff0c;如何找到并熟悉电脑的设置界面可能是一个挑战。特别是对于那些同时使用Windows和Mac双系统的用户来说&#xff0c;更是需要一篇详尽的指南来…

SSL证书选择免费还是付费 ?

目前在市场上既有免费的ssl证书&#xff0c;也有付费的ssl证书&#xff0c;那到底如何选择呢&#xff1f;下面我们来看看二者的区别 1验证级别不同 免费ssl证书通常只提供的是域名验证&#xff08;DV&#xff09;证书&#xff0c;仅验证域名的所有权&#xff0c;不涉及组织身…

vue2 webpack-dev-server Unknown promise rejection reason

在vue.config.js中添加如下配置&#xff0c;重启项目即可 module.exports defineConfig({devServer: {client: {overlay: false,},} })参考

Java实现手机短信验证码(互亿无线)

互亿无线 互亿无线是一家提供电信类增值服务插件以及其他相关插件的公司&#xff0c;是中国移动、中国联通、中国电信三大运营商的战略合作伙伴与工信部认定的电信增值业务服务商。公司旗下运营三大业务平台&#xff1a;数字奖励营销活动平台、应用短信平台、营销短信平台。 官…

IJCAI 2024:吉林大学、中国科学院计算技术研究所和自动化研究所等揭示数据增强在开放场景下的“两面性”

吉林大学人工智能学院研究员高一星、中国科学院计算技术研究所副研究员唐帆、中国科学院自动化研究所研究员董未名等在人工智能领域的CCF-A类顶级国际会议IJCAI上发表的工作&#xff0c;揭示并分析基于样本混合的数据增强方法在开放场景下存在的问题&#xff0c;提出了基于非对…

vue实现点击选中以下内容按钮选中按钮位置以下的所有数据项

1、预期效果 该需求的由来&#xff0c;是公司的产品为了实现如飞书这款应用中&#xff0c;IM聊天界面多选消息时一个快捷选择消息的操作功能。 2、实现思路 1. 使选择按钮悬浮在列表试图上方&#xff1b; 2. 在鼠标按下按钮时在其样式添加 pointer-events: none 使鼠标点击…

揭秘马斯克的日常:凌晨3点睡,每天苦恼开哪辆车,曾一度每周工作120小时 | 最新快讯

作为特斯拉和 SpaceX 的首席执行官&#xff0c;同时也是社交媒体平台X&#xff08;前身为推特&#xff09;的拥有者&#xff0c;埃隆马斯克以其在科技和商业领域的杰出成就而闻名。他的成功与其独特而苛刻的日常生活习惯密切相关。 上班前必须先洗澡 通勤时苦恼开哪辆特斯拉 据…

某大型文旅集团车辆维修公司薪酬绩效改革项目纪实 图片附件

---如何通过绩效薪酬改革&#xff0c;帮助公司降本增效 文旅行业“旺丁不旺财”&#xff1f;学会这样激励人才&#xff01;“五一”假期出游继续呈现火爆态势&#xff0c;但也出现了一些“旺丁不旺财”“增收不增利”的现象。文旅行业最重要的还是人力因素&#xff0c;靠人去做…

GPS与精致农业 无人机应用 农业遥感 农业类

全球定位系统是美国国防部主要为满足军事部门对海上、陆地和空中设施进行高精度导航和定位的要求而建立的。GPS系统最基本的特点是以“多星、高轨、高频、测量-测距”为体制&#xff0c;以高精度的原子钟为核心。GPS作为新一代卫星导航与定位系统&#xff0c;不仅具有全球性、全…

AF594-标记羊抗鼠免疫球蛋白(H+L),山羊抗小鼠IgG全长抗体已被交叉吸附在抗人IgG和人血清上,然后再偶联以小化交叉反应性

试剂介绍&#xff1a; AF594-标记羊抗鼠免疫球蛋白(HL)是荧光标记二抗&#xff0c;我们的山羊抗小鼠IgG全长抗体已被交叉吸附在抗人IgG和人血清上&#xff0c;然后再偶联以小化交叉反应性。 这种AF594标记的山羊抗小鼠IgG缀合物通过交叉吸附的山羊抗小鼠IgG全抗体与AF594 NHS酯…

python-scrapy框架示例

参考&#xff1a;https://blog.csdn.net/qq_44907926/article/details/119531324 创建项目步骤&#xff1a; 1.目标网站:www.itcast.cn 2.安装虚拟环境 pip install virtualenv3.创建虚拟环境 virtualenv --always-copy --system-site-packages venv4.激活虚拟环境 venv\sc…

便捷的驾驶证识别API,简化工作流程

随着社会的发展和人们生活水平的提高&#xff0c;机动车的数量也越来越多。为了确保交通安全和减少违法行为&#xff0c;每个驾驶机动车的人都需要携带驾驶证。然而&#xff0c;识别驾驶证上的信息却是一个繁琐的过程。为了简化这个工作流程&#xff0c;提高工作效率&#xff0…

信创基础软件之数据库

一、数据库概述 数据库是一种用于存储和管理拥有固定格式和结构数据的仓库型数据管理系统。其主要用于业务数据的存储和业务逻辑运算&#xff0c;具体负责保障数据的安全性、完整性、多用户对数据的并发使用以及发生故障后的系统恢复。 二、数据库的体系架构 数据库内核:对数…

这份攻防图谱,哪个搞安全的见了会不想要?(附下载)

近年来&#xff0c;随着我国信息化建设不断推进&#xff0c;信息技术广泛应用&#xff0c;信息网络快速普及。信息网络在促进经济发展、社会进步、科技创新的同时&#xff0c;也带来十分突出的信息安全问题。 现今的网络攻击手段逐步多样化、攻击方式也更加隐蔽难以发现。对于…

信息安全-古典密码学简介

目录 C. D. Shannon: 一、置换密码 二、单表代替密码 ① 加法密码 ② 乘法密码 ③密钥词组代替密码 三、多表代替密码 代数密码 四、古典密码的穷举分析 1、单表代替密码分析 五、古典密码的统计分析 1、密钥词组单表代替密码的统计分析 2、英语的统计规…

WebSocket 全面解析+实战演练(Nodejs实现简易聊天室)

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 &#x1f31f; 引言&#x1f4da; WebSocket基础概念&#x1f4cc; 什么是WebSocket&#xff1f;&#x1f4cc; 为什么需要WebSocket&#xff1f;&#x1f4cc; 与HTTP的关系 &#x1f4bb; WebSocket API 使用指南&#x1…