从Firebase取数后无法设置到Navigation Drawer导航头TextView的问题
问题:Firebase获取数据后无法设置到导航头的TextView,应用崩溃
我成功从Firebase Realtime Database获取了用户数据,Toast能正常显示这些数据,但当我尝试把数据设置到导航抽屉头部的TextView时,应用直接崩溃。去掉设置文本的代码后一切正常,请问该怎么解决这个问题?
导航头XML (nav_header.xml)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="@dimen/nav_header_height" android:background="@drawable/header" android:gravity="bottom" android:orientation="vertical" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingBottom="@dimen/activity_vertical_margin" android:theme="@style/ThemeOverlay.AppCompat.Dark"> <ImageView android:id="@+id/imageView" android:layout_width="80dp" android:layout_height="80dp" android:contentDescription="@string/nav_header_desc" android:paddingTop="@dimen/nav_header_vertical_spacing" app:srcCompat="@drawable/user_icon" /> <TextView android:id="@+id/holder_nav_text_username" android:layout_width="wrap_content" android:textSize="14sp" android:layout_height="wrap_content" android:textColor="#ffffff" android:paddingTop="@dimen/nav_header_vertical_spacing" android:textAppearance="@style/TextAppearance.AppCompat.Body1" /> <TextView android:id="@+id/holder_nav_text_email" android:textColor="#ffffff" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/holder_nav_text_phone" android:textColor="#ffffff" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
主Activity代码 (Dashboard.java)
package com.example.closeup; import android.os.Bundle; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.snackbar.Snackbar; import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.navigation.NavController; import androidx.navigation.Navigation; import androidx.navigation.ui.AppBarConfiguration; import androidx.navigation.ui.NavigationUI; import com.google.android.material.navigation.NavigationView; import com.google.firebase.auth.FirebaseAuth; import com.google.firebase.auth.FirebaseUser; import com.google.firebase.database.DataSnapshot; import com.google.firebase.database.DatabaseError; import com.google.firebase.database.DatabaseReference; import com.google.firebase.database.FirebaseDatabase; import com.google.firebase.database.ValueEventListener; import androidx.drawerlayout.widget.DrawerLayout; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import android.view.Menu; import android.widget.TextView; import android.widget.Toast; public class Dashboard extends AppCompatActivity { private AppBarConfiguration mAppBarConfiguration; FirebaseUser fuser; DatabaseReference dref,dr; String uid; TextView r_username,r_email,r_phone; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_interface); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = findViewById(R.id.fab); fuser= FirebaseAuth.getInstance().getCurrentUser(); uid=fuser.getUid(); dref= FirebaseDatabase.getInstance().getReference("Users"); // 这里直接findViewById会找不到导航头里的TextView r_username=findViewById(R.id.holder_nav_text_username); r_email=findViewById(R.id.holder_nav_text_email); r_phone=findViewById(R.id.holder_nav_text_phone); dref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot dataSnapshot) { String c_username=dataSnapshot.child(uid).child("name").getValue(String.class); String c_email=dataSnapshot.child(uid).child("email").getValue(String.class); String c_phone=dataSnapshot.child(uid).child("phone").getValue(String.class); Toast.makeText(getApplicationContext(),"Your ID: " + uid,Toast.LENGTH_SHORT).show(); Toast.makeText(getApplicationContext(),"Your Name: " + c_username,Toast.LENGTH_SHORT).show(); Toast.makeText(getApplicationContext(),"Your email: " + c_email,Toast.LENGTH_SHORT).show(); Toast.makeText(getApplicationContext(),"Your phone: " + c_phone,Toast.LENGTH_SHORT).show(); // 尝试设置文本导致崩溃 // r_username.setText(c_username); // r_email.setText(c_email); // r_phone.setText(c_phone); } @Override public void onCancelled(@NonNull DatabaseError databaseError) { } }); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } }); DrawerLayout drawer = findViewById(R.id.drawer_layout); NavigationView navigationView = findViewById(R.id.nav_view); mAppBarConfiguration = new AppBarConfiguration.Builder( R.id.nav_home,R.id.nav_tools, R.id.nav_share,R.id.nav_mealentry, R.id.nav_send,R.id.nav_interfaced) .setDrawerLayout(drawer) .build(); NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment); NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration); NavigationUI.setupWithNavController(navigationView, navController); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.interfacee,menu); return true; } @Override public boolean onSupportNavigateUp() { NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment); return NavigationUI.navigateUp(navController, mAppBarConfiguration) || super.onSupportNavigateUp(); } }
问题原因
你直接调用findViewById()去获取导航头里的TextView是行不通的,因为这些TextView并不属于Activity的主布局,而是嵌套在NavigationView的header布局里。直接查找会返回null,当你调用setText()时就会触发NullPointerException,导致应用崩溃。
修复步骤
- 先获取NavigationView的header视图:通过
NavigationView.getHeaderView(0)方法获取导航头的根视图(参数0是因为导航头是第一个header,如果你有多个header需要对应调整)。 - 通过header视图查找TextView:用获取到的header视图去调用
findViewById(),这样才能正确找到导航头里的控件。 - 调整代码顺序:确保在获取header视图之后再初始化TextView变量,避免空指针。
修改后的代码
调整onCreate()方法中的代码顺序,修改后的关键部分如下:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_interface); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = findViewById(R.id.fab); fuser= FirebaseAuth.getInstance().getCurrentUser(); uid=fuser.getUid(); dref= FirebaseDatabase.getInstance().getReference("Users"); // 先初始化NavigationView并获取header视图 DrawerLayout drawer = findViewById(R.id.drawer_layout); NavigationView navigationView = findViewById(R.id.nav_view); // 获取导航头的根视图 View headerView = navigationView.getHeaderView(0); // 通过headerView查找导航头里的TextView r_username= headerView.findViewById(R.id.holder_nav_text_username); r_email= headerView.findViewById(R.id.holder_nav_text_email); r_phone= headerView.findViewById(R.id.holder_nav_text_phone); dref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot dataSnapshot) { String c_username=dataSnapshot.child(uid).child("name").getValue(String.class); String c_email=dataSnapshot.child(uid).child("email").getValue(String.class); String c_phone=dataSnapshot.child(uid).child("phone").getValue(String.class); Toast.makeText(getApplicationContext(),"Your ID: " + uid,Toast.LENGTH_SHORT).show(); Toast.makeText(getApplicationContext(),"Your Name: " + c_username,Toast.LENGTH_SHORT).show(); Toast.makeText(getApplicationContext(),"Your email: " + c_email,Toast.LENGTH_SHORT).show(); Toast.makeText(getApplicationContext(),"Your phone: " + c_phone,Toast.LENGTH_SHORT).show(); // 现在可以安全设置文本了 if(c_username != null) r_username.setText(c_username); if(c_email != null) r_email.setText(c_email); if(c_phone != null) r_phone.setText(c_phone); } @Override public void onCancelled(@NonNull DatabaseError databaseError) { Toast.makeText(getApplicationContext(),"Failed to load user data",Toast.LENGTH_SHORT).show(); } }); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } }); mAppBarConfiguration = new AppBarConfiguration.Builder( R.id.nav_home,R.id.nav_tools, R.id.nav_share,R.id.nav_mealentry, R.id.nav_send,R.id.nav_interfaced) .setDrawerLayout(drawer) .build(); NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment); NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration); NavigationUI.setupWithNavController(navigationView, navController); }
额外建议
- 加上空值判断:从Firebase获取的数据可能为
null,设置文本前先判断可以避免潜在的崩溃。 - 在
onCancelled()里添加错误提示:方便调试和告知用户数据加载失败。
内容的提问来源于stack exchange,提问作者Mamun Nayeem
相关产品推荐
相关产品推荐

