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

在Kotlin Composable中调用JNI函数startOsc()遇未解析引用问题

解决Composable中调用startOsc()出现Unresolved reference的问题

问题场景

在MainActivity中定义了private external fun startOsc(),但在独立的Composable组件TwoNotesView中调用时触发Unresolved reference: startOsc错误。MainActivity内部调用该函数正常,startEngine()和stopEngine()也能正常执行,JNI层实现无问题。

核心原因

Composable函数TwoNotesView处于独立作用域,无法直接访问MainActivity类的私有成员函数,必须通过合理方式将函数引用传递到Composable的作用域中。

解决方案

方案1:直接传递函数引用(最简单)

修改TwoNotesView让它接收函数类型参数,在MainActivity调用Composable时传入::startOsc:

// MainActivity中修改setContent部分
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
        TwoNotesView(onReplayClick = ::startOsc)
    }
    startEngine()
}

// 修改TwoNotesView Composable
@Composable
fun TwoNotesView(onReplayClick: () -> Unit) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(colorResource(id = R.color.cyan))
    ) {
        Row {
            Box (
                modifier = Modifier
                    .clickable {
                        onReplayClick() // 调用传递进来的函数
                    }
            ) {
                AnswerButton(ImageSource = R.drawable.round_replay_24_cyan)
            }
        }
    }
}

方案2:使用ViewModel中转(适合复杂业务场景)

如果后续有更多音频控制逻辑,建议用ViewModel封装,避免直接在Composable中依赖Activity实例:

// 创建AudioViewModel
class AudioViewModel(private val startOscAction: () -> Unit) : ViewModel() {
    fun startOsc() {
        startOscAction()
    }
}

// MainActivity中初始化ViewModel
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val audioViewModel = ViewModelProvider(this, object : ViewModelProvider.Factory {
        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            return AudioViewModel(::startOsc) as T
        }
    })[AudioViewModel::class.java]
    
    setContent {
        TwoNotesView(viewModel = audioViewModel)
    }
    startEngine()
}

// 修改TwoNotesView
@Composable
fun TwoNotesView(viewModel: AudioViewModel) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(colorResource(id = R.color.cyan))
    ) {
        Row {
            Box (
                modifier = Modifier
                    .clickable {
                        viewModel.startOsc()
                    }
            ) {
                AnswerButton(ImageSource = R.drawable.round_replay_24_cyan)
            }
        }
    }
}

方案3:转为静态函数(仅当逻辑允许时)

如果startOsc不需要依赖MainActivity实例,可以将其移到companion object中转为静态函数:

class MainActivity : ComponentActivity() {
    private external fun startEngine()
    private external fun stopEngine()

    companion object {
        init {
            System.loadLibrary("pitch_andoid")
        }
        private external fun startOsc()
        // 提供公开的调用入口
        fun triggerStartOsc() = startOsc()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            TwoNotesView()
        }
        startEngine()
    }

    override fun onDestroy() {
        super.onDestroy()
        stopEngine()
    }
}

// 在Composable中调用
@Composable
fun TwoNotesView() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(colorResource(id = R.color.cyan))
    ) {
        Row {
            Box (
                modifier = Modifier
                    .clickable {
                        MainActivity.triggerStartOsc()
                    }
            ) {
                AnswerButton(ImageSource = R.drawable.round_replay_24_cyan)
            }
        }
    }
}

验证说明

三种方案都能解决Unresolved reference问题,其中方案1最适合简单场景,方案2更符合Jetpack Compose的架构设计理念,方案3仅适用于无实例依赖的JNI函数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 23:15:01