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自动注册的部分,如下

        <activity
            android:name=".FirstActivity"
            android:exported="false" />
        <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>
        </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。

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

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        <activity
            android: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">
    <Button
        android: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">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/btn"
            android:text="Button"/>
        <Button
            android: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">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:id="@+id/btn"
            android:text="Button"/>
        <Button
            android: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;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
        btn = findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                
            }
        });
        btn2 = findViewById(R.id.btn2);
        btn2.setOnClickListener(new View.OnClickListener() {
            @Override
            public 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;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
        btn = findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(FirstActivity.this,"这是第一个按钮",Toast.LENGTH_SHORT).show();
            }
        });
        btn2 = findViewById(R.id.btn2);
        btn2.setOnClickListener(new View.OnClickListener() {
            @Override
            public 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">
    <Button
        android: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 {

    @Override
    protected 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() {
            @Override
            public 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;
    @Override
    protected 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() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
                startActivity(intent);
            }
        });
        btn2 = findViewById(R.id.btn2);
        btn2.setOnClickListener(new View.OnClickListener() {
            @Override
            public 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 {

    @Override
    protected 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() {
            @Override
            public 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() {
            @Override
            public 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 {

    @Override
    protected 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() {
            @Override
            public 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">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="10"
        android:gravity="center"
        android:text="主界面"/>

    <Button
        android: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">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="对话框"/>
    <Button
        android: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;
    @Override
    protected 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() {
            @Override
            public void onClick(View v) {
                Intent intent  = new Intent(MainActivity.this,DialogActivity.class);
                startActivity(intent);
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, "onStart: ");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume: ");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "onStop: ");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause: ");
    }

    @Override
    protected void onRestart()
    {
        super.onRestart();
        Log.d(TAG, "onRestart: ");
    }

    @Override
    protected 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;
    @Override
    protected 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() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
    }
}

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

        <activity
            android: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">

    <Button
        android: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 {

    @Override
    protected 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() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,MainActivity.class);
                startActivity(intent);

            }
        });
    }
}

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

 

2)singleTop模式

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

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

         <activity
            android: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">

    <Button
        android: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 {

    @Override
    protected 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() {
            @Override
            public void onClick(View v) {
                Intent i = new Intent(SecondActivity.this,MainActivity.class);
                startActivity(i);
            }
        });
        
        
    }
    @Override
    protected  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 {

    @Override
    protected 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() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,SecondActivity.class);
                startActivity(intent);

            }
        });
    }
    @Override
    protected  void onDestroy()
    {
        super.onDestroy();
        Log.d("singleTask", "onDestroy: ");
    }
}

        最后在Androidmanifests.xml修改为singleTask      

         <activity
            android: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 {

    @Override
    protected 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() {
            @Override
            public void onClick(View v) {
                Intent i = new Intent(SecondActivity.this,ThirdActivity.class);
                startActivity(i);
            }
        });

    }
    @Override
    protected  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 {

    @Override
    protected 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() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,SecondActivity.class);
                startActivity(intent);

            }
        });
    }
    @Override
    protected  void onDestroy()
    {
        super.onDestroy();
        Log.d("singleInstance", "onDestroy: ");
    }
}

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

        <activity
            android:name=".ThirdActivity"
            android:exported="false" />
        <activity
            android:name=".SecondActivity"
            android:launchMode="singleInstance"
            android:exported="false" />
        <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>
        </activity>

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

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

七、小结

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

  • 19
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值