IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android开发(二)—— 活动 -> 正文阅读

[移动开发]Android开发(二)—— 活动

活动

活动定义

活动(Activity)是最吸引用户的地方,它包含用户界面的组件,主要用于和用户进行交互

活动基本用法

创建活动(手动创建)

? 选择新建一个Android项目,将activityName命名,在Java包中会默认创建一个**com.example.**activityName的文件,我们首先选择Add No Activity。

? 此时app/src/main/java/com.example.activityName目录是空的,

在此包中右击选择创建Activity,然后命名活动名称并取消Generate Layout File和Laucher Activity两个选项

  • Generate Layout File会自动为新建的活动创建对应的布局

  • Laucher Activity 会将当前项目活动设置为主活动

注意:任何的活动都需要重写Activity的onCreate()方法,Android Studio会帮我们自动完成这个方法,打开Activity.java如下:

public class FirstActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {//onCreate()方法已经被重写
        super.onCreate(savedInstanceState);
    }
}

创建加载布局

? Android程序的设计讲究逻辑与视图分离,最好每一个活动都能对应一个布局,布局就是用来显示界面内容的,因此我们现在就来手动创建一个布局文件。

? 右击app/src/main/res目录 -> New -> Directory, 会弹出一个新的目录窗口,在这里先创建一个名为layout的目录。然后对着layout目录右键 -> New -> Layout resource file,又会弹出一个新建布局资源文件的窗口,我们将这个布局文件命名为first_layout,根元素就默认为LinearLayout

? 创建后的效果如下:

在这里插入图片描述

布局编辑有三种方式:code 、 split 、design,上面这一种为design模式,切换为code代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
</LinearLayout>

布局中的控件我们都会放在这个布局文件中,下面是放入button的样例:

代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button 1"
        ></Button>
</LinearLayout>

效果:

在这里插入图片描述

应该注意到,Button元素内部增加了多个属性:

android:id是元素的唯一标志符

android:layout_width指定了当前的元素的宽度,march_parent表示当前元素与父元素一样的宽

android:layout_height指定了当前元素的高度,warp_content表示当前元素刚好可以包含里面的内容。

android:text指定了元素中显示的文字内容。

? 接下来最重要的就是在活动中加载这个布局:

重新回到FirstActivity,在onCreate()方法中加入如下的代码:

package com.example.activitytest;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class FirstActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.first_layout);
    }
}

这里用setContentView()方法来给当前的活动加载一个布局,而在setContentView()方法中,我们一般都会传入一个布局文件id,只需要调用R.layout.first_layout就可以得到first_layout.xml布局的id,将这个值传入setContentView()方法中即可。

在AndroidMainifest文件中注册

? 上一章中说到,所有的活动都要在AndroidMainifest.xml中注册才能生效,而实际上FirstActicity已经在AndroidMainifest.xml中注册过了,我们打开app/src/main/AndroidMainfest.xml就可以发现,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.activitytest">

    <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.ActivityTest">
        <activity
            android:name=".FirstActivity"
            android:exported="true" />
    </application>

</manifest>

? 活动申明是要放在<application>标签内的,这里通过<activity>标签来对活动进行注册的,可以发现是注册好的——这里要感谢android stduio对活动进行自动的注册。

? 这里的<activity>标签我们使用了android:name来指定具体的活动,这里的.firstActivity其实是com.example.activitytest.FirstActivity的缩写,因为在最外层的<mainfest>标签中已经通过package属性指定了程序的包名com.example.activitytest,因此注册部分可以省略。

? 不过仅是注册了活动,我们的程序还是不能运行的,因为还没有配置主活动,也就是说,当程序运行起来的时候,不知道要先启动哪个活动,所以需要配置主活动,步骤如下:

  • 在<activity>内部加入<intent-filter>标签,并在标签中加入<action android:name=“android.intent.action.MAIN”/>和<category android:name=“android.intent.category.LAUNCHER”>两句申明即可。

  • 还可以用android:label指定活动中标题栏的内容,标题栏是显示在活动最顶部的,注意的是,活动指定的label不仅会成为标题栏中的内容,还会成为启动器(Laucher)中的应用程序显示的名称

修改后的AndroidMainifest.xml文件代码如下所示:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.activitytest">

    <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.ActivityTest">
        <activity
            android:name=".FirstActivity"
            android:label="This is FirstActivity"
            android:exported="true" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

? 这样的话,FirstActivity就成为我们的程序主活动了,点击应用程序图标打开就是这个活动。

注意:如果没有申明主程序的话,app依然可以下载安装,但是无法正常看到这个活动或者打开这个活动,这种活动可以做第三方服务供其他应用在内部进行调用的,如支付宝快捷支付服务

运行程序结果如下:

在这里插入图片描述

成功掌握了手动创建活动的方法

在活动中使用Toast

? Toast是Android系统提供的一种非常好的提醒方式,在一些短小的信息通知给用户,这些消息在一段时间后会自动消失,并且不会占用任何屏幕空间

? 首先需要定义Toast出现的触发点,我们就利用前面这个按钮来弹出一个Toast。在OnCreate()方法中添加如下代码:

protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.first_layout);
        Button button1 = (Button) findViewById(R.id.button_1);
        button1.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Toast.makeText(FirstActivity.this,"You Click Button1",Toast.LENGTH_SHORT).show();
            }
        });

? 在活动中,通过findViewById()方法获取布局顶定义的元素,这里传入之前确定的R.id.button_1来指定按钮的实例。findViewId()方法返回的是View对象,我们需要向下转型成为Button对象。通过调用setOnClickListener()方法为按钮注册一个监听器,点击按钮的时候会执行监听器中的onclick()方法

? Toast使用方法,通过静态makeText()创建出一个Toast对象,然后调用show()将Toast显示出来即可。注意这里的makeText()需要传入三个参数,第一个参数是Context,也就是Toast的上下文,由于活动本身就是一个Context对象,直接传入FirstActivity.this即可,第二个参数是Toast显示的文本内容,第三个参数是Toast显示的时长,有两个内置常量可以选择Toast.LENGTH_SHORT和Toast.LENGTH.LONG

? 重新运行程序的结果如下:

在这里插入图片描述

活动中使用Menu

? 手机不同于电脑,屏幕的使用空间非常的有限,如果将含有大量内容的菜单显示,界面的设计就会比较的尴尬,这里提供了一种方式,在菜单显示的同时,也不会占用大量的屏幕空间——Menu

? 首先在res目录下新建一个menu文件夹,右击res -> New -> Directory,输入文件名menu,再在这个文件夹下新建main的菜单文件,右击menu -> New -> Menu resource file,文件命名为main,在main.xml菜单文件下添加如下代码:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/add_item"
        android:title="Add" />

    <item
        android:id="@+id/remove_item"
        android:title="Remove"/>
</menu>

在这里创建了两个菜单选项,其中<item>标签是用来创建具体的摸一个菜单选项,然后通过android:id给这个菜单项指定唯一的标识符,通过android:title给菜单命名名称

? 接着回到FirstActivity中重写onCreateOptionMenu()方法,重写快捷键Ctrl+O(Mac系统是control+O)

? 在onCreateOptionsMenu()方法中编写如下代码:

 @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main,menu);
        return true;
    }

? 通过getMenuInflater()方法能够得到MenuInflater对象,再调用它的infalte()方法就可以给当前活动创建菜单了。infalter()方法接收两个参数,第一个参数用于指定哪一个资源文件来创建菜单,第二个参数用来指定我们的菜单项将添加到哪一个Menu对象中,这里直接用onCreateOptionsMenu()方法中传入menu参数。然后给这个方法返回true,表示菜单允许显现出来。

? 显现菜单是远远不够的,菜单的作用不仅是看,还要用来使用,因此还要定义菜单的响应事件。在FirstAcitivty中重写onOptionsItemSelected()方法:

@Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()){
            case R.id.add_item:
                Toast.makeText(this,"you clicked Add",Toast.LENGTH_SHORT).show();
            case R.id.remove_item:
                Toast.makeText(this, "you clicked remove", Toast.LENGTH_SHORT).show();
                break;
            default:
        }
        return true;
    }

? 在onOptionsItemSelected()方法中,通过调用item.getItemId()来判断我们点击的是哪一个菜单项,然后给每个菜单项加入自己的逻辑处理,这里就活学活用加入Toast来显示效果。

? 效果如下:

在这里插入图片描述

在这里插入图片描述

销毁一个活动

销毁一个活动很简单,只需要按下返回键就可以了。如果不希望使用返回键销毁活动的话,Activity提供了一个finish()方法,活动中调用这个方法即可销毁活动

代码如下:

button1.setOnClickListener(new View.OnClickListener(){//位置位于FirstActivity.java/onCreate()/onClick()
            @Override
            public void onClick(View v){
                finish();
                //Toast.makeText(FirstActivity.this,"You Click Button1",Toast.LENGTH_SHORT).show();
            }
        });
}

使用Intent在活动之间穿梭

如何才能从主活动跳入到其他的活动去呢

使用显式Intent

? 右击com.example.activitytest包 -> New -> Activity -> Empty Activity,会弹出一个创建活动的对话框,我们将活动命名为SecondActivity ,勾选Generate Layout File,给布局文件起名为second_layout,但是不要勾选Launcher Activity选项。

? 依然使用LinearLayout 编辑second_layout.xml,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button_2"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:text="Button 2"
        />

</LinearLayout>

定义一个按钮Button 2,同时在SecondActivity中代码已经生成了一部分,暂时保持默认

最后在AndroidMainifest.xml中注册,不过Android Stduio已经帮我们自动完成了

<activity
            android:name=".SecondActivity"
            android:exported="true" />

新概念Intent

? Intent是Android程序中各组件之间进行交互的一种重要方式,不仅可以指明当前组件想要的动作,还能在不同组件之间传递数据。

? Intent一般可以用在启动活动、启动服务以及发送广播等场景,我们的先来实现启动活动。

? Intent分为两种:显式Intent和隐式Intent

使用显式Intent

? Intent有多个构造函数的重载,其中一个是Intent(Context packageContext , Class<?>cls)。这个构造函数两个参数Context要求提供活动的上下文,第二个参数Class则是指定想要启动的目标活动,通过这个构造函数可以构建出Intent的"意图"。

? 可是我们怎么才能使用Intent呢?Activity类提供了一个startActivity()方法,这个方法是专门用于启动活动的,它接收一个Intent参数,这里我们将构建好的Intent传入startActivity()方法就可以启动目标活动了。

? 修改FirstActivity中的按钮事件,代码如下:

public void onClick(View v){
                Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
                startActivity(intent);
                //finish();
                //Toast.makeText(FirstActivity.this,"You Click Button1",Toast.LENGTH_SHORT).show();
            }

重新运行程序,点击FirstActivity界面的按钮,效果如下:

在这里插入图片描述

由于用这样的方式启动Intent,意图十分明显,因此将这种方式称为显式Intent

使用隐式Intent

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

? 在SecondActivity的<activity>中配置<intent-filter>,可以指定当前活动能够响应的action和category,代码如下:

<activity
	android:name=".SecondActivity"
	android:exported="true" >
	<intent-filter>
		<action android:name="com.example.activitytest.ACTION_START" />
		<category android:name="android.intent.category.DEFAULT" />
	</intent-filter>
</activity>

? 在<action>标签中我们指定了活动可以响应com.example.activitytest.ACTION_START

这个action,而<category>标签则包含了附加信息,更加精确的指明了当前活动能够响应的Intent中还能带有category。只有<action>和<category>中的内容同时能够匹配环境中指定的action和category时,这个活动才能响应这个Intent。

? 修改FirstActivity中的按钮点击事件,代码如下所示:

Wpublic void onClick(View v){
                Intent intent = new Intent("com.example.activitytest.ACTION_START");
                startActivity(intent);
}

? 可以发现,我们使用了Intent的另一个构造函数,直接将action的字符串了进去,表明我们想要启动能够响应com.example.activitytest.ACTION_START这个action活动。而这里指定的category是利用android.intent.category.DEFAULT这种默认的,在调用startActivity()方法时会将这个category添加到intent中。

? 重新运行程序结果依然是成功的,说明配置的action和category已经生效了.

注意:一个Intent只能指定一个action,但是可以指定多个category

更多的隐式Intent的用法

? 隐式还有许多内容了解,使用隐式,我们不仅可以启动自己程序内的活动,还可以启动其他程序的活动,这使得Android多个应用程序之间的功能共享成为了可能,比如直接调用浏览器来打开网页

? 修改FirstActivity的按钮点击事件的代码:

public void onClick(View v){
                Intent intent = new Intent(Intent.ACTION_VIEW);
                intent.setData(Uri.parse("http://www.baidu.com"));
                startActivity(intent);
}

在上述代码中,setData是比较陌生的一部分,这里主要是数据传递,同时我们还可以在<intent-filter>标签中再配置一个<data>标签,用于更精确的指定活动能够响应什么类型的数据。<data>标签中主要有以下内容:

  • android:scheme 用于指定协议
  • android:host 用于指定主机
  • android:port 用于指定端口
  • android:path 用于指定域名
  • android:mimeType 用于指定可以处理的数据类型

向下一个活动传递数据

? Intent还可以在启动活动的时候传递数据。在启动活动的时候传递数据的思路很简单,Intent中提供了一系列putExtra()方法的重载,可以把我们想要传递的数据暂时存在Intent中,启动了另一个活动后,只需要把这些数据再从Intent中取出即可。

? 如:我们将FirstActivity中的一个字符串传入SecondActivity中,在FirstActivity中:

public void onClick(View v){
                String data = "Hello World";
                Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
                intent.putExtra("extra_data",data);
                startActivity(intent);
}

这里依然选择显式Intent方式来启动SecondActivity,并通过putExtra()方法传递了一个字符串。注意这里的putExtra()方法接收两个参数,第一个参数是键,用于后面从Intent中取值,第二个参数才是真正想要传递的数据

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.second_layout);
        Intent intent = getIntent();
        String data = intent.getStringExtra("extra_data");
        Log.d("SecondActivity",data);
    }

在按下按钮后可以在logcat中找到我们打印的数据

2022-07-30 16:23:00.366 13583-13583/com.example.activitytest D/SecondActivity: Hello World

返回数据给上一个活动

? 既然可以给下一个活动传递数据,那么给上一个活动传递数据也是理算当然的。不过不同的是给上一个活动传递时只需要按下back键即可,并没有可以传递数据的Intent。在Activity中有一个startActivityForResult()方法也是用于启动活动的,并且可以在活动销毁的时候返回一个结果给上一个活动。

? 修改FirstActivity中的按钮点击事件,代码如下:

Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
startActivityForResult(intent,1);

? 这里用startActivityForResult()方法启动SecondActivity,两个参数第一个时intent,而第二个是请求码(只要是唯一值即可),接下来在SecondActivity中加入按钮点击事件,代码如下:

Button button2 = (Button) findViewById(R.id.button_2);
button2.setOnClickListener(new View.OnClickListener(){
	@Override
	public void onClick(View v) {
		Intent intent = new Intent();
		intent.putExtra("data_return","hello world again");
		setResult(RESULT_OK,intent);
		finish();
	}
});

? 由于是使用startActivityForResult()方法来启动SecondActivity的,在SecondActivity被销毁后会回调上一个活动的onActivityResult方法,因此我们需要在FirstActivity中重写这个方法来得到返回的数据:

2022-07-30 17:46:39.207 15449-15449/com.example.activitytest D/Third: hello world again

? onActivityForResult()方法带三个参数,第一个参数requestCode,在我们启动时传入请求码,第二个参数resultCode,即我们在返回数据时的处理结果,第三个参数data,即带着返回数据的Intent。

? 由于在活动中可能有调用startActivityForResult()方法启动很多不同的活动,每一个活动返回的数据都会回调到onActivityResult()这个方法中,因此我们首先要做的就是通过检查requestCode来确定数据来源,然后通过resultCode来确定数据处理是否成功,最后将data数据打印出来。

? 这里有一点问题,如果不是按下按钮而是直接按下back键返回那数据不是没法返回了嘛,所以我们还要在SecondActivity中写入onBackPressed()来解决这个问题。代码如下:

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        Intent intent = new Intent();
        intent.putExtra("data_return","hello world again");
        setResult(RESULT_OK,intent);
        finish();
    }

活动的生命周期

? 掌握了活动的生命周期可以帮助我们设计出更加连贯流畅的程序,并在如何合理管理应用资源方面发挥的游刃有余。

返回栈

? Android是使用任务(Task)来管理活动的,一个任务就是存放在一组栈里的活动的集合,这个栈又被称作返回栈。每次启动一个新活动,都会入栈并处于栈顶位置,finish()销毁时,栈顶活动会入栈。

活动状态

? 活动在其生命周期最多会有四个状态。

  1. 运行状态

    当活动位于栈顶时,处于运行状态。系统最不愿意回收运行状态,这会让用户有非常差的体验。

  2. 暂停状态

    当一个活动不在栈顶时但是任然可见时,活动进入了暂停状态。只有在内存极低的情况下,系统才会回收这种活动。

  3. 停止状态

    不在栈顶且完全不可见的时候即为暂停状态。系统仍然会保存活动的变量以及状态,但并不是完全可靠,其他地方需要内存时这种活动就会被回收。

  4. 销毁状态

    从返回栈被移除就是销毁状态。系统倾向于回收这种活动,从而保证手机内存充足。

活动的生存期

Activity中定义了7个回调方法,覆盖生命周期的每一个环节。

  • onCreate()

    每一个活动都要重写的方法,专门用来初始化

  • onStart()

    活动由不可见变可见时使用

  • onResume()

    此活动一定位于栈顶且处于运行状态,在准备与用户交互时调用。

  • onPause()

    这个方法在系统准备启动或者恢复时调用,通常会用来释放CPU资源或者保存关键数据

  • onStop()

    完全不可见时调用

  • onDestory()

    被销毁前调用

  • onRestart()

    活动由停止变为运行状态时调用

以上七种方法又被分为三种生存期

  • 完整生存期
  • 可见生存期
  • 前台生存期

在这里插入图片描述

体验活动的生命周期

?

活动被回收了怎么办

? 当一个活动进入到了停止状态,是有可能被系统回收的。想象如下的场景:

应用程序中有一个活动A,用户在活动A的基础上启动了活动B,活动A就进入了停止状态,这个时候由于系统内存不足,将活动A回收了,然后用户按下back键返回活动A。其实A还是会正常显示,只是这里A活动的创建使用的不是onRestart()方法,而是onCreate()方法,因为这种情况下A活动会被重新创建一次。

? 可是这里就会出现一个问题,如果A活动有临时状态,在使用了onCreate()方法创建的话用户按下back键原来的临时状态就不会存在。如果我们的应用出现了这种情况,有可能会严重的影响用户体验。在Activity中还提供了一个onSaveInstanceState()回调方法,这个方法保证活动在回收之前一定会被调用,因此我们可以通过这个方法来解决数据保存的问题。

? onSaveInstanceState()方法会携带一个Bundle类型的参数,Bundle提供了一系列的方法用于保存数据,比如可以使用putString()方法保存字符串,使用putInt()方法保存数据,第一个参数是键,用于后面的Bundle中取值,第二个参数是真正要保存的内容。

? 在MainActivity中添加如下代码就可以将临时数据进行保存:

    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        String tempData = "Something you just typed";
        outState.putString("data_key",tempData);
    }

? 数据保存下来后,我们一直的onCreate()方法好像其实也有Budle类型的参数。这个参数正常情况下都是null,但是如果在活动被系统回收之前有通过onSaveInstanceState()方法来保存的话,这个参数就会带有之前保存的全部数据,我们只需要再通过相应的取值方法取出即可。

? 修改MainActivity的onCreate()方法,如下所示:

if(savedInstanceState != null){
            String tempData = savedInstanceState.getString("data_key");
            Log.d("Saved",tempData);
        }

? 这里可以使用Budle和Intent结合的方式来实现活动之间的数据传递,首先将数据存入Budle中,再将Budle存入Intent中,在下一个活动中打开。

活动的启动模式

? 启动活动需要恰当的模式,启动模式一共四种,分别是:standard,singleTop,singleTask和singleInstance。可以在AndroidMainifest.xml中通过给<activity>标签指定android:launchMode属性来选择启动模式。

standard

? standard是活动默认的启动模式,在不进行显示指定的情况下,所有活动都会自动启用这种模式。对于standard这种模式系统不会在意这个活动是否在栈中已经存在,每次启动都会创建这个活动的新实例。

singleTop

? standard模式在有些情况下不会很合理,比如明明活动已经在栈顶了,再次启动依然会创建新的活动实例。但是singleTop就不会出现这样的麻烦,当启动活动时发现活动已经在栈顶,则认为可以直接使用它,不会再创建新的活动实例。

? 只需要在AndroidManifest.xml中修改配置代码:

<activity
            android:launchMode="singleTop"\\启动模式设为singleTop
            android:name=".FirstActivity"
            android:exported="true"
            android:label="This is FirstActivity">

singleTask

? singleTop虽然可以很好的解决重复创建栈顶活动的问题,但是如果不在栈顶依然会重复创建,有没有一种模式可以让应用程序的上下文只存在一个实例呢,这就需要singleTask来实现了。

singleInstance

? singleInstance模式是四个启动模式中最特殊也是最复杂的存在了,不同于以上三个模式,该模式活动会启用一个新的返回栈来管理这个活动(其实如果singleTask如果用了不同的taskAffinity,也会启动一个新的返回栈)。

? 假设我们的程序有一个活动允许其他的活动程序调用,怎么才能实现其他程序和我们程序一起调用这个活动呢,因为前三种模式下,每一个程序都有一个自己的返回栈,同一个活动在不同的返回栈中入栈时必然创建了新的实例。而singleInstance可以利用新的返回栈来共享并单独管理这些活动,不管是哪一个程序来访问这个活动都可以共用同一个返回栈。

活动的最佳实践

? 以下是一些关于活动的实践技巧

知晓当前是在哪一个活动

? 在企业开发中有时并不能确定自己正在阅读或者编写的代码是在哪一个界面,这个时候就需要自己来尝试寻找。

? 方法:在主活动中重写onCreate()打印getclass().getsimplename()来打印当前页面,然后将其他所有的活动都从继承自AppCompatActivity改为继承自主活动,这样每次启动活动都会打印活动的名称,因为便于我们清楚界面是哪一个活动了。

随时随地退出程序

? 如果这时你要想返回到手机界面需要按三次back键,而按下home键只是将程序挂起,并没有退出程序。所以需要一个能够随时随地退出程序的方案才行。

? 解决思路需要专门的集合类对所有的活动进行管理

启动活动的最佳写法

? 启动活动的方法我们很熟悉,首先通过构建Intent构建出当前的“意图”,然后调用startActivity()或者startActivityForResult()方法将活动启动起来,如果有数据需要从一个活动传递给另一个活动,也可以借助Intent来完成。

? 假设SecondActivity中有两个非常重要的参数,在启动这个参数之前必须要传递过来,那么代码可以如下:

Intent intent = new Intent(SecondActivity.this,FirstActivity.class);
intent.putExtra("param1","data1");
intent.putExtra("param2","data2");
startActivity(intent);

? 这样的代码是完全正确的,不论是语法上还是规范上,只是在真正的项目开发中会遇到这样的问题:由于SecondActivity并不是你开发的,但是你需要知道secondActivity传递了什么参数,这个时候就一般有两种方法解决这个问题——可以去问写了secondActivity代码的同时或者自己阅读SecondActivity的代码来确定,这样有时会很麻烦甚至尴尬,作为一个优雅的程序猿,这样的作法自然不够优雅。但只要换一种写法,这种窘境就会被打破。

? 修改SecondActivity()代码如下:

public class SecondActivity extends BaseActivity {
    public static void actionStart(Context context,String data1,String data2){
		Intent intent = new Intent(FirstActivity.this,SecongActivity.class);
		intent.putExtra("param1","data1");
		intent.putExtra("param2","data2");
		startActivity(intent);
    }
}

? 我们在这里加入一个actionStart()方法,这个方法完成了Intent的构建,另外所有SecondActivity所有数据都是通过这个方法传过来的,只需要再把数据存入Intent,最后调用startActivity()方法启动SecongActivity即可。

? 好处是什么呢,显然这样可以立马清楚SecondActivity数据都有哪些,而且还能简化代码,现在只需一行代码即可启动SecondActivity(),如下所示:

@Override
public void onClick(View v) {
	SecondActivity.actionStart(FirstActivity.this,"data1","data2");
}

谢谢阅读

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-08-06 10:55:38  更:2022-08-06 11:00:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 4:26:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码