compose开发中的问题与解决方案

前言:

本文主要记录Compose开发过程中遇到的问题,以及解决方案。


一、开发

1、崩溃 AndroidRuntime: FATAL EXCEPTION

在fragmen.xml添加ComposeView控件并在Fragment的onViewCreated()方法中调用’mBinding.vCompose.setContent {}’ 导致APP崩溃;
崩溃信息

2022-02-14 10:43:15.686 15864-15864/? E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.***.***, PID: 15864
    java.lang.NoSuchMethodError: No virtual method setContent(Lkotlin/jvm/functions/Function0;)V in class Landroidx/compose/ui/platform/ComposeView; or its super classes (declaration of 'androidx.compose.ui.platform.ComposeView' appears in /data/app/com.***.***-sVGybdTDL2rvz-Fc4EzVSA==/base.apk)
        at com.***.***.ui.MainFragment.initView(MainFragment.kt:78)
        at com.***.***.ui.BaseFragment.onViewCreated(BaseFragment.kt:55)
        at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:3047)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:551)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:261)
        at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:113)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1387)
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2876)
        at androidx.fragment.app.FragmentManager.dispatchViewCreated(FragmentManager.java:2802)
        at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:3048)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:551)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:261)
        at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:113)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1387)
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2876)
        at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:2809)
        at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:262)
        at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:445)
        at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:246)
        at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1521)
        at android.app.Activity.performStart(Activity.java:7838)
        at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3399)
        at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
        at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2110)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7697)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)

原因
是没有启用Compose;
解决方法: build.gradle(:app)文件中配置以下内容:

composeOptions{
        kotlinCompilerExtensionVersion "$compose_version"
        kotlinCompilerVersion kotlin_version
    }
    buildFeatures{
        // 启用Jetpack Compose
        compose true
    }

由于使用的kotlin_version是1.6.10版本,compose_version也要升级至’1.1.0’。


2、下载文件至相册

1、MANAGE_EXTERNAL_STORAGE权限

  • Android 11 新权限MANAGE_EXTERNAL_STORAGE,并且此权限只能跳至设置页开启;
  • 在Android13, WRITE_EXTERNAL_STORAGE权限会失效;
  • Android 11+ 请配置清单权限
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
  • 判断是否开启MANAGE_EXTERNAL_STORAGE权限;
if (Build.VERSION.SDK_INT >= 30) {
            if (!Environment.isExternalStorageManager()) {
                val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
                startActivity(intent)
                return
            }
            mLoadingDialog?.show(activity.supportFragmentManager, "loading")
            startDownloadVideo("${mVideoInfo!!.works_video_id}.mp4")
            return
        }

3、WebView 闪白屏

表现:进入含有webView的页面,白屏,同时会闪烁;如图所示,定义webView为红色区域大小,但加载后,却导致全屏背景白色,在滑动网页后,白色才会消失。

此问题仅compose页面会出现,传统xml布局页面无此问题。

在这里插入图片描述

解决方案:给WebView之外包一层Surface用来控制大小,则不会导致“整页白屏”了,示例代码如下。

Surface(modifier = Modifier.padding(50.dp)){
        val webViewState = rememberWebViewState(url = url)
        WebView(state = webViewState)
}

4、IDEA 运行Compose For Desktop桌面项目报错

错误信息

ComposeComponentRegistrar has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0

原因:

项目SDK版本与gradle的java 运行时版本不匹配导致的。

解决方案:

在idea设置中修改gradle JVM 版本。 我这里项目使用的JDK 17, 所以也改为17即可。如下图所示:

在这里插入图片描述

5、IDEA 运行Compose For Desktop桌面项目报错

错误信息

warning: default scripting plugin is disabled: The provided plugin org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar is not compatible with this version of compiler
error: unable to evaluate script, no scripting plugin loaded

原因:

运行当前文件不是程序入口。

解决方案:

切换到Main.kt选项卡,再次点击“运行”。如下图所示:

在这里插入图片描述

6、在TV中,左右切换焦点,列表会上下跳动

问题描述:
在TV中,左右切换焦点,列表会上下跳动;
也就是使用animateFloatAsState将缩放应用于TvLazyRow中的列表项会使布局在Y轴上移动;

解决方法:

  • TV-Compose库现在提供 ,并且可以处理缩放,而不会遇到此问题的控件:Cards Buttons Surface
  • 解决此问题的另一种方法是避免直接用scale修饰符,应使用scale在drawWithContent修饰语中。
@Composable
fun Modifier.scaleOnFocus(
    scaleOnFocus: Float,
    animationSpec: AnimationSpec<Float> = tween()
): Modifier {
    var isFocused by remember { mutableStateOf(false) }
    val scale by animateFloatAsState(
        targetValue = if (isFocused) scaleOnFocus else 1f,
        animationSpec = animationSpec,
        label = "scaleOnFocusScaleAnimation"
    )
    return this
        .onFocusChanged { isFocused = it.isFocused }
        .drawWithContent {
            scale(scale) {
                this@drawWithContent.drawContent()
            }
        }
}

参考链接:https://issuetracker.google.com/issues/283654247

7、FocusRequester 移动焦点崩溃!!!

常用的焦点移动方法

Modifier.focusProperties {
            up = upRequester()
            left = leftRequester()
            right = rightRequester()
        }

但,经常会遇到移动焦点崩溃,一般日志会有以下提示:

java.lang.IllegalStateException:
FocusRequester is not initialized. Here are some possible fixes:

【1】Remember the FocusRequester: val focusRequester = remember { FocusRequester() }
【2】Did you forget to add a Modifier.focusRequester() ?
【3】Are you attempting to request focus during composition? Focus requests should be made in
response to some event. Eg Modifier.clickable { focusRequester.requestFocus() }

上面已给出三种可能引发的原因,但也没指出具体代码位置,需要结合页面逻辑进一步分析、猜测;
另外再补充两个坑
【4】如果item焦点FocusRequester()实例在item Data数据bean里创建,List列表内item之间移动焦点,当列表Data刷新时,up\left\right等方向的焦点也要同步更新。
以下为 伪代码示例

/** item数据 */
data class ItemInfo(
	val id: String = "",
	val requester: FocusRequester = FocusRequester()
)

// 在Item UI中remember 焦点
val focusRequester = remember { itemInfo.requester }
// 使用焦点
Modifier.focusRequester(focusRequester )

【5】itemData数据没变, 但compose列表重组,移动焦点也会崩溃;原因界面重组时未触发remember重新执行,所以要给它设置key,可以是多个;当key发生变化时,则会触发remember(key)。
修改后代码如下:

val focusRequester = remember(itemInfo.requester) {
        itemInfo.requester
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

两块三刀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值