【问题标题】:Why is setting onClickListener working once?为什么设置 onClickListener 工作一次?
【发布时间】:2017-11-13 16:25:08
【问题描述】:

我想将我使用的一个非常可靠的项目结构迁移到 Kotlin。我首先尝试了基础知识:活动和片段事务。它看起来如此简单:

class MainActivity : AppCompatActivity(), SomeInterface {
     override fun onCreate(savedInstanceState: Bundle?) {
         setContentView(R.layout.activity_main)

         val mainFragment = supportFragmentManager.findFragmentById(R.id.fragment_main) as MainActionsFragment?
                    ?: MainActionsFragment.newInstance()
         supportFragmentManager.inTransaction {
              add(R.id.container_main, mainFragment)
         }
    }

    private val anotherFragment by lazy {
    supportFragmentManager.findFragmentById(R.id.another_fragment) as AnotherFragment?
            ?: AnotherFragment.newInstance()
    }

    override fun myInterfaceMethod() {
        replaceFragment(anotherFragment, R.id.container_main)
    }
}

class MainActionsFragment : Fragment() {
    val btnSale: Button by bindView(R.id.btn_sale)
    val btnVisit: Button by bindView(R.id.btn_visit)

    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater!!.inflate(R.layout.fragment_main, container, false)
    }

    override fun onResume() {
        super.onResume()

        btnSale.setOnClickListener{ _ ->
            listener.requestAction(SaleType.SALE)
        }

        btnVisit.setOnClickListener{ _ ->
            listener.requestAction(SaleType.VISIT)
        }
    }
}

Extensions.kt

fun AppCompatActivity.replaceFragment(fragment: Fragment, @IdRes frameId: Int) {
    supportFragmentManager.inTransaction {
        replace(frameId, fragment)
                .addToBackStack(fragment.tag)
    }
}

inline fun FragmentManager.inTransaction(func: FragmentTransaction.() -> FragmentTransaction) {
    beginTransaction()
            .func()
            .commit()
}

现在,MainActionsFragment 拥有两个按钮。一切都按预期工作,第一次单击任何一个都会将我带到所需的片段。但是,一旦我按下后退按钮并再次看到我的两个按钮,它们的点击监听器就消失了。这几乎是转换为 Kotlin 的标准做事方式,除了酷炫的新功能外,没有什么特别的。我尝试将 onClickListeners 设置为onCreateView(),但它崩溃了:

原因:kotlin.KotlinNullPointerException 在 kotterknife.ButterKnifeKt$viewFinder$7.invoke(ButterKnife.kt:95) 在 kotterknife.ButterKnifeKt$viewFinder$7.invoke(ButterKnife.kt) 在 kotterknife.ButterKnifeKt$required$1.invoke(ButterKnife.kt:104) 在 kotterknife.ButterKnifeKt$required$1.invoke(ButterKnife.kt) 在 kotterknife.Lazy.getValue(ButterKnife.kt:125)

因此,尽管 Kotlin 非常酷,但我在做基础知识时遇到了麻烦,而且我对迁移感到沮丧。我真的做错事了吗?或者为什么设置一个简单的点击监听器会如此令人沮丧?

谢谢。

【问题讨论】:

标签: android android-fragments kotlin kotlin-android-extensions


【解决方案1】:

您必须将 ButterKnife 绑定的变量设置为 lateinit var 而不是 val。试试看

@BindView(R.id.btn_sale)
lateinit var title: Button

@BindView(R.id.btn_visit)
lateinit var title: Button

【讨论】:

  • 我正在使用 Kotterknife,如果我将其更改为 var 则会出错
  • 啊,对不起。我猜你不能在onCreate 中添加监听器,因为那时还没有创建按钮。也许您可以将它们添加到onViewCreated?我不太习惯 Fragments,但 onResume 仅在调用 Activity 的 onResume 时才被调用,这可能是它们第一次工作的原因,因为那是在创建 Activity 时而不是在同一时间创建的其他 Fragment不会调用onResume 的活动?
  • 我没有将它们移至onCreate(),而是移至onCreateView()。我想念 Kotlin 的 @OnClick,但 Jake 说没有计划这样做
  • 是的,我是想写onCreateView。尝试将听众移至onViewCreated,看看是否可行。
  • 所以我切换到普通的 ButterKnife,现在它说 lateinit vars 没有被初始化。我试图在 MainActivity 中的ButterKnife.bind(this) 之后立即使用它们,是否有特殊的方法需要放置它?
【解决方案2】:

解决方法:去掉KotterKnifeButterKnife,使用android的findViewById来解决。我猜想语言的优势之一和框架的进步使一些库过时或不必要。

【讨论】:

    猜你喜欢
    • 2012-03-09
    • 2011-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-21
    • 2019-10-08
    • 1970-01-01
    • 2017-05-29
    相关资源
    最近更新 更多