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

推荐订阅源

Blog — PlanetScale
Blog — PlanetScale
Webroot Blog
Webroot Blog
T
Troy Hunt's Blog
S
Secure Thoughts
S
Security @ Cisco Blogs
S
Security Affairs
Forbes - Security
Forbes - Security
W
WeLiveSecurity
H
Hacker News: Front Page
T
Threatpost
Google Online Security Blog
Google Online Security Blog
S
Schneier on Security
有赞技术团队
有赞技术团队
WordPress大学
WordPress大学
www.infosecurity-magazine.com
www.infosecurity-magazine.com
博客园 - Franky
腾讯CDC
IT之家
IT之家
博客园 - 聂微东
L
LINUX DO - 最新话题
罗磊的独立博客
Hacker News - Newest:
Hacker News - Newest: "LLM"
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 三生石上(FineUI控件)
Hacker News: Ask HN
Hacker News: Ask HN
C
CXSECURITY Database RSS Feed - CXSecurity.com
C
Cybersecurity and Infrastructure Security Agency CISA
C
CERT Recently Published Vulnerability Notes
Know Your Adversary
Know Your Adversary
V
Vulnerabilities – Threatpost
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
博客园_首页
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Cisco Talos Blog
Cisco Talos Blog
S
SegmentFault 最新的问题
酷 壳 – CoolShell
酷 壳 – CoolShell
Hugging Face - Blog
Hugging Face - Blog
L
LINUX DO - 热门话题
美团技术团队
G
GRAHAM CLULEY
T
The Exploit Database - CXSecurity.com
AI
AI
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Jina AI
Jina AI
Help Net Security
Help Net Security
N
News | PayPal Newsroom
月光博客
月光博客
Spread Privacy
Spread Privacy
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
N
News and Events Feed by Topic

博客园 - 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 滑动冲突 0. 安卓开发艺术探索参考资料 12. Material Design 7. 持久化技术 5. Fragment java 基础 4. UI 开发 3. Activity 2.2 Kotlin 面向对象 2.3 Kotlin高级 2.1 Kotlin基础 1. Android简介 [OpenJudge] 反正切函数的应用 (枚举)(数学) [OpenJudge] 摘花生 (模拟)
13. Jetpack
y丶innocence · 2026-01-20 · via 博客园 - y丶innocence

13. Jetpack

1. 依赖

lifecycle

MainActivity2

package com.example.helloworld

import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.ArrayAdapter
import android.widget.Button
import android.widget.ListView
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()
        }

        val button4: Button = findViewById(R.id.button4)
        button4.setOnClickListener {
            startNewActivity(this, MainActivity3::class.java)
        }

        val button5: Button = findViewById(R.id.button5)
        button5.setOnClickListener {
            startNewActivity(this, MainActivity4::class.java)
        }

        val button7: Button = findViewById(R.id.button7)
        button7.setOnClickListener {
            startNewActivity(this, FragmentActivity::class.java)
        }
        val button8: Button = findViewById(R.id.button8)
        button8.setOnClickListener {
            startNewActivity(this, FileStorage::class.java)
        }

        val button9: Button = findViewById(R.id.button9)
        button9.setOnClickListener {
            startNewActivity(this, DataPreference::class.java)
        }

        val button10: Button = findViewById(R.id.button10)
        button10.setOnClickListener {
            startNewActivity(this, SqliteDB::class.java)
        }

        val button11: Button = findViewById(R.id.button11)
        button11.setOnClickListener {
            startNewActivity(this, Design::class.java)
        }

        val button12: Button = findViewById(R.id.button12)
        button12.setOnClickListener {
            startNewActivity(this, JetpackDemo::class.java)
        }

    }

}

second_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/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="Back" />

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

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

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

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

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

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

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

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

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

</LinearLayout>

2. 概念

  • ViewModel
    • 存放界面相关数据
      • 解耦
      • 生命周期不同,能更好保存数据
  • LiveData
    • 背景
      • Activity 中手动获取 ViewModel 中的数据
      • 但是 ViewModel 却无法数据的变化主动通知Activity

3. 代码

JetpackDemo

package com.example.helloworld

import android.arch.lifecycle.Transformations
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.TextView
import androidx.core.content.edit
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.OnLifecycleEvent
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider



class MainViewModel(countReserved: Int) : ViewModel() {
    val counter: LiveData<Int>                      // 委托, val 表示引用不变
        get() = _counter
    private val _counter = MutableLiveData<Int>()   // 可变的LiveData, 外部无法调用
    init {
        _counter.value = countReserved
    }
    fun plusOne() {
        val count = _counter.value ?: 0         // getValue 可能为空,语法糖写法
        _counter.value = count + 1
    }

    fun clear() {
        _counter.value = 0
    }
}

class MyObserver(val lifecycle: Lifecycle) : LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_START)  // 在 onStart 时触发
    fun activityStart() {
        Log.d("MyObserver", "activityStart")
    }
    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun activityStop() {
        Log.d("MyObserver", "activityStop")
    }
}


class MainViewModelFactory(private val countReserved: Int) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {  // 【理解】
        return MainViewModel(countReserved) as T
    }
}

class JetpackDemo : BaseActivity() {

    lateinit var viewModel: MainViewModel
    lateinit var sp: SharedPreferences

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

        sp = getPreferences(Context.MODE_PRIVATE)       // 读取 sp 实例
        val countReserved = sp.getInt("count_reserved", 0) // 如果没有则默认 0

        // 不能直接创建 ViewMode 实例, 因为每次调用 onCreate 都会创建新的
        // kotlin 中的生命周期不是栈,因此不存在因为自动销毁,根据引用计数销毁
        viewModel = ViewModelProvider(this, MainViewModelFactory(countReserved))
            .get(MainViewModel::class.java)

        val plusOneBtn: Button = findViewById(R.id.plusOneBtn)
        plusOneBtn.setOnClickListener {
            viewModel.plusOne()
        }
        val clearBtn: Button = findViewById(R.id.clearBtn)
        clearBtn.setOnClickListener {
            viewModel.clear()
        }

        viewModel.counter.observe(this) { count ->                  // 观察者模式更新数据
            val infoText: TextView = findViewById(R.id.infoText)
            infoText.text = count.toString()                                // 数字保存在 viewModel 中
            Log.d("lifecycle", "${lifecycle.currentState}")   // 输出 resumed
        }

        lifecycle.addObserver(MyObserver(lifecycle))        // 是这么调用吗? 查看的哪个对象,好像没有参数这两句话都有输出
        Log.d("lifecycle", "${lifecycle.currentState}")   // 输出 initialized,因为还没完全创建

    }
    override fun onPause() {        // 离开前台后保存数据
        super.onPause()
        sp.edit {
            putInt("count_reserved",  viewModel.counter.value ?: 0)
        }
    }
}

jetpack_layout

<?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:id="@+id/infoText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:textSize="32sp"/>

    <Button
        android:id="@+id/plusOneBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="Plus One"/>
    <Button
        android:id="@+id/clearBtn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="Clear"/>
</LinearLayout>