Firebase数据无法在App启动时显示于HomeFragment的问题
问题描述
我希望将Firebase数据库中的用户名展示在HomeFragment中。当前在MainActivity中从Firebase获取数据后传递给目标Fragment,但App启动时Fragment不显示数据库数据,切换其他Fragment再返回后才会显示。
MainActivity 代码
package com.shariarunix.examiner; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import android.annotation.SuppressLint; import android.os.Bundle; import android.util.Log; import android.view.MenuItem; import android.widget.Toast; import com.google.android.material.bottomnavigation.BottomNavigationView; import com.google.android.material.navigation.NavigationBarView; 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 java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private String uniqueKey; private String userName, userEmail, userPhone, userCourse; List<StudentDataModel> sDataList = new ArrayList<>(); BottomNavigationView navBottom; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Default Fragment loadFrag(HomeFragment.getInstance(userName, userCourse), 0); Toast.makeText(MainActivity.this, ""+userName+" : "+userCourse, Toast.LENGTH_SHORT).show(); // Add Operation on Bottom Navigation Bar navBottom = findViewById(R.id.nav_bar); navBottom.getMenu().findItem(R.id.home).setChecked(true); navBottom.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() { @SuppressLint("NonConstantResourceId") @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { switch (item.getItemId()){ case R.id.profile: // Loading Profile Fragment loadFrag(new ProfileFragment(), 1); break; case R.id.home: // Load Home Fragment loadFrag(HomeFragment.getInstance(userName,userCourse), 1); break; case R.id.resource: // Load R loadFrag(new ResourceFragment(sDataList), 1); Toast.makeText(MainActivity.this, "Resource", Toast.LENGTH_SHORT).show(); break; default: Toast.makeText(MainActivity.this, "Bonk", Toast.LENGTH_SHORT).show(); } return true; } }); } //Swapping Fragment public void loadFrag(Fragment fragment, int flag){ FragmentManager fragManager = getSupportFragmentManager(); FragmentTransaction fragTrans = fragManager.beginTransaction(); if (flag == 0){ fragTrans.add(R.id.fragment_frame, fragment); }else{ fragTrans.replace(R.id.fragment_frame, fragment); } fragTrans.commit(); } // Load Data from database public void loadData(){ DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference(); mDatabase.child("Student's Data").child(uniqueKey).addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { sDataList.clear(); StudentDataModel sData = snapshot.getValue(StudentDataModel.class); assert sData != null; userName = sData.getName(); userEmail = sData.getEmail(); userPhone = sData.getPhone(); userCourse = sData.getCourse(); sDataList.add(sData); } @Override public void onCancelled(@NonNull DatabaseError error) { Toast.makeText(MainActivity.this, "Hoy nai", Toast.LENGTH_SHORT).show(); } }); } @Override protected void onStart() { super.onStart(); uniqueKey = getIntent().getStringExtra("uniqueKey"); loadData(); } }
HomeFragment 代码
package com.shariarunix.examiner; import android.content.Intent; import android.os.Bundle; import androidx.appcompat.widget.AppCompatButton; import androidx.fragment.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import java.util.ArrayList; import java.util.List; public class HomeFragment extends Fragment { private static final String U_NAME = "uName"; private static final String U_COURSE = "uCourse"; private String uName, uCourse; public HomeFragment(){ //Default Empty Constructor } public static HomeFragment getInstance(String uName, String uCourse){ HomeFragment homeFragment = new HomeFragment(); Bundle bundle = new Bundle(); bundle.putString(U_NAME, uName); bundle.putString(U_COURSE, uCourse); homeFragment.setArguments(bundle); return homeFragment; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_home, container, false); TextView txtShowName = view.findViewById(R.id.txt_show_name_home); AppCompatButton btnExamReadMore = view.findViewById(R.id.btn_exam_read_more); if (getArguments()!= null){ uName = getArguments().getString(U_NAME); uCourse = getArguments().getString(U_COURSE); } txtShowName.setText(uName); btnExamReadMore.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { startActivity(new Intent(getActivity(), ExamInfoActivity.class)); } }); return view; } }
问题原因
Firebase数据获取是异步操作:
- App启动时,
onCreate方法先加载了HomeFragment,但此时loadData还在后台请求数据,userName和userCourse都是空值 - 切换Fragment返回时,Firebase已经完成数据加载,
userName已有有效值,所以Fragment能正常显示内容
解决方案
方案一:Activity控制数据加载后更新Fragment
通过保留Fragment引用,在Firebase数据加载完成后初始化或更新Fragment的UI:
修改后的MainActivity代码
package com.shariarunix.examiner; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import android.annotation.SuppressLint; import android.os.Bundle; import android.view.MenuItem; import android.widget.Toast; import com.google.android.material.bottomnavigation.BottomNavigationView; import com.google.android.material.navigation.NavigationBarView; 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 java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private String uniqueKey; private String userName, userEmail, userPhone, userCourse; List<StudentDataModel> sDataList = new ArrayList<>(); BottomNavigationView navBottom; private HomeFragment homeFragment; // 保留Fragment引用 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化底部导航 navBottom = findViewById(R.id.nav_bar); navBottom.getMenu().findItem(R.id.home).setChecked(true); navBottom.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() { @SuppressLint("NonConstantResourceId") @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { switch (item.getItemId()){ case R.id.profile: loadFrag(new ProfileFragment(), 1); break; case R.id.home: homeFragment = HomeFragment.getInstance(userName,userCourse); loadFrag(homeFragment, 1); break; case R.id.resource: loadFrag(new ResourceFragment(sDataList), 1); Toast.makeText(MainActivity.this, "Resource", Toast.LENGTH_SHORT).show(); break; default: Toast.makeText(MainActivity.this, "Bonk", Toast.LENGTH_SHORT).show(); } return true; } }); } public void loadFrag(Fragment fragment, int flag){ FragmentManager fragManager = getSupportFragmentManager(); FragmentTransaction fragTrans = fragManager.beginTransaction(); if (flag == 0){ fragTrans.add(R.id.fragment_frame, fragment); }else{ fragTrans.replace(R.id.fragment_frame, fragment); } fragTrans.commit(); } public void loadData(){ DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference(); mDatabase.child("Student's Data").child(uniqueKey).addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { sDataList.clear(); StudentDataModel sData = snapshot.getValue(StudentDataModel.class); assert sData != null; userName = sData.getName(); userEmail = sData.getEmail(); userPhone = sData.getPhone(); userCourse = sData.getCourse(); sDataList.add(sData); // 数据加载完成后初始化或更新Fragment if (homeFragment == null) { homeFragment = HomeFragment.getInstance(userName, userCourse); loadFrag(homeFragment, 0); } else { homeFragment.updateUserInfo(userName, userCourse); } Toast.makeText(MainActivity.this, ""+userName+" : "+userCourse, Toast.LENGTH_SHORT).show(); } @Override public void onCancelled(@NonNull DatabaseError error) { Toast.makeText(MainActivity.this, "Hoy nai", Toast.LENGTH_SHORT).show(); } }); } @Override protected void onStart() { super.onStart(); uniqueKey = getIntent().getStringExtra("uniqueKey"); loadData(); } }
修改后的HomeFragment代码
添加UI更新方法,供Activity调用:
package com.shariarunix.examiner; import android.content.Intent; import android.os.Bundle; import androidx.appcompat.widget.AppCompatButton; import androidx.fragment.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import java.util.ArrayList; import java.util.List; public class HomeFragment extends Fragment { private static final String U_NAME = "uName"; private static final String U_COURSE = "uCourse"; private String uName, uCourse; private TextView txtShowName; // 保留TextView引用 public HomeFragment(){ //Default Empty Constructor } public static HomeFragment getInstance(String uName, String uCourse){ HomeFragment homeFragment = new HomeFragment(); Bundle bundle = new Bundle(); bundle.putString(U_NAME, uName); bundle.putString(U_COURSE, uCourse); homeFragment.setArguments(bundle); return homeFragment; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_home, container, false); txtShowName = view.findViewById(R.id.txt_show_name_home); AppCompatButton btnExamReadMore = view.findViewById(R.id.btn_exam_read_more); if (getArguments()!= null){ uName = getArguments().getString(U_NAME); uCourse = getArguments().getString(U_COURSE); txtShowName.setText(uName); } btnExamReadMore.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { startActivity(new Intent(getActivity(), ExamInfoActivity.class)); } }); return view; } // 供Activity调用的UI更新方法 public void updateUserInfo(String name, String course) { this.uName = name; this.uCourse = course; if (txtShowName != null) { txtShowName.setText(uName); } } }
方案二:Fragment自主监听Firebase数据(解耦性更好)
让Fragment直接获取并监听Firebase数据,无需Activity传递:
@Override public void onStart() { super.onStart(); if (getActivity() != null) { String uniqueKey = getActivity().getIntent().getStringExtra("uniqueKey"); DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference(); mDatabase.child("Student's Data").child(uniqueKey).addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { StudentDataModel sData = snapshot.getValue(StudentDataModel.class); if (sData != null) { txtShowName.setText(sData.getName()); } } @Override public void onCancelled(@NonNull DatabaseError error) { Toast.makeText(getActivity(), "加载失败", Toast.LENGTH_SHORT).show(); } }); } }
方案对比
- 方案一:适合需要在多个Fragment共享同一数据的场景,由Activity统一管理数据
- 方案二:Fragment自主管理数据,解耦性更强,适合单个Fragment独立使用数据的场景
内容的提问来源于stack exchange,提问作者Shariar Nafiz
相关产品推荐
相关产品推荐

