本文介绍: Activity一个应用组件用户可与其提供的屏幕进行交互,以执行拨打电话、拍摄照片发送电子邮件查看地图操作每个 Activity 都会获得一个用于绘制用户界面窗口窗口通常会充满屏幕,但也可小于屏幕浮动在其他窗口之上。

在这里插入图片描述

Activity一个应用组件用户可与其提供的屏幕进行交互,以执行拨打电话、拍摄照片发送电子邮件查看地图操作每个 Activity 都会获得一个用于绘制用户界面的窗口。窗口通常会充满屏幕,但也可小于屏幕浮动在其他窗口之上。

Activity

1. Activity使用

我们新建工程中带有一个基础 activity

新建工程中,需要注意3个文件

这3个文件分布在不同的地方。简单来说,java文件可以控制界面逻辑layout文件这里指的是activity_main.xml)预设了UI如何摆放。 清单文件告诉系统,我这个app哪些组件申请什么权限

2. layout界面布局

新建layout 中,as 一般会默认一个ConstraintLayout比如 activity_main.xml

activity_main.xml

<?xml version="1.0" encoding="utf-8"?&gt;
<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=".MainActivity"&gt;

    <!-- 省略默认的TextView --&gt;

</androidx.constraintlayout.widget.ConstraintLayout>

这里为了用起来方便,我们把它换成LinearLayout 有的朋友会问,都2021年了,为什么不直接用 ConstraintLayout

现在不做什么功能,先用LinearLayout,就是为了方便。 换成LinearLayout后,layout文件长这样。

换成LinearLayout后的activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <!-- 省略默认的TextView -->

</LinearLayout>

可以看到标签开头和结尾都换成了LinearLayout。其他地方暂时不修改

as功能强大,非常便利。我们可以鼠标选中标签开始的androidx...Layout然后直接键盘输入LinearLayout的前几位字母

as会自动弹出选择框,在里面双击选择LinearLayout或者回车选择标签替换完成了。

3. Java – 控制界面

layout文件设计的是界面的初始布局。它决定了初始界面上放着什么UI组件以及组件是怎么组织安排的。

这里我们说的是「初始界面」或者「初始布局」。也就是说,我们可以控制界面上的UI元素

先看默认的 MainActivity.java。在onCreate方法里,R.layout.activity_main指的就是activity_main.xml

现在layout中有一个TextView,它可以用来显示文字我们想在MainActivity控制它,该怎么做呢?

现在改一下这个TextView。删掉原来ConstraintLayout用到的那些属性

给它添加一个id。这个id在这个layout文件中必须是独一无二的。给它分配一个id叫做tv1,就像下面。

<TextView
    android:id="@+id/tv1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello World!" />

现在TextView有了身份证,我们在activity中就可以找到它。用的是findViewById方法。

TextView tv1 = findViewById(R.id.tv1);

现在我们就拿到了界面上的这个TextView对象。可以对它进行操作了。 比如改变它显示文字

TextView tv1 = findViewById(R.id.tv1); // 拿到textView的对象
tv1.setText("Today is a good day.");   // 改变文字
4. AndroidManifest.xml – 清单文件

也可以简称为「manifest文件」。清单文件非常重要,它告诉系统我们的app有哪些activity,用到什么权限等等信息

如果要新建activity,需要在清单中注册

AndroidManifest.xml

<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/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

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

从这个默认的清单文件中我们可以得知,activity 是属于 application 的。application 就是我们的应用

application 标签中也指定了各种元素,例如应用图标名字主题等等。

MainActivity 是应用启动第一个 activity。可以观察到它设置了 actioncategory 属性

设置了这 2 个标签,决定了这个 activity 是用户点击应用图标时第一个启动的界面。

小结 activity是应用重要的组件之一。纷繁复杂内容需要activity来承载。

之后我们会在activity中控制各种各样的UI组件处理用户的操作,申请权限等等。还要了解activity的生命周期启动方式跳转方法。


Activity 生命周期

生命周期图示

img

1. 生命周期变化

执行一些常见的操作,打log看一下生命周期的变化。测试机型:RedMi。

启动然后退出

onCreate
onStart
onResume
onWindowFocusChanged: hasFocus: true

onWindowFocusChanged: hasFocus: false
onPause
onStop
onDestroy

启动后按home

Act1: onCreate
Act1: onStart
Act1: onResume
Act1: onWindowFocusChanged: hasFocus: true

// 按home
Act1: onWindowFocusChanged: hasFocus: false
Act1: onPause
Act1: onStop

// 再回来
Act1: onRestart
Act1: onStart
Act1: onResume
Act1: onWindowFocusChanged: hasFocus: true

// 按返回退出act
Act1: onWindowFocusChanged: hasFocus: false
Act1: onPause
Act1: onStop
Act1: onDestroy

旋转手机 activity 在切换横竖屏的时候的生命周期。

[Life]: onCreate
[Life]: onStart
[Life]: onResume
[Life]: onWindowFocusChanged: hasFocus: true

// 横屏
[Life]: onPause
[Life]: onStop
[Life]: onDestroy
[Life]: onCreate
[Life]: onStart
[Life]: onResume
[Life]: onWindowFocusChanged: hasFocus: true

// 竖屏
[Life]: onPause
[Life]: onStop
[Life]: onDestroy
[Life]: onCreate
[Life]: onStart
[Life]: onResume
[Life]: onWindowFocusChanged: hasFocus: true

// 返回
[Life]: onWindowFocusChanged: hasFocus: false
[Life]: onPause
[Life]: onStop
[Life]: onDestroy

来回切换的生命周期变化 以2个Activity启动为例

Act1: onCreate
Act1: onStart
Act1: onResume
Act1: onWindowFocusChanged: hasFocus: true
Act1: onPause
Act1: onWindowFocusChanged: hasFocus: false
Act2: onCreate
Act2: onStart
Act2: onResume
Act2: onWindowFocusChanged: hasFocus: true
Act1: onStop
Act2: onWindowFocusChanged: hasFocus: false
Act2: onPause
Act1: onRestart
Act1: onStart
Act1: onResume
Act1: onWindowFocusChanged: hasFocus: true
Act2: onStop
Act2: onDestroy
Act1: onWindowFocusChanged: hasFocus: false
Act1: onPause
Act1: onStop
Act1: onDestroy

弹出 AlertDialog 点击按钮弹出一个AlertDialog。观察发现调用 onWindowFocusChanged

onWindowFocusChanged: hasFocus: false
onWindowFocusChanged: hasFocus: true

这里也可以用 DialogFragment 来做测试

recreate 调用 recreate() 方法

[Life]: onCreate
[Life]: onStart
[Life]: onResume
[Life]: onWindowFocusChanged: hasFocus: true
[Life]: click [recreate]
[Life]: onPause
[Life]: onStop
[Life]: onDestroy
[Life]: onCreate
[Life]: onStart
[Life]: onResume

可以看到,调用recreate()方法后并没有onWindowFocusChanged回调

2. onCreate 和 onStart区别

activity的状态区别

onStart() 方法会非常快速地完成,并且与“已创建状态一样,Activity 不会一直处于“已开始”状态。一旦此回调结束,Activity 便会进入恢复状态系统将调用 onResume() 方法。

3. onPause 和 onStop区别

onPause() 执行非常简单,而且不一定要有足够的时间来执行保存操作。 因此,您不应使用 onPause()保存应用或用户数据、进行网络调用,或执行数据库事务。因为在该方法完成之前,此类工作可能无法完成。

进入已停止状态,因此系统将调用 onStop() 回调。举例而言,如果新启动的 Activity 覆盖整个屏幕,就可能会发生这种情况。

onStop() 方法中,应用应释放或调整应用对用户不可见时的无用资源例如,应用可以暂停动画效果,或从细粒度位置更新切换到粗粒度位置更新使用 onStop() 而非 onPause() 可确保与界面相关工作继续进行,即使用户在多窗口模式查看您的 Activity 也能如此。 您还应该使用 onStop() 执行 CPU 相对密集的关闭操作。


Activity 启动,携带参数启动

前面大致了解了Activity是一个应用组件,能为用户提供一个界面。以及如何新增activity。 一个App中,通常有多个界面。假设每一个界面对应一个activity,不同界面之间怎么跳转呢?

1. Intent

通常activity之间的跳转离不开Intent这个类。 Intent,直译为“意图”。我们把信息包裹在intent对象中,然后执行。 比如启动RelativeLayoutGuideAct这个activity。

startActivity(new Intent(getApplicationContext(), RelativeLayoutGuideAct.class));

这里用到一个很常见的方法startActivity (Intent intent)startActivity属于Context类,Activity是Context子类

java.lang.Object
android.content.Context
android.content.ContextWrapper
android.view.ContextThemeWrapper
android.app.Activity

现在我们知道了,启动activity需要使用Intent,调用startActivity方法。

2. 带参数跳转

跳转去下一个页面时,我们可能会想携带一些信息到下一个界面去。例如携带一些文本数字等等。 或者是一个对象。 这些信息我们可以交给Intent,传递到下一个activity去。下一个activity中拿到我们传入的Intent。

携带基本类型和String

我们直接看intent的方法。

Intent intent = new Intent(getApplicationContext(), SendParamsDemo.class);
intent.putExtra(SendParamsDemo.K_INT, 100);
intent.putExtra(SendParamsDemo.K_BOOL, true);
intent.putExtra(SendParamsDemo.K_STR, "Input string");
startActivity(intent);

intent的putExtra方法,可以传入参数。它接受1个String作为key然后是具体参数。 例子中我们跳转去了SendParamsDemo

public class SendParamsDemo extends AbsActivity {

    public static final String K_INT = "k_int";
    public static final String K_BOOL = "k_bool";
    public static final String K_STR = "k_str";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        gotInput();
    }

    private void gotInput() {
        Intent intent = getIntent();
        if (intent != null) {
            int i = intent.getIntExtra(K_INT, -1);
            boolean b = intent.getBooleanExtra(K_BOOL, false);
            String str = intent.getStringExtra(K_STR);
            Log.d(TAG, "gotInput: i:" + i + ", b: " + b + ", str: " + str);
        } else {
            Log.d(TAG, "gotInput: input null.");
        }
    }
}
// log:
// com.rustfisher.tutorial2020 D/rustAppSendParamsDemo: gotInput: i:100, b: true, str: Input string

在这个activity中我们接收到了传入的参数。

观察intent的putExtra方法,我们发现支持传入很多种参数。

int,byte, char, float, double, long, booleanstring,CharSequence或是它们的数组。 也可以传入Parcelable,Serializable对象或是对象数组

传入Serializable对象

除了基本类型和String,可以传送对象吗? 答案是肯定的。Intent可以携带Serializable对象。 Serializable本身是一个接口自定义的对象实现这个接口后,就可以被Intent携带。 比如我们改造一下DataTest类,让它实现Serializable接口

public class DataTest implements Serializable { // 实现接口

然后将对象送给intent,再启动activity。

Intent intent = new Intent(getApplicationContext(), RecyclerViewDemo2Act.class);
DataTest out = new DataTest("input time", 233, 666, 999);
Log.d(TAG, "startInputData: sending object: " + out);
intent.putExtra(RecyclerViewDemo2Act.K_INPUT_DATA, out);
startActivity(intent);

被启动的activity接受传入的intent并取出对象。

Intent intent = getIntent();
if (intent != null) {
    DataTest d = (DataTest) intent.getSerializableExtra(K_INPUT_DATA);
    // 取出了对象,拿去显示
}

Serializable接口不含任何方法。实现了这个接口的类,系统自动将其序列化

我们打印发送接收到的对象。

startInputData: sending object: com.rustfisher.tutorial2020.recycler.data.DataTest@fb43df5
getInputData: input data object: com.rustfisher.tutorial2020.recycler.data.DataTest@a588b5c

可以发现这2个对象并不是同一个引用。但它们的“内容”是一样的。对象经历了序列化和反序列化的过程

值得注意的是,Intent 能携带的对象大小并不是无限制的。实际开发中,需要开发者自己预估传输数据大小

传送 Parcelable 对象和传送 Serializable 对象类似,用同样的存入和取出操作。


Activity 相关面试题

1. 谈一下返回

首先理解android是使用Task管理活动,一个Task就是一组存放在栈里的活动的集合,这个栈就叫做返回栈,每启动一个新的活动,就会将其放入栈顶,当我们点击back回退或调用activity的finish函数处于栈顶的活动就会出栈,前一个入栈的活动就会到栈顶,系统总是显示处于栈顶的活动。

2. 说下Activity的生命周期?
3. 说下活动的生存期

活动的生存期分为三个:

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

完整生存期:onCreate()方法与onDestory()都处于完整生存期,一般情况下,Activity会在onCreate()方法中完成各种初始化操作,而在onDestory()方法中完成释放内存的操作。

**可见生存期:**onStart()方法与onStop()方法就是可见生存期,Activity对于用户是可见的,但无法与用户交互。onStart()方法中对资源进行加载,onStop()方法中对资源进行释放。

**前台生存期:**onResume方法与onPause方法就是前台生存期,在前台生存期内,活动处于运行状态,此时可以与用户交互

4. 说下Activity处于onPasue()下可以执行那些操作?
  • 用户返回该Activity,调用onResume()方法,重新running
  • 用户打开了其他Activity,就会调用onStop()方法
  • 系统内存不足,拥有更高权限的应用需要内存,该Activity就会被系统回收
  • 如果用户返回到onStop()的Activity又显示在前台了,系统会调用
onRestart() -> onStart() -> onResume() 然后重新running

当Activity结束(调用finish()方法)就会调用onDestory()方法释放所有占用资源

生命周期的切换过程

  1. 启动一个Activity onCreate->onStart->onResume
  2. 当一个Activity打开另一个Activity都会回调哪些方法,如果ActivityB是完全透明的呢,如果启动的是一个对话框Activity呢? A:onPause->B:onCreate->B:onStart->B:onResume->A:onStop 如果ActivityB是完全透明的或对话框Activity则不会调用onStop。
  3. 启动新Activity后,又返回到旧的Activity B:onPause->A:onRestart->A:onStart->A:onResume->B:onStop->B:onDestory
  4. 关闭屏幕/按Home键: onPause->onStop
  5. 当一个Activity按Home键切换桌面后又回到该Activity回调哪些方法。 onPause->onStop->onRestart->onStart->onResume
  6. 当一个Activity按back回退回调哪些方法 onPause->onStop->onDestory

Activity的优先级

  1. 可见且可以交互(前台Acitivity):正在和用户交互,优先级最高。
  2. 可见但不可以交互(可见但非前台Activity):比如当前Activity启动了一个对话框Activity,当前Activity就是可见但不可以交互。
  3. 后台Activity:已经被暂停的Activity,比如执行了onStop,优先级最低。 当系统内存不足,会按照优先级顺序从低到高去杀死目标Activity所在的进程
5. 优先级低的Activity在内存不足被回收后怎样做可以恢复到销毁前状态?

优先级低的 Activity 在内存不足被回收后重新打开(横竖屏切换过程中)会引发Activity重建。

在 Activity 由于异常情况被终止时,系统会调用 onSaveInstanceState 方法来保存当前 Activity 的状态,该方法调用于 onStop 之前,与 onPause 方法没有时序关系

异常终止的 Activity 被重建时,会调用 onRestoreInstanceState 方法(该方法在 onStart 之后),并且把 Activity 销毁时 onSaveInstanceState 保存的 Bundle 对象参数同时传递onCreate 方法和onRestoreInstanceState 方法。该方法的调用是在 onStart 之前。

因此可通过 onRestoreInstanceState(Bundle savedInstanceState)onCreate((Bundle savedInstanceState)判断 Activity 是否被重建,并取出数据进行恢复。但需要注意的是,在 onCreate 取出数据时一定要先判断savedInstanceState 是否为空

补充:其中 onCreate 和 onRestoreInstanceState 方法来恢复 Activity 的状态的区别onRestoreInstanceState 方法回调说明 bundle 对象非空,不需要加非空判断,而 onCreate 需要非空判断。

6. 谈谈 onSaveInstanceState()onRestoreIntanceState()

onSaveInstanceState()两个方法并不是生命周期方法,它们并不一定会被触发。当应用遇到意外情况(如:内存不足、用户直接按Home键)由系统销毁一个Activity时,onSaveInstanceState() 会被调用,该方法的调用在onStop之前,与onPause没有时序关系。但是当用户主动去销毁一个Activity时,例如在应用中按返回键,onSaveInstanceState()就不会被调用。因为在这种情况下,用户的行为决定了不需要保存Activity的状态。

onSaveInstanceState()时机: (1)用户按下Home键 (2)横竖屏切换 (3)按下电源按钮关闭屏幕显示) (4)内存不足导致优先级的Activity被杀死

onRestoreIntanceState() 当被系统异常销毁的 Activity 被重建时,会调用 onRestoreIntanceState 或 onCreate 方法来恢复,而 onRestoreInstance 与 Oncreate 方法中传入的 Bundle 对象是销毁时 onSaveInstanceState 保存的,onRestoreIntanceState 在 onStart之后。

7. onSaveInstanceState()与onPause()的区别

onSaveInstanceState() 只适合用于保存一些临时性的状态,而onPause()适合用于数据的持久化保存。

8. 谈谈横竖屏切换过程中调用的函数

要切记这里活动已经被销毁了。 onPause->onSaveInstanceState->onStop->onDestory()->onCreate->onStart->onRestoreIntanceState->onResume

9. 如何防止横竖屏切换(配置改变)时Activity销毁并切换

通过对AndroidManifest文件的Activity中指定configChanges)属性

android:configChanges = “orientation| screensize

来避免横竖屏切换时,Activity的销毁和重建,而是回调了onCofigurationChanged()方法

@Override
 public void onConfigurationChanged(Configuration newConfig) {
 super.onConfigurationChanged(newConfig);
 }

这里附上android configChanges 的所有属性解释

mcc移动国家号码,由三位数字组成,每个国家都有自己独立MCC,可以识别手机用户所属国家。
“mnc“ 移动网号,在一个国家或者地区中,用于区分手机用户的服务商。
“locale“ 所在地区发生变化。
“touchscreen“ 触摸屏已经改变。(这不应该常发生。)
“keyboard“ 键盘模式发生变化,例如:用户接入外部键盘输入。
“keyboardHidden“ 用户打开手机硬件键盘navigation“ 导航型发生了变化。(这不应该常发生。)
“orientation“ 设备旋转,横向显示和竖向显示模式切换。
“fontScale“ 全局字体大小缩放发生改变
10. 说下Activity的四种启动模式
  1. standard模式标准模式):普通启动模式,每次启动Activity时,就会创建一个实例
  2. singletop模式(栈顶模式):当启动Activity时,会判断任务栈的栈顶是否为该Activity,如果是该Activity则不会创建实例,去回调onNewIntent(intent)方法,否则会创建实例
  3. singletask模式(栈内模式):当启动Activity时,只要该Activity在指定的栈中,就不会创建实例,去回调onNewIntent(intent)**方法。如果不存在,会判断是否指定的栈不存在,就创建一个栈并将Activity的实例压入,如果指定的栈存在,就直接压入该栈中。
  4. singleInstance模式(单实例模式):该模式下,创建Activity实例时,直接创建一个栈,栈中只有该Activity实例。之后无论哪个应用程序启动该Activity,都只会调用栈中该实例
11. 谈谈 singleTop 和 singleTask区别以及应用场景

singleTop 模式的含义是(参考上面问题),singleTask 模式的含义是(参考上面问题

因此二者的差别为:

  • singleTop 模式:该模式下,任务栈中可能有多个相同 Activity 实例,因为它只是判断当前启动的 Activity 是否在栈顶。 该模式的 Activity 会默认进入启动它所属的任务栈,不涉及任务栈的转换。常用于防止快速连续点击而创建多个 Activity 实例。
  • singleTask 模式:该模式向,任务栈中只会有一个Activity实例,因为它会判断当前启动的Activity是否在当前指定的栈中。该模式下Activity可以通过taskAffinity去指定需要的任务栈,可能涉及任务栈的转换,常用于首页登录页。因为不论我们在进入首页进入了多少个Activity,当我们返回首页后,还是希望退出首页直接可以退出应用。该模式下会把栈中位于要启动的Activity上面的Activity都出栈
12. onNewIntent()调用时机?

两个调用时机,分别是singleTop模式下与singleTask模式下启动Activity。 singleTop模式:当启动的Activity是在任务栈的栈顶时,会回调onNewIntent方法。 singleTask模式:当启动的Activity存在于任务栈中,会回调onNewIntent方法。

13. 了解哪些Activity启动模式的标记位?
  • FLAG_ACTIVITY_SINGLE_TOP:对应singleTop启动模式
  • FLAG_ACTIVITY_NEW_TASK:对应singleTask模式

更多Android零基础入门到精通的资料完整资料可以扫码免费领取!!!

腾讯技术团队出品】Android零基础入门到精通,Android Studio安装教程+全套安卓基础教程

Android编程入门教程

Java语言基础从入门到熟悉

在这里插入图片描述

Kotlin语言基础从入门到熟悉

在这里插入图片描述

Android 技术栈从入门到熟悉

在这里插入图片描述

Android Jetpack 全家桶全面学习

在这里插入图片描述

对于新手来说可能安装Android Studio存在一定困难你可以看着以下视频一步步的跟着学习安装运行

Android Studio 安装教程

在这里插入图片描述

有了Java阶段学习,这一阶段建议视频学习为主辅以图书查漏补缺。如果以图书为主,可以根据图书讲解代码,辅以教学视频查漏补缺。遇到问题可以去百度入门问题一般会有很多人遇到,并且给出比较好的解答。

需要掌握基本知识点比如四大组件如何使用、如何创建Service、如何进行布局、简单的自定义View、动画、网络通信常见技术

全套零基础教程已经为你们准备好了,需要的可以添加下方二维码免费领取

全套安卓基础教程

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

原文地址:https://blog.csdn.net/Android23333/article/details/132401922

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_26418.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注