新的结果API错误:requestCode只能使用低16位

16

今天我切换到新的ResultAPI,却遇到了这个错误:

java.lang.IllegalArgumentException: Can only use lower 16 bits for requestCode
    at androidx.fragment.app.FragmentActivity.checkForValidRequestCode(FragmentActivity.java:715)
    at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:673)
    at androidx.core.app.ActivityCompat.startActivityForResult(ActivityCompat.java:234)
    at androidx.activity.ComponentActivity$2.onLaunch(ComponentActivity.java:207)
    at androidx.activity.result.ActivityResultRegistry$3.launch(ActivityResultRegistry.java:147)
    at androidx.activity.result.ActivityResultLauncher.launch(ActivityResultLauncher.java:42)
    at .MainActivity.getVideo(MainActivity.kt:61)
    at .MainActivity.access$getVideo(MainActivity.kt:18)
    at .MainActivity$onCreate$2.onClick(MainActivity.kt:42)
    at android.view.View.performClick(View.java:5232)
    at android.view.View$PerformClick.run(View.java:21289)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:168)
    at android.app.ActivityThread.main(ActivityThread.java:5885)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:797)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:687)

当执行以下代码时:

private val takeFile = registerForActivityResult(GetContent()) {
    Log.e("MainActivity", "fileName: $it")
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)

    btn_get_video.setOnClickListener {
        getVideo()
    }

}


private fun getVideo() {
    takeFile.launch("video/*")
}

使用这个新的result API,没有办法手动声明REQUEST_CODE

注意:
有时可以工作!

[更新]
我注册了多个合同(TakeVideo & GetContent),我发现注册的顺序很重要(第一个像魅力一样工作,但其他人会崩溃)。也许我们只需要为每个活动注册一个合同?!

[更新 #2]
问题已在最新版本的activity(1.2.7-alpha07)中解决。现在它会警告您添加与活动和片段相关的依赖项。


你的片段依赖版本是多少? - Saurabh Thorat
@Cristan,是的,但实际上不是。那个问题有一个精确描述问题来源的答案。但这里的REQUEST_CODE是由库生成的,而不是开发者。而且它一直生成错误的值。 - user28434'mstep
1
刚刚拿到了 1.2.0-beta01 版本,完全没有使用任何片段! - WindRider
1.2.0-beta01和1.2.0-alpha08出现了相同的错误。有人解决了吗? - Fahad Nasrullah
从我的有限测试来看,似乎即使您实际上不使用片段,也需要添加androidx.fragment库(请参见下文)。不知道为什么... - Eric Sellin
显示剩余3条评论
2个回答

29

添加或更新此依赖项:

implementation 'androidx.fragment:fragment:1.3.0'

使用ActivityResult API时,请使用此片段依赖项以确保与FragmentActivity兼容。


1
从 Activity 1.2.0-alpha07 开始,将会发出一个关于此的 "lint 警告"。 - Saurabh Thorat

4

我认为新的API出了问题。在ActivityResultRegistry中可以看到:

 /**
 * Generate a random number between the initial value (00010000) inclusive, and the max
 * integer value. If that number is already an existing request code, generate another until
 * we find one that is new.
 *
 * @return the number
 */
private int generateRandomNumber() {
    int number = mRandom.nextInt((Integer.MAX_VALUE - INITIAL_REQUEST_CODE_VALUE) + 1)
            + INITIAL_REQUEST_CODE_VALUE;
    while (mRcToKey.containsKey(number)) {
        number = mRandom.nextInt((Integer.MAX_VALUE - INITIAL_REQUEST_CODE_VALUE) + 1)
                + INITIAL_REQUEST_CODE_VALUE;
    }
    return number;
}

在调试模式下,我看到请求代码发送了 "1388473134"。现在让我们看看发生了什么。在这种情况下,我们正在使用框架提供的 ActivityResultRegistry。它会生成一个由框架持有的请求代码,并通过generateRandomNumberActivityResultRegistry生成。
请参阅Google框架androidx.activity中的ComponentActivity类。
private ActivityResultRegistry mActivityResultRegistry = new ActivityResultRegistry() {

    @Override
    public <I, O> void onLaunch(
            final int requestCode,
            @NonNull ActivityResultContract<I, O> contract,
            I input,
            @Nullable ActivityOptionsCompat options) {

            ...
            
        } else {
            // startActivityForResult path
            ActivityCompat.startActivityForResult(activity, intent, requestCode, optionsBundle);
        }
}
        

这将从FragmentActivity调用checkForValidRequestCode,并抛出异常(因为生成的请求代码过高)。
@Override
    public void startActivityForResult(@SuppressLint("UnknownNullness") Intent intent,
            int requestCode, @Nullable Bundle options) {
        // If this was started from a Fragment we've already checked the upper 16 bits were not in
        // use, and then repurposed them for the Fragment's index.
        if (!mStartedActivityFromFragment) {
            if (requestCode != -1) {
                checkForValidRequestCode(requestCode);
            }
        }
        super.startActivityForResult(intent, requestCode, options);
    }

为了解决该问题,您需要使用此方法的最新版本更新androidx.fragment.app中提供的checkForValidRequestCode源代码。在您的gradle文件中进行更新。
dependencies {
    def fragment_version = "1.3.0-beta02"

    // Java language implementation
    implementation "androidx.fragment:fragment:$fragment_version"
    // Kotlin
    implementation "androidx.fragment:fragment-ktx:$fragment_version"
    // Testing Fragments in Isolation
    debugImplementation "androidx.fragment:fragment-testing:$fragment_version"
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接