首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >因为currentInputConnection总是返回null

因为currentInputConnection总是返回null
EN

Stack Overflow用户
提问于 2022-04-01 23:50:32
回答 2查看 415关注 0票数 2

我正在为Android构建一个IME (输入法编辑器)。我知道我必须创建一个扩展InputMethodService的类,才能访问getCurrentInputConnection。我的理解是,这会将我返回到当前聚焦的文本字段,如果没有,则返回null。

我知道我必须做这样的事:

代码语言:javascript
复制
val focusedTextField = currentInputConnection ?: return

问题是,结果我总是得到null。我的理论是,文本编辑器(当前关注的文本字段)不承认我的应用程序是一个IME,或者可能“没有意识到”它正在被关注。所以也许我得提供更多的信息。我已经检查了声明服务和提供元数据的清单,一切似乎都是正确的。res/xml/method.xml文件是正确的。

这是清单文件。我被告知,从android 11开始,我们必须获得使用服务的位置许可。

代码语言:javascript
复制
<service
    android:name=".IMEService"
    android:label="Amazing Keyboard"
    android:foregroundServiceType="location"
    android:permission="android.permission.BIND_INPUT_METHOD"
    android:exported="true">
        <intent-filter>
            <action android:name="android.view.InputMethod" />
        </intent-filter>
        <meta-data
            android:name="android.view.im"
            android:resource="@xml/method" />
</service>

这是方法文件

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?>
<input-method xmlns:android="http://schemas.android.com/apk/res/android"
    android:settingsActivity="com.example.amazingkeyboard.MainActivity">
    <subtype
        android:name = "my app"
        android:label="English (U.S)"
        android:imeSubtypeLocale="en_US"
        android:imeSubtypeMode="keyboard"/>
</input-method>

这就是我所做的,我正在使用jetpack撰写,但这不是问题所在,因为我已经尝试返回一个xml视图,而且我总是有错误的。

代码语言:javascript
复制
class IMEService : InputMethodService(), LifecycleOwner, 
      ViewModelStoreOwner, SavedStateRegistryOwner {
  fun sendText(text : CharSequence, newCursorPosition : Int) {
    val focusedTextField = currentInputConnection ?: return //always returns null 
    focusedTextField.commitText(text, newCursorPosition) 
  } 
  ...
}

这就是我称之为方法的地方。

代码语言:javascript
复制
val connection = IMEService()
@Composable fun TestKey(modifier: Modifier = Modifier) {
  Key( 
    modifier = modifier .clickable { 
      connection.sendText(unicodeToString(0x1F436), 1)
}...

当我删除验证时。正如我前面所说的,问题是我总是得到null。显然,如果我进行验证,就不会出现错误,但是我也不能发送(因为我总是有空)。

代码语言:javascript
复制
// val focusedTextField = currentInputConnection ?: return
val focusedTextField = currentInputConnection

我有这个错误。

代码语言:javascript
复制
java.lang.NullPointerException:
Attempt to invoke interface method 'boolean android.view.inputmethod.InputConnection.commitText(java.lang.CharSequence, int)' on a null object reference
at com.chrrissoft.amazingkeyboard.IMEService.sendText(IMEService.kt:21)
at com.chrrissoft.amazingkeyboard.composables.GeneralKeysKt$TestKey$1.invoke(generalKeys.kt:32)
at com.chrrissoft.amazingkeyboard.composables.GeneralKeysKt$TestKey$1.invoke(generalKeys.kt:31)

这里是一个完整的项目,如果您想查看它的话。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-04-07 13:58:55

您将在以下代码的第二行获得NullPointerException

代码语言:javascript
复制
val focusedTextField = currentInputConnection
focusedTextField.commitText(text, newCursorPosition) 

因为当前活动的InputConnection没有绑定到输入方法,所以currentInputConnection是空的。

onBindInput中有一个InputConnection方法,当新客户机绑定到输入方法时调用该方法。在这个调用中,您知道currentInputConnection返回有效的对象。因此,在使用currentInputConnection之前,客户端应该绑定到输入方法。

要在类范围之外使用IMEService的公共方法,需要有绑定服务的实例。深入了解GitHub上的源代码,似乎很容易通过将IMEService传递给TestKey()函数来解决问题。整个代码如下所示:

代码语言:javascript
复制
@Composable
fun TestKey(modifier: Modifier = Modifier, connection: IMEService) {
    Key(
        modifier = modifier
            //...
            .clickable {
                connection.sendText(unicodeToString(0x1F383), 1)
            }
    ) {
        Icon(/*...*/)
    }
}

@Composable
fun EmojiLayout(navController: NavHostController, connection: IMEService) {

    val (currentPage, onPageChange) = remember {
        mutableStateOf(EmoticonsAndEmotionsPage)
    }

    Column(modifier = Modifier.fillMaxSize()) {
        EmojiPage(
            //...
        )
        Row(
            //...
        ) {
            //...
            TestKey(Modifier.weight(1f), connection)
        }
    }
}

@Composable
fun KeyboardScreen(connection: IMEService) {

    AmazingKeyboardTheme() {
        Column(
            //...
        ) {
            val navController = rememberNavController()
            NavHost(navController = navController, startDestination = "qwertyLayout") {
                //...
                composable("emojiLayout") { EmojiLayout(navController, connection) }
            }
        }
    }
}

class AndroidKeyboardView(context: Context) : FrameLayout(context) {

    constructor(service: IMEService) : this(service as Context) {
        inflate(service, R.layout.keyboard_view, this)
        findViewById<ComposeView>(R.id.compose_view).setContent {
            KeyboardScreen(connection = service)
        }
    }
}

IMEService类保持不变。

票数 2
EN

Stack Overflow用户

发布于 2022-04-02 09:41:20

我假设您遵循这个文档并完成了所有必要的设置,包括将IMEService添加到Android中。

代码语言:javascript
复制
val connection = IMEService()

不幸的是,您不能这样使用Service,您不能自己创建Service类的实例,并且依赖于它将正确工作。服务是由Android系统创建的。如果您想使用currentInputConnection属性,您应该在IMEService中使用它,或者您需要以某种方式将它的实例传递到您想要使用它的地方,或者如果您想要有IMEService服务的实例,则需要将绑定传递给它。也请参考Service

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71713785

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档