惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Y
Y Combinator Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Apple Machine Learning Research
Apple Machine Learning Research
Blog — PlanetScale
Blog — PlanetScale
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
G
Google Developers Blog
F
Full Disclosure
大猫的无限游戏
大猫的无限游戏
酷 壳 – CoolShell
酷 壳 – CoolShell
T
Threat Research - Cisco Blogs
A
Arctic Wolf
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
The Cloudflare Blog
博客园 - 【当耐特】
AWS News Blog
AWS News Blog
U
Unit 42
V
Vulnerabilities – Threatpost
P
Privacy International News Feed
T
Tor Project blog
Microsoft Security Blog
Microsoft Security Blog
宝玉的分享
宝玉的分享
Google DeepMind News
Google DeepMind News
爱范儿
爱范儿
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Recorded Future
Recorded Future
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
CXSECURITY Database RSS Feed - CXSecurity.com
T
Threatpost
Latest news
Latest news
GbyAI
GbyAI
S
SegmentFault 最新的问题
MongoDB | Blog
MongoDB | Blog
N
Netflix TechBlog - Medium
Hacker News: Ask HN
Hacker News: Ask HN
美团技术团队
N
News | PayPal Newsroom
J
Java Code Geeks
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Microsoft Azure Blog
Microsoft Azure Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
The Hacker News
The Hacker News
The GitHub Blog
The GitHub Blog
V
V2EX
N
News and Events Feed by Topic
T
Troy Hunt's Blog
Security Latest
Security Latest
博客园 - 叶小钗
P
Palo Alto Networks Blog

博客园 - y丶innocence

临时111 RecyclerView 数据多时无法滑动:ConstraintLayout 约束高度修复笔记 Android Kotlin OkHttp3 WebSocket 长连接与 Gson 数据解析系统笔记 Android + Kotlin + OkHttp WebSocket 相关概念与使用流程笔记(TLS/证书 + 鉴权/会话) AI对话导出markdown格式流程 代理转发 分享文件 面向全球的app的excel导出和kotlin IO原理 安卓导出笔记(未整理) java&kotlin listener 0.7 动画 0.4 View 工作流程 0.3 view 滑动冲突 13. Jetpack 0. 安卓开发艺术探索参考资料 12. Material Design 7. 持久化技术 5. Fragment java 基础 4. UI 开发 2.2 Kotlin 面向对象 2.3 Kotlin高级 2.1 Kotlin基础 1. Android简介 [OpenJudge] 反正切函数的应用 (枚举)(数学) [OpenJudge] 摘花生 (模拟)
3. Activity
y丶innocence · 2026-01-09 · via 博客园 - y丶innocence

3. Activity

1. 基本用法

  • Activity

    • 概念:可以包含用户界面的组件,主要用于和用户进行交互
    • 每个 Activity 都应该重写 onCreate 方法
  • Layout

    • res 中建立 layout 文件夹,并建立文件
    • 最好每一个 Activity 对应一个布局 layout
    • layout 创建好之后通过 setContentView 加载到 Activity 上
    • 布局拖动内容可以直接修改 xml 代码
    • 资源 id
      • R.layout.first_layout
      • R.id.button1
  • Toast

    • 短暂提醒后消失
  • menu

    • res 中建立 menu文件夹,并建立文件
    • 由于版本不同,这里参照书中内容,进行如下修改,代码如下
      • 继承 ComponentActivity
      • layout 文件增加 Toolbar
      • res/values/theme 修改主题为 Theme.AppCompat.Light.NoActionBar
  • Main.kt

package com.example.helloworld

import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.first_layout)                        // 设置 layout

        val toolbar: Toolbar = findViewById(R.id.toolbar)       // 绑定工具栏
        setSupportActionBar(toolbar)

        supportActionBar?.setDisplayHomeAsUpEnabled(true)            // 设置返回按钮

        val button1: Button = findViewById(R.id.button)        // 通过 id 找到 view, 并指明类型为 button
        button1.setOnClickListener{
            Toast.makeText(this, "You clicked Button 1", Toast.LENGTH_SHORT).show()     // layout 为 context
        }
        Log.d("MainActivity", "onCreate execute")
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {         // 工具栏右边的 ... 菜单
        menuInflater.inflate(R.menu.main, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {    // 菜单按钮的点击逻辑
        when(item.itemId){
            R.id.add_item -> Toast.makeText(
                this, "You clicked Add",
                Toast.LENGTH_SHORT).show()
            R.id.remove_item -> Toast.makeText(
                this, "You clicked Remove",
                Toast.LENGTH_SHORT).show()
        }
        return true
    }
}


  • layout
<?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">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize"
        android:theme="?attr/actionBarTheme" />

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button" />
</LinearLayout>
  • main_menu
<?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>
  • res/values/theme
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <style name="Theme.HelloWorld" parent="Theme.AppCompat.Light.NoActionBar" />
</resources>

2. Intent

1. 总结

  • 作用

    • 启动 Activity,启动 Service,发送广播,传递数据

    • 主 Intent 中会有 intent-filter 相关设置

  • 分类

    • 显式 Intent
      • Activity1 中通过 Intent 对象和 startActivity 函数启动特定 Activity
    • 隐式 Intent
  • 数据传输

    • 发送数据
      • Activity1
        • intent.putExtra(key, data)
      • Activity2
        • data = intent.getStringExtra(key)
    • 传回数据
      • Activity1
        • startActivityForResult(intent, 1)
        • 重写 onActivityResult
      • Activity2
        • intent.putExtra(key, data)
        • setResult(RESULT_OK, intent

2. 隐式 Intent 详解

1. 隐式 Intent

  • 指定 actioncategory
    • AndroidManifest.xml 和主代码中指定
    • 内容似乎可以随意写,但是得对应上
    • 只有两者都匹配时才会相应
    • .DEFAULT 是默认 category,能自动添加到 intent
    • 每个 intent 只能指定一个 action,但是可以指定多个 category
    • 注意
      • 注意 xml 的格式,以及 android:exported 需要改为 true
  • 优势
    • 解构

2. 拓展

【暂不学习】

0. 代码

1. 显式 Intent + 数据传输代码

  • Activity1

  • package com.example.helloworld
    
    import android.app.ComponentCaller
    import android.content.Intent
    import android.os.Bundle
    import android.util.Log
    import android.view.Menu
    import android.view.MenuItem
    import android.widget.Button
    import android.widget.Toast
    import androidx.appcompat.app.AppCompatActivity
    import androidx.appcompat.widget.Toolbar
    class MainActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.first_layout)                        // 设置 layout
    
            val toolbar: Toolbar = findViewById(R.id.toolbar)       // 绑定工具栏
            setSupportActionBar(toolbar)
    
            supportActionBar?.setDisplayHomeAsUpEnabled(true)            // 设置返回按钮
    
            val button1: Button = findViewById(R.id.button)        // 通过 id 找到 view, 并指明类型为 button
            button1.setOnClickListener{
                Toast.makeText(this, "You clicked Button 1", Toast.LENGTH_SHORT).show()     // layout 为 context
                val intent = Intent(this, MainActivity2::class.java)
                val data = "Hello Activity2"
                intent.putExtra("first_data", data)   // 发送数据,类似map,第一个为键,用于选择哪个值,后者为值
    //            startActivity(intent)
                startActivityForResult(intent, 1)       // 接受数据时调用这个函数表明需要返回一个结果,1代表请求码
            }
            Log.d("MainActivity", "onCreate execute")
        }
    
        override fun onActivityResult(                                  // 由于调用 startActivityForResult,因此需要重写方法来得到返回的数据
            requestCode: Int,
            resultCode: Int,
            data: Intent?,
            caller: ComponentCaller
        ) {
            super.onActivityResult(requestCode, resultCode, data, caller)
            when(requestCode){
                1 -> if(resultCode == RESULT_OK){
                    val returnedData = data?.getStringExtra("data_return")
                    Log.d("Activity1", "returned data is $returnedData")
                }
            }
        }
    
        override fun onCreateOptionsMenu(menu: Menu?): Boolean {         // 工具栏右边的 ... 菜单
            menuInflater.inflate(R.menu.main, menu)
            return true
        }
    
        override fun onOptionsItemSelected(item: MenuItem): Boolean {    // 菜单按钮的点击逻辑
            when(item.itemId){
                R.id.add_item -> Toast.makeText(
                    this, "You clicked Add",
                    Toast.LENGTH_SHORT).show()
                R.id.remove_item -> Toast.makeText(
                    this, "You clicked Remove",
                    Toast.LENGTH_SHORT).show()
            }
            return true
        }
    }
    
  • Activity2

  • package com.example.helloworld
    
    import android.content.Intent
    import android.os.Bundle
    import android.util.Log
    import android.widget.Button
    import androidx.appcompat.app.AppCompatActivity
    import androidx.appcompat.widget.Toolbar
    
    class MainActivity2 : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.second_layout)                        // 设置 layout
    
            val toolbar: Toolbar = findViewById(R.id.toolbar2)       // 绑定工具栏
            val extraData = intent.getStringExtra("first_data")   // 接收数据
            Log.d("Activity2", "data is $extraData")
            setSupportActionBar(toolbar)
            supportActionBar?.setDisplayHomeAsUpEnabled(true)            // 设置返回按钮
            toolbar.setNavigationOnClickListener { finish() }             // 设置结束 act2
    
            val button2: Button = findViewById(R.id.button2)        // 通过 id 找到 view, 并指明类型为 button
            button2.setOnClickListener {
                val intent = Intent()
                intent.putExtra("data_return", "Hello Activity1")
                setResult(RESULT_OK, intent)
                finish()
            }
        }
    }
    
    
    
  • firstlayout

  • <?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">
    
        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="?attr/colorPrimary"
            android:minHeight="?attr/actionBarSize"
            android:theme="?attr/actionBarTheme" />
    
        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Button" />
    </LinearLayout>
    
  • secondlayout

  • <?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">
    
        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="?attr/colorPrimary"
            android:minHeight="?attr/actionBarSize"
            android:theme="?attr/actionBarTheme" />
    
        <Button
            android:id="@+id/button2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Button" />
    </LinearLayout>
    

2. 隐式 Intent

  • activity1

  • package com.example.helloworld
    
    import android.app.ComponentCaller
    import android.content.Intent
    import android.os.Bundle
    import android.util.Log
    import android.view.Menu
    import android.view.MenuItem
    import android.widget.Button
    import android.widget.Toast
    import androidx.appcompat.app.AppCompatActivity
    import androidx.appcompat.widget.Toolbar
    class MainActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.first_layout)                        // 设置 layout
    
            val toolbar: Toolbar = findViewById(R.id.toolbar)       // 绑定工具栏
            setSupportActionBar(toolbar)
            supportActionBar?.setDisplayHomeAsUpEnabled(true)            // 设置返回按钮
    
            val button1: Button = findViewById(R.id.button)        // 通过 id 找到 view, 并指明类型为 button
            button1.setOnClickListener{
                val intent = Intent("com.example.helloworld.ACTION_START")
                intent.addCategory("com.example.helloworld.MY_CATEGORY")
                startActivity(intent)
            }
            Log.d("MainActivity", "onCreate execute")
        }
    }
    
  • AndroidManifest

  • <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">
    
        <application
            android:allowBackup="true"
            android:dataExtractionRules="@xml/data_extraction_rules"
            android:fullBackupContent="@xml/backup_rules"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/Theme.HelloWorld">
            <activity
                android:name=".MainActivity2"
                android:exported="true"
                android:label="@string/title_activity_main2"
                android:theme="@style/Theme.HelloWorld" >
                <intent-filter>
                    <action android:name="com.example.helloworld.ACTION_START"/>
                    <category android:name="android.intent.category.DEFAULT"/>
                    <category android:name="com.example.helloworld.MY_CATEGORY"/>
                </intent-filter>
            </activity>
            <activity
                android:name=".MainActivity"
                android:exported="true"
                android:label="@string/app_name"
                android:theme="@style/Theme.HelloWorld">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>
    

3. 生命周期

1. 基础

1. 栈

  • 在安卓中,Activity 的层叠关系可以用来表示
    • 主动创建销毁
      • 创建的 Activity 出现在栈顶
      • 返回后 finish 的 Activity 在栈顶被移除
    • 被动系统回收
      • 根据 Activity 状态回收,不倾向于回收栈顶的 Activity

2. Activity 状态和生存期

运行状态 返回栈的栈顶,最不容易被回收 暂停状态 不处于栈顶,但仍然可见 (运行 Activity 可能没全屏),不容易被回收 停止状态 不处于栈顶且不可见,仍保存对应的状态成员变量,可能会被回收 销毁状态 从返回栈中被移除,最倾向于回收
状态 内容
完整生存期 onCreate 第一次被创建时使用,完成 Activity 的初始化onDestrory销毁时使用 分别进行初始化和释放内存可见生存期 onStart不可见变为可见时调用 onStop 在变为完全不可见时调用,比如启动对话框(仍可见时),只会调用 onPause 总是可见但不一定能交互,能管理可见资源,分别进行资源加载和释放,保证处于停止状态的 Activity 不会占用过多内存 前台生存期 onResume 准备进行交互时调用,此时位于栈顶onPause 系统准备启动或者恢复另一个 Activity 时调用,会释放一些消耗 CPU 的资源,保存关键数据,执行要快 处于运行状态,可以进行交互
生存期 操作 细节 操作 细节 整体细节
  • onRestart:从停止状态变为**运行状态 **
  • 左边从上到下,右边从下到上

3. 案例

有 MainActivity,NormalActivity 和 DialogActivity,其中 DialogActivity 不是全屏,点击 MainActivity 的两个按钮可以启动对应 Activity

  • 启动时
    • onCreate/onStart/onResume
  • 退出时
    • onPause/onStop/onDestrory
  • 点击 NormalActivity 时(不可见)
    • onPause/onStop
  • 退出 NormalActivity 时
    • onRestart/onStart/onResume
  • 点击 DialogActivity 时
    • onPause
  • 退出 DialogActivity 时
    • onResume

4. 回收

  • 情况:当一个 Activity 点入其他 Activity 后进入停止状态(不可见时),然后从其他 Activity 返回,而原始 Activity 可能被回收
    • 当没被回收时
      • 仍处于停止状态
      • onRestart/onStart/onResume
    • 当被回收时
      • 处于销毁状态,需要重新创建
      • onCreate/onStart/onResume
      • 此时临时数据被销毁,因此需要进行状态恢复
  • 恢复原理
    • Activity 中提供 onSaveInstanceState 回调
      • 该函数携带一个 Bundle 类型参数,提供一些列方法保存不同的数据
// 保存数据
override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    val tempData = "Something"
    outState.putString("data_key", tempData)
}

// 取出数据(在onCreate函数中)
if(savedInstanceState != null){                                             // 取出数据
    val tempData = savedInstanceState.getString("data_key")
    Log.d("saved_data", "tempData is $tempData")
}

val tempData = savedInstanceState?.getString("data_key")            // 简化写法
tempData?.let{Log.d("saved_data", "tempData is $it")}

2. 启动模式

  • 在 AndroidManifest.xml 的对应 Activity 处修改启动模式
standard每次创建一个新的 Activity 可以递归创建若干次同一个 Activity,需要返回若干次回到第一个 Activity singleTop栈顶不会出现重复的 Activity 在栈顶进行检查,判断是否需要启动新的 Activity,相同则不启动 singleTask整个栈不会出现重复的 Activity 创建新的 Activity 时,如果发现该 Activity 已存在,则该 Activity 之上的全部出栈singleInstance 会有一个新的栈存储 Activity 1 通过 singleInstance 调用2,2普通调用3,此时3返回1,然后返回2
启动模式 特征 具体 原理图

4. 实践

1. 判断在哪个 Activity

  • 创建一个 BaseActivity 类继承自 AppComPatActivity 类
  • 增加一个 javaClass.simpleName 的 Log
  • 后续继承自 BaseActivity

2. 随处退出程序

  • 创建一个单例类 ActivityCollector 来管理 Activity 集合
    • 维护一个 Activity 的 List
    • 函数包括添加,移除和全部结束【问题:如果只需要结束一个呢,因为新版本似乎需要自己写 finish 逻辑】

3. 启动 Activity 的最佳写法

// 伴生类
companion object {
    fun actionStart(context: Context, data1: String, data2: String) {
        val intent = Intent(context, MainActivity2::class.java).apply {
            putExtra("param1", data1)
            putExtra("param2", data2)
        }
        context.startActivity(intent)           // 没有 startActivityForResult
    }
}

//调用启动
button1.setOnClickListener{
    actionStart(this, "Activity1", "")      // 启动 Activity
}

5. 汇总代码

【暂未完成返回数据到上一个 Activity】

MainActivity.kt

package com.example.helloworld

import android.app.ComponentCaller
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
class MainActivity : BaseActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 设置 layout
        setContentView(R.layout.first_layout)
        ActivityCollector.addActivity(this)

        // 绑定工具栏
        val toolbar: Toolbar = findViewById(R.id.toolbar)
        setSupportActionBar(toolbar)

        // 设置返回按钮
        supportActionBar?.setDisplayHomeAsUpEnabled(true)

        // 取出保存的数据
        val tempData = savedInstanceState?.getString("data_key")
        tempData?.let{Log.d("saved_data", "tempData is $it")}

        // 通过 id 找到 view, 并指明类型为 button
        val button1: Button = findViewById(R.id.button)
        // 启动 Activity
        button1.setOnClickListener{
            actionStart(this, "Activity1", "")
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        ActivityCollector.removeActivity(this)
    }

    // 工具栏右边的 ... 菜单
    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.main, menu)
        return true
    }

    // 菜单按钮的点击逻辑
    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when(item.itemId){
            R.id.add_item -> Toast.makeText(
                this, "You clicked Add",
                Toast.LENGTH_SHORT).show()
            R.id.remove_item -> Toast.makeText(
                this, "You clicked Remove",
                Toast.LENGTH_SHORT).show()
        }
        return true
    }

    // 伴生类 启动 Activity
    companion object {
        fun actionStart(context: Context, data1: String, data2: String) {
            val intent = Intent(context, MainActivity2::class.java).apply {
                putExtra("param1", data1)
                putExtra("param2", data2)
            }
            context.startActivity(intent)           // 没有 startActivityForResult
        }
    }

    // 保存杀死后台之后的数据
    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        val tempData = "Something"
        outState.putString("data_key", tempData)
    }
}

MainAcitivity2.kt

package com.example.helloworld

import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar

class MainActivity2 : BaseActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.second_layout)

        // toolbar 部分
        val toolbar: Toolbar = findViewById(R.id.toolbar2)
        setSupportActionBar(toolbar)
        supportActionBar?.setDisplayHomeAsUpEnabled(true)            // 设置返回按钮
        toolbar.setNavigationOnClickListener { finish() }             // 设置结束 act2

        ActivityCollector.addActivity(this)

        // 从前一个 Activity 接收数据
        val extraData1 = intent.getStringExtra("param1")
        val extraData2 = intent.getStringExtra("param2")
        Log.d("Activity2", "param1 is $extraData1, param2 is $extraData2")


        // 返回数据(但是未实现)
        val button2: Button = findViewById(R.id.button2)        // 通过 id 找到 view, 并指明类型为 button
        button2.setOnClickListener {
            val intent = Intent().apply { putExtra("data_return", "Hello Activity1") }
            setResult(RESULT_OK, intent)
            finish()
        }

        // 关闭所有 Activity
        val button3: Button = findViewById(R.id.button3)
        button3.setOnClickListener {
            ActivityCollector.finishAll()
        }
    }
}


Util.kt

package com.example.helloworld

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.snackbar.Snackbar

// 输出当前是哪一个 Activity
open class BaseActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d("BaseActivity", "${javaClass.simpleName} is created")
    }

    override fun onStart() {
        super.onStart()
        Log.d("BaseActivity", "${javaClass.simpleName} is started")
    }

    override fun onResume() {
        super.onResume()
        Log.d("BaseActivity", "${javaClass.simpleName} is resumed")
    }
}

// Activity 管理
object ActivityCollector {
    private val activities = ArrayList<Activity>()
    fun addActivity(activity: Activity){
        activities.add(activity)
    }

    fun removeActivity(activity: Activity){
        activities.remove(activity)
    }

    fun finishAll() {
        activities.forEach {
            if(!it.isFinishing) {
                it.finish()
            }
        }
        activities.clear()
    }
}

fun startNewActivity(context: Context, targetActivity: Class<out AppCompatActivity>) {
    val intent = Intent(context, targetActivity)
    context.startActivity(intent)
}

// 调用方法 startNewActivity(this, ActivityClass::class.java)
fun startNewActivity(context: Context, targetActivity: Class<out AppCompatActivity>, data1: String, data2: String) {
    val intent = Intent(context, targetActivity).apply {
        putExtra("param1", data1)
        putExtra("param2", data2)
    }
    context.startActivity(intent)
}

fun startNewActivityAndFinish(activity: Activity, targetActivity: Class<out AppCompatActivity>) {
    val intent = Intent(activity, targetActivity)
    activity.startActivity(intent)
    activity.finish()
}

// 调用方法 "This is Toast".showToast(context, Toast.LENGTH_LONG)
fun String.showToast(context: Context, duration: Int = Toast.LENGTH_SHORT) {
    Toast.makeText(context, this, duration).show()
}
fun Int.showToast(context: Context, duration: Int = Toast.LENGTH_SHORT) {
    Toast.makeText(context, this, duration).show()
}


/*      调用方法
 *      view.showSnackBar("This is SnackBar", "Action") {
 *          //
 *      处理具体的逻辑
 *      }
 **/
fun View.showSnackBar(text: String, actionText: String? = null,
                      duration: Int = Snackbar.LENGTH_SHORT, block: (() -> Unit)? = null) {
    val snackBar = Snackbar.make(this, text, duration)
    if (actionText != null && block != null) {
        snackBar.setAction(actionText) {
            block()
        }
    }
    snackBar.show()
}
fun View.showSnackBar(resId: Int, actionResId: Int? = null,
                      duration: Int = Snackbar.LENGTH_SHORT, block: (() -> Unit)? = null) {
    val snackBar = Snackbar.make(this, resId, duration)
    if (actionResId != null && block != null) {
        snackBar.setAction(actionResId) {
            block()
        }
    }
    snackBar.show()
}

first_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">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize"
        android:theme="?attr/actionBarTheme" />

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button" />
</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">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize"
        android:theme="?attr/actionBarTheme" />

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

    <Button
        android:id="@+id/button3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Quit App" />
</LinearLayout>

AndroidManifest.xml

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

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.HelloWorld">
        <activity
            android:name=".MainActivity2"
            android:exported="true"
            android:label="@string/title_activity_main2"
            android:theme="@style/Theme.HelloWorld" >
            <intent-filter>
                <action android:name="com.example.helloworld.ACTION_START"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="com.example.helloworld.MY_CATEGORY"/>
            </intent-filter>
        </activity>
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:theme="@style/Theme.HelloWorld">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>

themes.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <style name="Theme.HelloWorld" parent="Theme.AppCompat.Light.NoActionBar" />
</resources>