You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android聊天Activity销毁重启后出现白屏问题求助

问题

我的应用中Chat Activity在销毁后(未关闭应用)重新启动时,会显示1-2秒的白屏。尝试在应用主题中添加<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>未生效,将init()函数移至后台线程也没有解决问题。以下是onCreate()和onStart()方法代码,需要优化启动性能:

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityChatBinding.inflate(layoutInflater)
        setContentView(binding.root)
        when (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
            Configuration.UI_MODE_NIGHT_YES -> {}
            Configuration.UI_MODE_NIGHT_NO -> {}
        }
        //setSupportActionBar(chatToolbar)
        init()
        Handler().postDelayed({
            init()
        }, 10)
        audioRecordView = AudioRecordView()
        audioRecordView.initView(findViewById<View>(R.id.layoutMain) as FrameLayout)
        val containerView = audioRecordView.setContainerView(R.layout.layout_chatting)
        record = layoutInflater.inflate(R.layout.record_view, null)
        audioRecordView.recordingListener = this
        uName = containerView?.findViewById(R.id.chatUserName)!!
        uImage = containerView.findViewById(R.id.chatUserImg)!!
        uPresence = containerView.findViewById(R.id.chatUserPresence)
        recyclerView = containerView.findViewById(R.id.recyclerViewMessages)
        addContacts()

        EmojiManager.install(
            GoogleCompatEmojiProvider(
                EmojiCompat.init(
            FontRequestEmojiCompatConfig(
                this,
                FontRequest(
                    "com.google.android.gms.fonts",
                    "com.google.android.gms",
                    "Noto Color Emoji Compat",
                    R.array.com_google_android_gms_fonts_certs,
                )
            ).setReplaceAll(true)
                )
            )
        )
        //EmojiManager.install(FacebookEmojiProvider())
        //EmojiManager.install(TwitterEmojiProvider())
        val rootView = findViewById<View>(R.id.layoutMain)
        emojiPopup = EmojiPopup(rootView, audioRecordView.messageView!!)
        if (emojiPopup.isShowing){
            audioRecordView.emojiView?.setImageResource(R.drawable.ic_keyboard)
        } else {
            audioRecordView.emojiView?.setImageResource(R.drawable.emoji_ic)
        }

        //Record
        val filePath:String = externalCacheDir?.absolutePath + "/audioFile.wav"
        waveRecorder = WaveRecorder(filePath)

        waveRecorder.onStateChangeListener = {
            when (it) {
                RecorderState.RECORDING -> startRecording()
                RecorderState.STOP -> stopRecording()
                RecorderState.PAUSE -> pauseRecording()
            }
        }
        waveRecorder.onTimeElapsed = {
            Log.e(TAG, "onCreate: time elapsed $it")
        }

        //Chat
        messages = ArrayList()
        senderRoom = senderUid+receiverUid
        receiverRoom = receiverUid+senderUid
        setTxtDataToAdapter()
        //setImgDataToAdapter()
        setRecyclerView()
        //setListeners()
        setListener()
        //audioRecordView.messageView!!.requestFocus()
        val profileL = containerView.findViewById<View>(R.id.userImgNameL)
        val backBtn = containerView.findViewById<View>(R.id.single_ChatBack)
        profileL?.setOnClickListener{}
        backBtn?.setOnClickListener{ finish() }

        audioRecordView.setAttachmentOptions(AttachmentOption.defaultList, this)
        audioRecordView.removeAttachmentOptionAnimation(false)
        audioRecordView.removeAttachmentOptionAnimation(false)
    }
override fun onStart() {
    super.onStart()
    val currentId = FirebaseAuth.getInstance().uid
    val presence = hashMapOf<String, Any>("presence" to "Online")
    val state = hashMapOf<String, Any>("state" to "available")
    firestore.collection("Users").document(currentId!!).update(presence)
    firestore.collection("Contacts").document(userId).collection("rooms")
        .document(currentId).update(state)
    val seen = hashMapOf<String, Any>("seen" to "true")
    firestore.collection("Chats").document(senderRoom!!)
        .collection("messages").document().update(seen)
    firestore.collection("Chats").document(receiverRoom!!)
        .collection("messages").document().update(seen)
}
优化方案

1. 移除重复初始化操作

代码中init()被重复调用两次,直接删除延迟调用的冗余代码:

// 删除这段重复初始化代码
Handler().postDelayed({
    init()
}, 10)

2. 异步初始化EmojiCompat

EmojiCompat初始化涉及字体加载,属于耗时操作,必须放到后台线程执行,避免阻塞主线程:

// 替换原EmojiManager初始化代码
lifecycleScope.launch(Dispatchers.IO) {
    val config = FontRequestEmojiCompatConfig(
        this@ChatActivity,
        FontRequest(
            "com.google.android.gms.fonts",
            "com.google.android.gms",
            "Noto Color Emoji Compat",
            R.array.com_google_android_gms_fonts_certs,
        )
    ).setReplaceAll(true)
    EmojiCompat.init(config)
    EmojiManager.install(GoogleCompatEmojiProvider(EmojiCompat.get()))
    // 初始化完成后若需更新UI,切换回主线程
    withContext(Dispatchers.Main) {
        updateEmojiButtonState()
    }
}

3. 优化视图查找与布局加载

  • 利用已有的ActivityChatBinding替代findViewById,减少视图查找耗时;
  • 延迟加载非核心视图(如录音面板),等到需要使用时再初始化:
// 移除onCreate中的record初始化代码,改为在startRecording中加载
private fun startRecording() {
    if (record == null) {
        record = layoutInflater.inflate(R.layout.record_view, null)
        // 绑定录音面板的视图逻辑
    }
    // 原有录音启动逻辑
}

4. 合并Firestore批量更新

onStart中的多次Firestore操作可合并为批量写,减少网络请求次数:

override fun onStart() {
    super.onStart()
    val currentId = FirebaseAuth.getInstance().uid ?: return
    val batch = firestore.batch()
    
    // 更新在线状态
    batch.update(firestore.collection("Users").document(currentId), mapOf("presence" to "Online"))
    batch.update(firestore.collection("Contacts").document(userId).collection("rooms").document(currentId), mapOf("state" to "available"))
    
    // 批量更新消息已读状态(修正原代码空文档更新的问题)
    firestore.collection("Chats").document(senderRoom!!).collection("messages")
        .whereEqualTo("seen", false)
        .get()
        .addOnSuccessListener { snapshot ->
            snapshot.documents.forEach { doc ->
                batch.update(doc.reference, mapOf("seen" to true))
            }
            firestore.collection("Chats").document(receiverRoom!!).collection("messages")
                .whereEqualTo("seen", false)
                .get()
                .addOnSuccessListener { receiverSnapshot ->
                    receiverSnapshot.documents.forEach { doc ->
                        batch.update(doc.reference, mapOf("seen" to true))
                    }
                    batch.commit()
                }
        }
}

5. 解决启动白屏问题

白屏源于Activity启动时窗口背景未设置,修改Chat Activity专属主题:

<!-- styles.xml中定义主题 -->
<style name="Theme.ChatActivity" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- 设置与聊天界面匹配的窗口背景 -->
    <item name="android:windowBackground">@color/colorPrimary</item>
    <item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
</style>

在AndroidManifest.xml中为Chat Activity指定该主题:

<activity
    android:name=".ChatActivity"
    android:theme="@style/Theme.ChatActivity"/>

6. 延迟非核心初始化

将WaveRecorder、EmojiPopup等非立即需要的初始化移至onResume,减少onCreate执行时间:

override fun onResume() {
    super.onResume()
    // 初始化WaveRecorder
    if (waveRecorder == null) {
        val filePath: String = externalCacheDir?.absolutePath + "/audioFile.wav"
        waveRecorder = WaveRecorder(filePath)
        waveRecorder.onStateChangeListener = {
            when (it) {
                RecorderState.RECORDING -> startRecording()
                RecorderState.STOP -> stopRecording()
                RecorderState.PAUSE -> pauseRecording()
            }
        }
        waveRecorder.onTimeElapsed = {
            Log.e(TAG, "onResume: time elapsed $it")
        }
    }
    
    // 初始化EmojiPopup
    if (emojiPopup == null && audioRecordView.messageView != null) {
        val rootView = binding.layoutMain
        emojiPopup = EmojiPopup(rootView, audioRecordView.messageView!!)
        updateEmojiButtonState()
    }
}

// 提取表情按钮状态更新为单独方法
private fun updateEmojiButtonState() {
    audioRecordView.emojiView?.setImageResource(
        if (emojiPopup?.isShowing == true) R.drawable.ic_keyboard else R.drawable.emoji_ic
    )
}

内容的提问来源于stack exchange,提问作者Mahmoud Nabil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 01:53:00