ViewModel和LifecycleOwner

一、先说结论:ViewModel 不能感知页面生命周期

很多人以为:

val viewModel = ViewModelProvider(this)[MainViewModel::class.java]

这里传了 this,而 this 是 Activity,所以 ViewModel 应该就能知道 Activity 的生命周期。

这个理解是错的。

ViewModelProvider(this) 里的 this,并不是把 Activity 传给 ViewModel,也不是让 ViewModel 持有 Activity。

这里的 this 本质上表示:

这个 ViewModel 要存放在哪个 ViewModelStore 里面。

也就是说,Activity 只是作为一个“宿主”,给 ViewModel 提供一个存放位置。

可以理解为:

  • Activity 是一个房间;
  • ViewModel 是一个箱子;
  • ViewModelStore 是房间里的柜子;
  • ViewModelProvider(this) 的意思是:把这个箱子放到当前房间的柜子里。

但是:

箱子被放进房间,不代表箱子知道房间什么时候开门、关门、亮灯、熄灯。

所以,ViewModel 不知道 Activity 什么时候执行了:

onCreate()
onStart()
onResume()
onPause()
onStop()
onDestroy()

ViewModel 只知道一件事:

自己什么时候要被销毁。

也就是:

override fun onCleared() {
    super.onCleared()
}

二、ViewModel 到底有没有生命周期?

这个问题面试里很容易被问。

要回答得严谨一点:

ViewModel 有自己的存活周期,但它不是 LifecycleOwner,不能感知页面生命周期事件。

也就是说,ViewModel 不是完全没有生命周期。

它确实有一个从创建到销毁的过程:

class MainViewModel : ViewModel() {

    init {
        // ViewModel 创建
    }

    override fun onCleared() {
        super.onCleared()
        // ViewModel 销毁
    }
}

但是它没有类似 Activity 的这些回调:

onCreate()
onStart()
onResume()
onPause()
onStop()
onDestroy()

ViewModel 只有:

onCleared()

所以更准确的说法是:

ViewModel 有自己的生命周期边界,但没有页面生命周期感知能力。


三、ViewModel 什么时候会销毁?

这是理解 ViewModel 的核心。

ViewModel 的销毁时机和 Activity 的销毁时机并不完全一样。

1. 配置变更时,ViewModel 不会销毁

比如:

  • 屏幕旋转;
  • 深色模式切换;
  • 语言切换;
  • 字体大小变化;
  • 某些配置变化导致 Activity 重建。

这些情况下,Activity 会经历销毁和重建。

旧 Activity 会执行:

onDestroy()

然后新的 Activity 会重新执行:

onCreate()

但是 ViewModel 不会销毁。

它会被保留下来,然后交给新的 Activity 继续使用。

这就是 ViewModel 最核心的价值之一:

在配置变更时保存数据,避免 Activity 重建导致数据丢失。


2. Activity 真正结束时,ViewModel 才会销毁

比如:

  • 用户按返回键退出页面;
  • 调用了 finish()
  • Fragment 从返回栈中被彻底移除;
  • 宿主真正结束。

这时候 ViewModel 才会执行:

onCleared()

所以可以总结为:

场景 Activity 是否重建 ViewModel 是否销毁
屏幕旋转
深色模式切换
语言切换
按返回键退出页面 是/否不重要
调用 finish()
Fragment 被彻底移除

四、为什么 ViewModel 不能持有 Activity 或 Fragment?

这是 ViewModel 设计里非常重要的一点。

ViewModel 的目的主要有两个:

  1. 在配置变更时保留数据;
  2. 让业务逻辑和 UI 解耦,避免内存泄漏。

如果 ViewModel 持有 Activity,会发生什么?

假设你这么写:

class MainViewModel(
    private val activity: Activity
) : ViewModel()

然后手机旋转屏幕。

此时流程是:

  1. 旧 Activity 被销毁;
  2. ViewModel 因为配置变更不会销毁;
  3. ViewModel 还持有旧 Activity;
  4. 旧 Activity 无法被 GC 回收;
  5. 内存泄漏。

这就是为什么官方不建议在 ViewModel 里持有:

  • Activity;
  • Fragment;
  • View;
  • Context,尤其是 Activity Context;
  • LifecycleOwner;
  • ViewBinding;
  • Adapter;
  • Dialog;
  • RecyclerView;
  • NavController。

这些对象都和 UI 生命周期强相关。

ViewModel 里应该放的是:

  • 页面状态;
  • 业务逻辑;
  • 网络请求;
  • 数据转换;
  • Repository 调用;
  • LiveData / StateFlow / SharedFlow;
  • SavedStateHandle;
  • Application 级别 Context,必要时可通过 AndroidViewModel 使用。

五、viewModelScope 能不能感知页面前后台?

不能。

很多人会误以为:

viewModelScope.launch {
    // do something
}

既然 viewModelScope 会自动取消,那它是不是能感知 Activity 的生命周期?

不是。

viewModelScope 只和 ViewModel 自己的销毁绑定。

也就是说:

viewModelScope.launch {
    while (true) {
        delay(1000)
        println("running")
    }
}

如果页面只是进入后台:

onPause()
onStop()

这个协程不会自动停止。

如果屏幕旋转,Activity 重建,ViewModel 仍然存在,那么这个协程也不会停止。

只有当 ViewModel 执行:

onCleared()

时,viewModelScope 里的协程才会自动取消。

所以结论是:

viewModelScope 感知的是 ViewModel 的销毁,不是 Activity / Fragment 的 onPause、onStop、onDestroyView。


六、页面 onResume / onPause 相关逻辑应该写在哪里?

如果业务需要在页面可见时刷新数据,或者页面不可见时停止某些任务,应该由 UI 层监听生命周期,再通知 ViewModel。

也就是说:

生命周期是 Activity / Fragment 的事情,业务处理可以交给 ViewModel。

比如:

class MainActivity : AppCompatActivity() {

    private val viewModel by viewModels<MainViewModel>()

    override fun onResume() {
        super.onResume()
        viewModel.onPageResume()
    }

    override fun onPause() {
        super.onPause()
        viewModel.onPagePause()
    }
}

ViewModel 中只处理业务:

class MainViewModel : ViewModel() {

    fun onPageResume() {
        // 页面回到前台
        // 可以刷新数据、恢复轮询、上报埋点
    }

    fun onPagePause() {
        // 页面进入后台
        // 可以暂停任务、停止轮询、保存状态
    }
}

这种写法是合理的。

注意,这并不是 ViewModel 主动感知生命周期,而是:

Activity 感知生命周期,然后主动调用 ViewModel 的方法。


七、也可以用 LifecycleObserver 解耦生命周期监听

如果不想直接重写 onResume()onPause(),也可以这样写:

lifecycle.addObserver(object : DefaultLifecycleObserver {

    override fun onResume(owner: LifecycleOwner) {
        viewModel.onPageResume()
    }

    override fun onPause(owner: LifecycleOwner) {
        viewModel.onPagePause()
    }
})

这和重写生命周期方法本质是一样的。

区别只是写法不同。

核心仍然是:

UI 层监听生命周期,ViewModel 被动接收通知。

不要反过来让 ViewModel 去监听 Activity。


八、observe(this) 里的 this 又是什么意思?

很多人会被这句代码搞混:

viewModel.count.observe(this) { count ->
    textView.text = count.toString()
}

这里也传了 this

于是有人就会问:

既然 observe(this) 可以传 Activity,为什么又说 ViewModel 不能感知生命周期?

关键点在于:

感知生命周期的是 LiveData,不是 ViewModel。

这句代码里:

viewModel.count.observe(this) { }

真正拿到 this 的是 LiveData

LiveData 会根据 Activity 的生命周期来决定:

  • 页面活跃时,分发数据;
  • 页面不活跃时,暂缓分发;
  • 页面销毁时,自动移除观察者。

但是 ViewModel 本身并没有拿到 Activity。

ViewModel 只是持有了一个 LiveData:

class MainViewModel : ViewModel() {

    private val _count = MutableLiveData<Int>()
    val count: LiveData<Int> = _count
}

Activity 订阅这个 LiveData:

viewModel.count.observe(this) { count ->
    // 更新 UI
}

所以流程是:

  1. ViewModel 更新 LiveData;
  2. LiveData 通知观察者;
  3. LiveData 根据 LifecycleOwner 判断当前页面能不能收到数据;
  4. Activity 收到数据后更新 UI。

ViewModel 并不知道 Activity 当前是 resumed、paused 还是 destroyed。


九、Fragment 里 observe 不要随便传 this

这里还要补充一个非常高频的坑。

在 Fragment 里,很多人会这样写:

viewModel.data.observe(this) {
    // update UI
}

这通常不推荐。

因为 Fragment 有两个生命周期:

  1. Fragment 自己的生命周期;
  2. Fragment 的 View 生命周期。

Fragment 的 View 可能已经销毁了,但 Fragment 还没销毁。

比如:

onDestroyView()

执行之后,Fragment 还可能存在。

如果你用 this 作为 LifecycleOwner,观察者可能还活着,但 ViewBinding 已经没了,这就容易导致:

  • 空指针;
  • 重复观察;
  • 内存泄漏;
  • UI 更新异常。

所以在 Fragment 里应该使用:

viewModel.data.observe(viewLifecycleOwner) {
    // update UI
}

原因是:

UI 更新应该跟 Fragment 的 View 生命周期绑定,而不是跟 Fragment 本身绑定。

这是面试和项目里都非常重要的细节。


十、LiveData 和 Flow 的生命周期区别

如果项目里用的是 LiveData:

viewModel.data.observe(viewLifecycleOwner) {
    // update UI
}

LiveData 自带生命周期感知能力。

如果项目里用的是 Flow / StateFlow:

lifecycleScope.launch {
    viewModel.dataFlow.collect {
        // update UI
    }
}

这样写还不够严谨。

因为普通 collect 不会自动根据页面 STARTED / STOPPED 停止和恢复收集。

更推荐这样:

lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.dataFlow.collect { data ->
            // update UI
        }
    }
}

在 Fragment 里一般写成:

viewLifecycleOwner.lifecycleScope.launch {
    viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.dataFlow.collect { data ->
            // update UI
        }
    }
}

这样可以做到:

  • 页面进入 STARTED 状态后开始收集;
  • 页面 STOPPED 后停止收集;
  • 页面再次 STARTED 后重新收集;
  • View 销毁后自动取消。

这才是 Flow 配合页面生命周期的推荐方式。


十一、完整 MVVM 流程应该这样理解

MVVM 里不是 ViewModel 主动操作 View,而是双向通过方法和数据流进行沟通。

1. UI 层通知 ViewModel

比如用户点击按钮:

button.setOnClickListener {
    viewModel.onLoginClick()
}

比如页面回到前台:

override fun onResume() {
    super.onResume()
    viewModel.onPageResume()
}

也就是说:

Activity / Fragment 感知事件
        ↓
调用 ViewModel 方法
        ↓
ViewModel 执行业务逻辑

2. ViewModel 暴露状态给 UI

ViewModel 不直接操作 TextView、RecyclerView、Toast、Dialog。

它应该暴露状态:

class MainViewModel : ViewModel() {

    private val _uiState = MutableLiveData<UiState>()
    val uiState: LiveData<UiState> = _uiState

    fun loadData() {
        viewModelScope.launch {
            _uiState.value = UiState.Loading

            try {
                val data = repository.getData()
                _uiState.value = UiState.Success(data)
            } catch (e: Exception) {
                _uiState.value = UiState.Error(e.message ?: "未知错误")
            }
        }
    }
}

Activity / Fragment 观察状态:

viewModel.uiState.observe(this) { state ->
    when (state) {
        is UiState.Loading -> showLoading()
        is UiState.Success -> showData(state.data)
        is UiState.Error -> showError(state.message)
    }
}

整体流程是:

ViewModel 更新状态
        ↓
LiveData / StateFlow 发出数据
        ↓
Activity / Fragment 收到数据
        ↓
更新 UI

可以把这两个点总结成一句话:

页面生命周期事件是 UI 主动告诉 ViewModel;数据变化是 ViewModel 通过 LiveData/StateFlow 通知 UI。
这两个方向完全不同,很多人混淆就是因为都出现了 thisviewModelobserve 这些代码。

下面帮你按面试和项目最容易混的点梳理清楚。


一、先建立总模型:MVVM 里有两个方向

方向 1:UI → ViewModel

例如:

override fun onResume() {
    super.onResume()
    viewModel.onPageResume()
}

或者:

lifecycle.addObserver(object : DefaultLifecycleObserver {
    override fun onResume(owner: LifecycleOwner) {
        viewModel.onPageResume()
    }
})

这个方向表达的是:

Activity / Fragment 感知生命周期
        ↓
主动调用 ViewModel 方法
        ↓
ViewModel 执行业务逻辑

比如:

  • 页面回到前台,刷新数据;
  • 页面进入前台,开启轮询;
  • 页面进入后台,暂停任务;
  • 用户点击按钮,调用登录逻辑;
  • 用户下拉刷新,调用加载逻辑。

所以这个方向叫:

UI 通知 ViewModel 做事。


方向 2:ViewModel → UI

例如:

viewModel.count.observe(this) { count ->
    tvCount.text = count.toString()
}

这个方向表达的是:

ViewModel 更新数据
        ↓
LiveData 通知观察者
        ↓
Activity / Fragment 收到回调
        ↓
更新 UI

比如:

  • ViewModel 请求接口成功;
  • ViewModel 更新 LiveData;
  • Activity 收到数据;
  • Activity 渲染页面。

所以这个方向叫:

ViewModel 通过数据通知 UI 更新。


二、最容易混淆的点 1:viewModel.onPageResume() 不是 ViewModel 感知生命周期

很多人看到这段代码:

override fun onResume() {
    super.onResume()
    viewModel.onPageResume()
}

就会误以为:

ViewModel 感知到了 Activity 的 onResume。

这是错的。

真正感知生命周期的是 Activity。

ViewModel 只是被 Activity 调了一个普通方法。

它和下面这个按钮点击本质一样:

button.setOnClickListener {
    viewModel.onLoginClick()
}

onPageResume() 这个名字虽然带了 Resume,但它不是生命周期回调。

它只是你自己定义的一个普通方法:

fun onPageResume() {
    loadData()
}

ViewModel 并不知道:

  • Activity 是否真的执行了 onResume;
  • 当前页面是否可见;
  • Activity 是不是在前台;
  • Fragment 的 View 是否还存在。

它只知道:

外部调用了我的 onPageResume() 方法,我开始执行业务。

所以准确说法是:

不是 ViewModel 监听了生命周期,而是 UI 层监听生命周期后,主动通知 ViewModel。


三、最容易混淆的点 2:observe(this) 不是 ViewModel 感知生命周期

很多人看到:

viewModel.count.observe(this) { count ->
    tvCount.text = count.toString()
}

就会以为:

ViewModel 拿到了 Activity,所以 ViewModel 可以感知 Activity 生命周期。

这也是错的。

这里的 this 不是传给 ViewModel 的,而是传给 LiveData 的。

完整理解应该是:

viewModel.count.observe(this) { }

等价于:

从 viewModel 里拿到 count 这个 LiveData
        ↓
调用 LiveData 的 observe 方法
        ↓
把 Activity 作为 LifecycleOwner 传给 LiveData
        ↓
LiveData 根据 Activity 生命周期决定什么时候分发数据

也就是说:

感知生命周期的是 LiveData,不是 ViewModel。

ViewModel 只是持有了一个 LiveData 对象:

class MainViewModel : ViewModel() {

    private val _count = MutableLiveData<Int>()
    val count: LiveData<Int> = _count
}

Activity 观察它:

viewModel.count.observe(this) { count ->
    tvCount.text = count.toString()
}

ViewModel 不知道谁在观察,也不知道 Activity 当前是 onResume、onPause 还是 onDestroy。


四、最容易混淆的点 3:两个 this 不是同一个含义

在 ViewModel 相关代码里,常见两个 this

1. ViewModelProvider(this)

val viewModel = ViewModelProvider(this)[MainViewModel::class.java]

或者:

private val viewModel: MainViewModel by viewModels()

这里的 this 表示:

这个 ViewModel 归哪个 Activity / Fragment 的 ViewModelStore 管理。

它的作用是找到 ViewModel 的存放仓库。

它不是把 Activity 传进 ViewModel。


2. observe(this)

viewModel.count.observe(this) { }

这里的 this 表示:

LiveData 根据这个 LifecycleOwner 的生命周期来分发和解绑数据。

它是给 LiveData 用的。

它也不是给 ViewModel 用的。


所以这两个 this 要分清:

代码 this 给谁用 作用
ViewModelProvider(this) ViewModelProvider / ViewModelStore 决定 ViewModel 归谁管理
observe(this) LiveData 根据生命周期分发和解绑数据

一句话总结:

ViewModelProvider(this) 的 this 是用来找仓库;observe(this) 的 this 是用来控制观察者生命周期。它们都不是让 ViewModel 持有 Activity。


五、最容易混淆的点 4:UI → ViewModel 和 ViewModel → UI 不要反过来理解

正确方向是:

生命周期、点击、输入、刷新等事件:
UI → ViewModel

比如:

override fun onResume() {
    super.onResume()
    viewModel.onPageResume()
}
数据、状态、结果:
ViewModel → UI

比如:

viewModel.uiState.observe(this) { state ->
    render(state)
}

错误理解是:

ViewModel 主动监听 Activity 生命周期
ViewModel 主动调用 Activity 更新 UI

这种写法不推荐:

class MainViewModel(
    private val activity: Activity
) : ViewModel() {

    fun updateUI() {
        activity.findViewById<TextView>(R.id.tvName).text = "hello"
    }
}

这样会导致:

  • ViewModel 持有 Activity;
  • 配置变更时旧 Activity 无法释放;
  • 容易内存泄漏;
  • ViewModel 和 UI 强耦合;
  • 单元测试困难。

正确做法是:

class MainViewModel : ViewModel() {

    private val _uiState = MutableLiveData<String>()
    val uiState: LiveData<String> = _uiState

    fun loadData() {
        _uiState.value = "hello"
    }
}

Activity 观察:

viewModel.uiState.observe(this) { text ->
    tvName.text = text
}

六、最容易混淆的点 5:onPageResume() 里面能不能直接更新 UI?

不建议。

比如这样写就不合适:

class MainViewModel : ViewModel() {

    fun onPageResume() {
        textView.text = "刷新成功"
    }
}

ViewModel 不应该知道 TextView。

正确写法是:

class MainViewModel : ViewModel() {

    private val _uiState = MutableLiveData<String>()
    val uiState: LiveData<String> = _uiState

    fun onPageResume() {
        loadData()
    }

    private fun loadData() {
        _uiState.value = "刷新成功"
    }
}

Activity:

viewModel.uiState.observe(this) { text ->
    tvContent.text = text
}

也就是说:

UI 通知 VM:页面 resume 了
        ↓
VM 执行业务:刷新数据
        ↓
VM 更新 LiveData
        ↓
UI 观察数据:更新页面

ViewModel 可以决定“页面应该显示什么状态”,但不应该直接操作“具体哪个 View 怎么显示”。


七、最容易混淆的点 6:viewModelScope 不是页面生命周期作用域

很多人会把这三者混到一起:

lifecycleScope
viewModelScope
LiveData.observe(this)

它们的生命周期绑定对象不同。

1. viewModelScope

viewModelScope.launch {
    loadData()
}

它绑定的是 ViewModel。

ViewModel 被销毁时,协程取消。

也就是说,只有:

onCleared()

执行时,它才会自动取消。

它不会因为 Activity 执行:

onPause()
onStop()

就自动停止。


2. lifecycleScope

lifecycleScope.launch {
    // do something
}

它绑定的是 Activity / Fragment 的 Lifecycle。

但是注意,普通 lifecycleScope.launch 也不是在 onStop 自动取消,它通常会在 Lifecycle Destroyed 时取消。

如果想要 STARTED 开始、STOPPED 停止,应该用:

lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        // collect flow
    }
}

3. LiveData.observe(this)

viewModel.data.observe(this) { }

LiveData 会根据 LifecycleOwner 的状态分发数据。

页面销毁时会自动移除观察者。


总结表:

写法 绑定对象 主要作用
viewModelScope ViewModel ViewModel 销毁时取消协程
lifecycleScope Activity/Fragment 生命周期销毁时取消协程
observe(this) LifecycleOwner LiveData 按生命周期分发数据

八、最容易混淆的点 7:Fragment 里不要随便用 observe(this)

Activity 中可以这样:

viewModel.data.observe(this) { data ->
    render(data)
}

但是 Fragment 中更推荐:

viewModel.data.observe(viewLifecycleOwner) { data ->
    render(data)
}

不要随便写:

viewModel.data.observe(this) { data ->
    render(data)
}

原因是 Fragment 有两个生命周期:

  1. Fragment 自身生命周期;
  2. Fragment 的 View 生命周期。

Fragment 的 View 可能已经销毁了,但是 Fragment 自己还没销毁。

如果你用 this,观察者可能还在,但 ViewBinding 已经置空了,容易出现:

  • 空指针;
  • 重复观察;
  • UI 更新异常;
  • 内存泄漏。

所以 Fragment 中观察 LiveData,一般写:

viewModel.data.observe(viewLifecycleOwner) { data ->
    binding.tvContent.text = data
}

九、完整代码串起来理解

ViewModel

class MainViewModel : ViewModel() {

    private val _count = MutableLiveData<Int>()
    val count: LiveData<Int> = _count

    private var currentCount = 0

    fun onPageResume() {
        refreshCount()
    }

    fun onPagePause() {
        // 页面暂停时,做一些业务处理
        // 比如停止轮询、保存状态等
    }

    private fun refreshCount() {
        currentCount++
        _count.value = currentCount
    }
}

Activity

class MainActivity : AppCompatActivity() {

    private val viewModel: MainViewModel by viewModels()

    private lateinit var tvCount: TextView

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

        tvCount = findViewById(R.id.tvCount)

        observeData()

        addLifecycleObserver()
    }

    private fun observeData() {
        viewModel.count.observe(this) { count ->
            tvCount.text = "count = $count"
        }
    }

    private fun addLifecycleObserver() {
        lifecycle.addObserver(object : DefaultLifecycleObserver {

            override fun onResume(owner: LifecycleOwner) {
                viewModel.onPageResume()
            }

            override fun onPause(owner: LifecycleOwner) {
                viewModel.onPagePause()
            }
        })
    }
}

这段代码完整体现了两个方向:

1. UI → ViewModel
Activity onResume
        ↓
viewModel.onPageResume()
        ↓
ViewModel 刷新 count
2. ViewModel → UI
ViewModel 更新 count LiveData
        ↓
LiveData 通知 Activity
        ↓
Activity 更新 TextView

MVVM 里要分清两个方向。

第一,页面生命周期事件是 UI 层自己的能力,比如 Activity 的 onResume、onPause。ViewModel 不能主动感知这些生命周期。如果业务需要在 onResume 时刷新数据,应该由 Activity 或 Fragment 监听生命周期,然后主动调用 viewModel.onPageResume()。这属于 UI → ViewModel。

第二,ViewModel 执行业务后会更新 LiveData,Activity 通过 observe(this) 观察数据变化。这里的 this 是传给 LiveData 的 LifecycleOwner,作用是让 LiveData 根据页面生命周期自动分发和解绑数据,不是让 ViewModel 持有 Activity。这个方向属于 ViewModel → UI。

所以,ViewModel 不感知页面生命周期,也不直接操作 UI。UI 负责感知生命周期和渲染页面,ViewModel 负责处理业务和暴露状态。


十一、一句话记忆

生命周期事件从 UI 进 ViewModel,数据状态从 ViewModel 回 UI。

再简化:

UI 负责感知事件
VM 负责处理业务
LiveData 负责通知变化
UI 负责渲染页面

核心区别:

onResume 调 vm 方法:UI → VM,是事件通知
observe LiveData:VM → UI,是数据通知
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇