android - 智能投射到“DrawerLayout!” 是不可能的,因为 'drawerLayout' 是一个可变属性,此时可能已更改
问题描述
我是 android 开发的完全新手,过去两天我一直被这个问题困扰,我的生活中从未感到如此沮丧。先来个小故事,
我正在创建最基本的图书库应用程序,并尝试向应用程序添加导航抽屉。在 kotlin 文件中,当我使用lateinit声明所有变量(对应于布局文件中创建的标签)时,它会抛出一个nullPointerException。出于这个原因,我开始像这样声明我的变量:
var drawerLayout: DrawerLayout? = null
这有助于我避免异常。现在来到真正的问题,
我试图以这种方式在 onCreate 方法中为我的 actionBarDrawerToggle创建一个单击侦听器:
val actionBarDrawerToggle = ActionBarDrawerToggle(this@MainActivity, drawerLayout, R.string.open_drawer, R.string.close_drawer)
drawerLayout.addDrawerListener(actionBarDrawerToggle)
actionBarDrawerToggle.syncState()
并且由于某种原因,“drawerLayout.addDrawerListener(actionBarDrawerToggle)”行的drawerLayout部分带有红色下划线,表示存在错误。当我运行它时,这是它在构建窗口中显示的错误:
Smart cast to 'DrawerLayout!' is impossible, because 'drawerLayout' is a mutable property that could have been changed by this time
我不知道如何进行此操作。我已经尝试了很多东西,但它们都不起作用。我认为该错误可能与我上面描述的我使用的声明方法有关。如果有人可以帮助我,那就太好了
解决方案
您已将其定义drawerLayout
为可空 ( DrawerLayout?
) var
,这意味着该值可以随时更改,并且该值可以为空。因此,即使您进行空检查以确保它不为空,也可能随时改变!编译器无法保证调用是安全的。
以下是一些选项,从坏到好:
通过引用将变量显式标记为非空drawerLayout!!
。这是你告诉编译器“我知道发生了什么,这很好,相信我”。您应该避免这样做,因为这是一个危险信号,您会忽略警告,最终您会遇到错误的情况
将非空值复制到一个临时变量中,你知道它不会改变。这是在 Kotlin 中处理可空值的典型方法,您可以使用以下范围函数之一let
:
drawerLayout?.let { drawer -> // do stuff with drawer }
那是在做一个空检查(使用?
),如果它不为空,它会调用let
具有该非空值的块。而且您知道该值在块内不会改变。我已经调用了该变量drawer
,但您可以省略它,it
默认情况下会调用它。还有其他范围功能,例如run
,做同样事情的方式略有不同。
如果您只需要这样做,您也可以只调用检查变量本身:
drawerLayout?.doAThingItsNotNullSoItsFine()
这基本上在引擎盖下做同样的事情
首先不要使drawerLayout
nullable !它实际上永远不应该为空,对吧?它应该始终存在,并且在您尝试访问它时具有价值?然后为自己省去仇恨和一直对它进行空检查的需要——这就是lateinit
目的。
lateinit
允许你声明一个变量而不实际给它一个值。通常你必须这样做,这就是你在这里所做的正确 - 你已经让它可以为空,这样你就可以在那里粘贴一个临时的空值。lateinit
是对编译器的一个承诺,它没关系,你还没有提供一个值,但你肯定会在任何尝试访问它之前设置一个值。(这就是为什么它被称为后期初始化!)
因此,您遇到的问题是在尝试读取它之前您实际上并没有设置该值。您可以检查它是否已设置为::drawerLayout.isInitialized
,但实际上您应该充分了解您的代码流程,以确保只有在初始化之后才能读取。如果您不能保证这一点,那么您可能处于一种状态,即您没有其他东西可能需要访问的变量的值 - 这是使其可空并使用空处理功能的一个很好的候选者顺利处理
推荐阅读
- spring - 如何在同一个spring boot项目中使用EhCache(本地)和RedisCache(远程)?
- android-studio - 无法激活 intellij 产品上的快捷方式
- javascript - 如何使用与至少一个匹配的字符串数组过滤数据?
- c# - 如何禁用回车键
- ios - 当应用程序语言与系统语言不同时更改iOS系统提示语言
- ruby-on-rails - 每个线程的“单例”
- javascript - Thingsboard_导航到新仪表板状态_Widget 自定义操作_Javascript 代码
- c# - 从仅包含不同项目的两个列表创建新列表?
- excel - 合并方法 - VBA
- css - BEM 中的元素是否需要在块内?