Navigation Drawer Activity中OnClickListener崩溃,OnClick正常问题
导航抽屉Activity中使用OnClickListener崩溃问题解决
问题描述
在导航抽屉Activity的MainActivity.kt中,使用OnClickListener时应用启动即崩溃,但在onCreate函数外部使用XML绑定的OnClick方法时应用运行正常。编译无报错,但Logcat中存在空指针错误信息。
崩溃时的代码
package com.example.android.chatapplication import android.content.Intent import android.os.Bundle import android.view.Menu import android.view.View import android.widget.Button import android.widget.ImageButton import com.google.android.material.snackbar.Snackbar import com.google.android.material.navigation.NavigationView import androidx.navigation.findNavController import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.navigateUp import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupWithNavController import androidx.drawerlayout.widget.DrawerLayout import androidx.appcompat.app.AppCompatActivity import com.example.android.chatapplication.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { private lateinit var appBarConfiguration: AppBarConfiguration private lateinit var binding: ActivityMainBinding val loginbtn : Button = findViewById(R.id.loginButtonNavHeader) val addchannelbtn : ImageButton = findViewById(R.id.addChannelButton) val sendmessagebtn : ImageButton = findViewById(R.id.sendMessageBtn) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) setSupportActionBar(binding.appBarMain.toolbar) loginbtn.setOnClickListener { val loginIntent = Intent(this, LoginActivity::class.java) startActivity(loginIntent) } val drawerLayout: DrawerLayout = binding.drawerLayout val navView: NavigationView = binding.navView val navController = findNavController(R.id.nav_host_fragment_content_main) appBarConfiguration = AppBarConfiguration( setOf( R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow ), drawerLayout ) setupActionBarWithNavController(navController, appBarConfiguration) } }
Logcat错误信息
Process: com.example.android.chatapplication, PID: 6449 java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.example.android.chatapplication/com.example.android.chatapplication.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.ApplicationInfo android.content.Context.getApplicationInfo()' on a null object reference at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3637) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3896) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:140) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:100) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2326) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:263) at android.app.ActivityThread.main(ActivityThread.java:8296) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:612) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1006) Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.ApplicationInfo android.content.Context.getApplicationInfo()' on a null object reference at android.content.ContextWrapper.getApplicationInfo(ContextWrapper.java:183) at android.view.ContextThemeWrapper.getTheme(ContextThemeWrapper.java:174) at android.content.Context.obtainStyledAttributes(Context.java:744) at androidx.appcompat.app.AppCompatDelegateImpl.createSubDecor(AppCompatDelegateImpl.java:852) at androidx.appcompat.app.AppCompatDelegateImpl.ensureSubDecor(AppCompatDelegateImpl.java:819) at androidx.appcompat.app.AppCompatDelegateImpl.findViewById(AppCompatDelegateImpl.java:640) at androidx.appcompat.app.AppCompatActivity.findViewById(AppCompatActivity.java:261) at com.example.android.chatapplication.MainActivity.<init>(MainActivity.kt:25) at java.lang.Class.newInstance(Native Method) at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:95) at androidx.core.app.CoreComponentFactory.instantiateActivity(CoreComponentFactory.java:45) at android.app.Instrumentation.newActivity(Instrumentation.java:1254) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3625) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3896) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:140) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:100) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2326) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:263) at android.app.ActivityThread.main(ActivityThread.java:8296) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:612) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1006)
正常运行的代码
fun loginbtnclicked(view : View ){ val loginIntent = Intent(this, LoginActivity::class.java) startActivity(loginIntent) }
问题分析
崩溃的核心原因是在Activity实例初始化阶段(成员变量声明时)调用了findViewById:
- 类成员变量
loginbtn直接在类中通过findViewById赋值,这会在Activity实例创建时(onCreate执行前)执行,此时Activity的Context还未初始化,布局也未加载,findViewById依赖的上下文环境不存在,直接触发空指针异常。 - 而XML绑定的
android:onClick="loginbtnclicked"方法,只会在用户点击按钮时才会被调用,此时Activity已经完成初始化和布局加载,Context正常可用,因此不会崩溃。
解决方案
方案1:延迟初始化控件,在onCreate中赋值
将控件声明改为lateinit,在setContentView之后再初始化控件:
class MainActivity : AppCompatActivity() { private lateinit var appBarConfiguration: AppBarConfiguration private lateinit var binding: ActivityMainBinding private lateinit var loginbtn: Button private lateinit var addchannelbtn: ImageButton private lateinit var sendmessagebtn: ImageButton override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) // 初始化控件 loginbtn = findViewById(R.id.loginButtonNavHeader) addchannelbtn = findViewById(R.id.addChannelButton) sendmessagebtn = findViewById(R.id.sendMessageBtn) setSupportActionBar(binding.appBarMain.toolbar) loginbtn.setOnClickListener { val loginIntent = Intent(this, LoginActivity::class.java) startActivity(loginIntent) } // 导航相关代码 val drawerLayout: DrawerLayout = binding.drawerLayout val navView: NavigationView = binding.navView val navController = findNavController(R.id.nav_host_fragment_content_main) appBarConfiguration = AppBarConfiguration( setOf( R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow ), drawerLayout ) setupActionBarWithNavController(navController, appBarConfiguration) } }
方案2:使用ViewBinding直接获取控件
既然已经启用了ViewBinding,可直接通过binding对象获取控件,无需调用findViewById,更安全高效:
class MainActivity : AppCompatActivity() { private lateinit var appBarConfiguration: AppBarConfiguration private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) setSupportActionBar(binding.appBarMain.toolbar) // 获取导航头中的按钮 val loginbtn = binding.navView.getHeaderView(0).findViewById<Button>(R.id.loginButtonNavHeader) loginbtn.setOnClickListener { val loginIntent = Intent(this, LoginActivity::class.java) startActivity(loginIntent) } // 其他控件可直接通过binding获取(示例) // val addchannelbtn = binding.appBarMain.addChannelButton // addchannelbtn.setOnClickListener { ... } // 导航相关代码 val drawerLayout: DrawerLayout = binding.drawerLayout val navView: NavigationView = binding.navView val navController = findNavController(R.id.nav_host_fragment_content_main) appBarConfiguration = AppBarConfiguration( setOf( R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow ), drawerLayout ) setupActionBarWithNavController(navController, appBarConfiguration) } }
内容的提问来源于stack exchange,提问作者Ritik Rawat
相关产品推荐
相关产品推荐

