# 架构

12345678

# 基础知识

# 基础组件

  • 界面组件:

    • Activity
    • Fragment
  • 服务组件

    • Service
  • 广播组件

    • BroadcastReceiver
  • 数据组件

    • ContentProvider
    • ContentResolver

# Activity

Activiey 是一个界面容器,主要用于展示界面和与用户交互

# 生命周期:

image-20220730091914457

//Activity 创建,完成初始化操作
	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//        Log.v (TAG,"Msg");//Verbose  观察值,Verbose 是冗长、啰嗦的意思,任何消息都会输出
//        Log.d (TAG,"Msg");//Debug  调试
//        Log.i (TAG,"Msg");//Info  信息,为一般提示性的消息
//        Log.w (TAG,"Msg");//Warn  可能会出问题,一般用于系统提示开发者需要优化 android 代码等场景
//        Log.e (TAG,"Msg");//Error  崩溃信息,一般用于输出异常和报错信息
        Log.i(TAG, "----onCreate----");
    }
    // Activity 在最新任务列表中打开时候会走此方法
    @Override
    protected void onRestart() {
        super.onRestart();
        Log.i(TAG, "----onRestart----");
    }
    // Activity 在 onCreate 或者 onRestart 之后执行
    @Override
    protected void onStart() {
        super.onStart();
        Log.i(TAG, "----onStart----");
    }
    // 正在与用户交互的界面,前台活动
    @Override
    protected void onResume() {
        super.onResume();
        Log.i(TAG, "----onResume----");
    }
    // 被其他与用户交互的 Activity 部分覆盖
    @Override
    protected void onPause() {
        super.onPause();
        Log.i(TAG, "----onPause----");
    }
    // 被其它与用户交互的 Activity 全部覆盖,可以做轻微重量级操作,如取消网络连接、注销广播接收器等
    @Override
    protected void onStop() {
        super.onStop();
        Log.i(TAG, "----onStop----");
    }
    // Activity 销毁时候调用此方法,释放资源
    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "----onDestroy----");
    }

几种情况:

  • 打开页面: onCreate() -> onStart() -> onResume()

  • 关闭页面:Resumed -> onPause() -> onStep() -> onDestroy()

  • 后台回收:销毁不会有时机处理,重建: onStart() -> onRestoreInstanceState() -> onResume()

  • 部分遮挡:Resumed -> onPause() 遮挡恢复 -> onResume()

  • 页面全遮挡:Resumed -> onStop() 遮挡恢复: onRestart() -> onStart() -> onResume()

  • 配置改变重建 Activity:Resumed -> onSaveInstanceState() -> onPause() - > onStop() -> onDestroy() - onCteate() -> onStart() -> onRestoreInstanceState() -> onResume()

  • 配置改变不重建 Activity:AndroidMainfest 配置 Activity 节点的 configChange 属性:

    • local:语言改变
    • fontSize:字体大小改变
    • orientation:旋转屏幕
    • keybordHidden:键盘显示隐藏

    配置改变:onConfigurationChanged ()

Activity 四个状态:

  1. 运行状态:Activity 处于返回栈栈顶,此时最不可能被回收
  2. 暂停状态;不再处于任务栈栈顶,系统不会轻易回收
  3. 停止状态:不在栈顶且不可见,内存低时系统会回收
  4. 销毁状态:不在栈内,系统自动回收

# 启动模式

参考:https://juejin.cn/post/6844903781486821389

首先了解任务和返回堆栈:官方文档

用户在执行某项工作时与之互动的一系列 Activity 集合,这些 Activity 按照每个 Activity 打开的顺序排列在一个返回堆栈里。

  • Standard 默认启动模式

    不设置 launchMode 属性默认是 Standard 启动模式,该模式的 Activity 启动就会在同一个任务栈创建一个新的实例,栈内可以存在多个实例。

    例子:任务栈 A-B-C (C 是栈顶),如果 C 去启动一个 A,那么会重新创建一个实例 A,即最终结果为 A-B-C-A,这时我们返回的时候(按下返回键)顺序依次是 A-C-B-A

    • 从 C 跳转到 A: onPause-C -> onCreate-A -> onStart-A -> onResume-A -> onStop-C -

    • 从 A 回退到 C: onPause-A -> onRestart-C -> onStart-C -> onResume-C -> onStop-A -> onDestroy-A

    • home 或锁屏: Resumed -> onPause -> onStop

    • home 回到 App: onStop -> onRestart -> onStart -> onResunme

  • SingleTask 栈内复用启动模式

    启动已在任务栈中的 Activity,则复用已经存在的 Activity 实例,调用该实例的 onNewInstant() 方法,若该实例不在栈顶,则将实例提到栈顶,在被调用的实例之上的实例出栈(销毁),如果实例不存在则创建一个实例加入当前栈

    常用于 APP 入口点

    • A 在栈顶:A 启动 A: onPause() -> onNewIntent ()-> onResume ()
    • 不在栈顶:
      • A->B B 启动 A: Resumed-B -> onPause-B -> onNewIntent-A -> onRestart-A -> onStart-A -> onResume-A -> onStop-B -> onDestroy-B
      • A ->B->C C 启动 A: Resumed-C -> onDestroy-B -> onPause-C -> onNewIntent-A -> onRestart-A -> onStart-A -> onResume-A -> onStop-C - > onDestroy-C
  • SingleTop 栈顶复用启动模式

    若调用的实例位于栈顶,则复用,调用 onNewTntent() 否则创建新的实例(类似于 Standard)

    • A 在栈顶,启动 A: onPause() -> onNewIntent ()-> onResume ()
    • A 不在栈顶:
      • A->B,B 启动 A 后,A->B->A: Resumed-B -> onPause-B -> onCreate-A -> onStart-A -> onResume-A -> onStop-B
      • A->B->C,C 启动 A,A->B->C-> Resumed-C -> onPause-C -> onCreate-A -> onStart-A -> onResume-A -> onStop-C
  • SingleInstance 单例启动模式

    全局单例,启动比较慢,切换效果不好,影响用户体验,用的不多,次启动模式的实例单独一个栈

# Intent 和 Intent 过滤器

Intent 是一个消息传递对象,基本用例:

  • 启动 Activity
  • 启动服务
  • 传递广播

# 启动 Acitivity

Intent 用于描述要启动的 Activity ,将 Intent 对象传递给 stratActivity( ) 可以启动新的 Activity 实例

如果希望启动的 Activity 完成后返回结果,使用 startActivityForResult( ) ,在 Activity 的 onActivityResult( ) 回调中,Activity 将结果作为单独的 Intent 对象接收

# 启动服务

Service 是没有用户界面的后台操作的组件,通过将 Intent 传递给 startService() ,启动服务执行一次性操作

如果服务旨在使用客户端 - 服务器接口,则通过将 Intent 传递给 bindService() ,可以从其他组件绑定到此服务。

# 传递广播

广播是任何应用均可接收的消息,系统根据系统事件传递广播,如网络断开与连接,充电等,通过将 Intent 传递给 sendBroadcast()sendOrderedBroadcast() ,可以将广播传递给其他应用。

# 构建 Intent

Intent 中包含主要信息如下:

  1. 组件名称:要启动的组件名称(可选项),有组件名称为显示传递,没有名称是隐式。启动 Service 时组件名称一定要指定

  2. 操作:指定要执行的操作(查看、选取等)的字符串。对于广播 Intent,这是指已发生且正在报告的操作。操作会在很大程度上决定其余 Intent 的构成,特别是数据和 extra 中包含的内容。

  3. 数据:引用待操作数据和 / 或该数据 MIME 类型的 URI( Uri 对象)。提供的数据类型通常由 Intent 的操作决定。例如,如果操作是 ACTION_EDIT ,则数据应包含待编辑文档的 URI。

    使用 setDataAndType() 同时设置 URI 和 MIME 类型

  4. 类别:一个包含应处理 Intent 组件类型的附加信息的字符串。可以将任意数量的类别描述放入一个 Intent 中,但大多数 Intent 均不需要类别。

  5. Extra:携带完成请求操作所需的附加信息的键值对。正如某些操作使用特定类型的数据 URI 一样,有些操作也使用特定的 extra。

    可以使用各种 putExtra() 方法添加 extra 数据,每种方法均接受两个参数:键名和值。您还可以创建一个包含所有 extra 数据的 Bundle 对象,然后使用 putExtras()Bundle 插入 Intent 中。

  6. 标志:标志在 Intent 类中定义,充当 Intent 的元数据。标志可以指示 Android 系统如何启动 Activity(例如,Activity 应属于哪个任务),以及启动之后如何处理(例如,Activity 是否属于最近的 Activity 列表)。

# Intent 实例

# 显式 Intent

显示 Intent 需要使用启动组件的名称(.class)

// 在 Activity 里执行,'this' 是 Context
// The fileUrl is a string URL, such as "http://www.example.com/image.png"
Intent downloadIntent = new Intent(this, DownloadService.class);
downloadIntent.setData(Uri.parse(fileUrl));
startService(downloadIntent);

Intent(Context, Class) 构造函数分别为应用和组件提供 ContextClass 对象。因此,此 Intent 将显式启动该应用中的 DownloadService 类。

# 隐式 Intent

隐式 Intent 指定能够在可以执行相应操作的设备上调用任何应用的操作。如果本应用无法执行该操作而其他应用可以,且希望用户选取要使用的应用,则使用隐式 Intent 非常有用。

例如,如果希望用户与他人共享你的内容,请使用 ACTION_SEND 操作创建 Intent,并添加指定共享内容的 extra。使用该 Intent 调用 startActivity() 时,用户可以选取共享内容所使用的应用。

:::warnning

** 注意:** 用户可能没有任何应用处理您发送到 startActivity() 的隐式 Intent。或者,由于配置文件限制或管理员执行的设置,可能无法访问应用。如果发生这样的情况,调用失败,应用也会崩溃。要验证 Activity 是否会接收 Intent,请对 Intent 对象调用 resolveActivity() 。如果结果为非空,则至少有一个应用能够处理该 Intent,并且可以安全调用 startActivity() 。如果结果为空,不要使用该 Intent。如有可能,您应停用发出该 Intent 的功能。以下示例说明如何验证 Intent 是否解析为 Activity。此示例没有使用 URI,但已声明 Intent 的数据类型,用于指定 extra 携带的内容。

:::

// Create the text message with a string
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType("text/plain");
// Verify that the intent will resolve to an activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(sendIntent);
}

# 接受隐式 Intent

要公布应用可以接收哪些隐式 Intent,请在清单文件中使用 <Intent-Filter> 过滤器之一传递时,系统才会将该 Intent 传递给应用组件。

显式 Intent 始终会传递给其目标,无论组件声明的 Intent 过滤器如何均是如此。

<Intent-Filter> 内部,可以使用以下三个元素中的一个或多个指定要接受的 Intent 类型:

  • <action>

    name 属性中,声明接受的 Intent 操作。该值必须是操作的文本字符串值,而不是类常量。

  • <data>

    使用一个或多个指定数据 URI( schemehostportpath )各个方面和 MIME 类型的属性,声明接受的数据类型。

  • <category>

    name 属性中,声明接受的 Intent 类别。该值必须是操作的文本字符串值,而不是类常量。

<activity android:name="ShareActivity">
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
</activity>

当接受类型为文本时,应用会接收 ACTION_SEND 的 Intent

过滤器一些实例

<activity android:name="MainActivity">
    <!-- This activity is the main entry, should appear in app launcher -->
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<activity android:name="ShareActivity">
    <!-- This activity handles "SEND" actions with text data -->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
    </intent-filter>
    <!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data -->
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <action android:name="android.intent.action.SEND_MULTIPLE"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="application/vnd.google.panorama360+jpg"/>
        <data android:mimeType="image/*"/>
        <data android:mimeType="video/*"/>
    </intent-filter>
</activity>
  • ACTION_MAIN 操作指示这是主要入口点,且不要求输入任何 Intent 数据。

  • CATEGORY_LAUNCHER 类别指示此 Activity 的图标应放入系统的应用启动器。如果 <activity> 元素未使用 icon 指定图标,则系统将使用 <application> 元素中的图标。

这两个元素必须配对使用,Activity 才会显示在应用启动器中。

更新于 阅读次数 本文阅读量:

请我喝[茶]~( ̄▽ ̄)~*

Windlinxy 微信支付

微信支付

Windlinxy 支付宝

支付宝