Java Android ViewModel和Firebase获取空列表
我正在使用一个ViewModel架构和一个Firebase实时数据库来管理我的应用程序的数据 应用程序描述: 有飞溅活动、登录活动、游戏活动和排行榜活动。在splash活动中检索一次完整的用户数据,以检查用户在成功检索时是否具有internet连接,登录活动是否打开或绕过游戏活动。排行榜活动可以从LoginActivity和GameAcility打开 问题: 每当我尝试从GameActivity打开排行榜时,总会返回一个空列表。然而,当我从LoginActivity打开它时,这个问题从未出现过。然而,如果我曾经登录,然后从firebase控制台更改数据库数据,我确实会在排行榜中得到一个非空列表 我试过什么?: 调试并记录存储库代码,以发现当我从GameActivity到达LeadboardActivity时,onDataChange()从未在LeadboardActivity中调用,但是ViewModel调用按预期进行 我还尝试使用model.getUsers().getValue()检索列表但返回null 代码: GameViewModel.java GameActivity.java LeaderboardActivity.javaJava Android ViewModel和Firebase获取空列表,java,android,firebase,firebase-realtime-database,mvvm,Java,Android,Firebase,Firebase Realtime Database,Mvvm,我正在使用一个ViewModel架构和一个Firebase实时数据库来管理我的应用程序的数据 应用程序描述: 有飞溅活动、登录活动、游戏活动和排行榜活动。在splash活动中检索一次完整的用户数据,以检查用户在成功检索时是否具有internet连接,登录活动是否打开或绕过游戏活动。排行榜活动可以从LoginActivity和GameAcility打开 问题: 每当我尝试从GameActivity打开排行榜时,总会返回一个空列表。然而,当我从LoginActivity打开它时,这个问题从未出现过。
公共类排行榜活动扩展了AppCompative活动{
列表用户=新建ArrayList();
回收视图回收视图;
排行榜回收适配器;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_排行榜);
适配器=新的排行榜回收适配器(用户);
recyclerView=findViewById(R.id.rv);
recyclerView.setLayoutManager(新的LinearLayoutManager(本));
recyclerView.setAdapter(适配器);
GameViewModel模型=(新ViewModelProvider(this)).get(GameViewModel.class);
model.getUsers().observe(这个,u->{
user.clear();
users.addAll(u);
adapter.notifyDataSetChanged();
});
}
}
LoginActivity.java
公共类LoginActivity扩展了AppCompatActivity{
意图;
博弈模型;
List userList=new ArrayList();
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity\u登录);
sharedPref=getSharedPreferences(
SP_密钥,上下文。模式_专用);
model=(新ViewModelProvider(this)).get(GameViewModel.class);
model.getUsers().observe(这个,u->{
userList=u;
});
}
私有void setListeners(){
ivleadboard.setOnClickListener(新视图.OnClickListener(){
@凌驾
公共void onClick(视图){
意图=新意图(LoginActivity.this、leadboardActivity.class);
星触觉(意向);
覆盖转换(0,0);
}
});
btnLogin.setOnClickListener(新视图.OnClickListener(){
@凌驾
公共void onClick(视图){
登录();
}
});
}
私有void登录(){
//登录检查在这里
意图=新意图(这个,GameActivity.class);
星触觉(意向);
}
}
假设代码适用于其他功能,则删除了此问题不需要的部分。在活动销毁之前手动删除附加到FirebaseReference的侦听器可以解决问题。早期的实现是在ViewModel生命周期之后进行的,因此从技术上讲,侦听器被附加并随后被删除,因此列表为空 代码更改: GameViewModel.java XyzActivity.java
请包含与问题相关的最小可运行代码,而不是整个应用程序的转储,以供其他人尝试和调试。很可能,您会发现在侦听器被取消时生成了一个错误,这可能是因为它是在身份验证完成解析之前建立的。@Kato谢谢您的建议,我缩短了代码!
public class GameViewModel extends ViewModel implements DataRetrievedInterface {
private MutableLiveData<List<User>> users;
private GameRepository repository = GameRepository.getInstance(this);
public LiveData<List<User>> getUsers() {
if (users == null) {
users = new MutableLiveData<>();
loadUsers();
}
return users;
}
private void loadUsers() {
repository.retrieveData();
}
private void loadUsers(List<User> result) {
users.setValue(result);
}
public void addUser(User user) {
List<User> us = users.getValue();
assert us != null;
us.add(user);
repository.addUser(us);
users.postValue(us);
}
@Override
public void notifyDataRetrieved(List<User> result) {
loadUsers(result);
}
@Override
protected void onCleared() {
super.onCleared();
repository.removeListener();
}
public void updateScore(String userName, Long score) {
repository.updateScore(userName, score);
}
}
public class GameRepository {
public final FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("Users");
public DataRetrievedInterface retrievedInterface;
private static GameRepository repository = null;
ValueEventListener eventListener;
private GameRepository(DataRetrievedInterface retrievedInterface) {
this.retrievedInterface = retrievedInterface;
}
public static GameRepository getInstance(DataRetrievedInterface retrievedInterface) {
if(repository==null)
repository = new GameRepository(retrievedInterface);
repository.eventListener = (new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
List<User> users = new ArrayList<>();
for(DataSnapshot snapshot1:snapshot.getChildren()) {
users.add(snapshot1.getValue(User.class));
}
retrievedInterface.notifyDataRetrieved(users);
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
Log.e("Database Error", error.getMessage());
}
});
return repository;
}
public void retrieveData() {
ref.addValueEventListener(eventListener);
}
public void removeListener() {
ref.removeEventListener(eventListener);
}
public void addUser(List<User> user) {
ref.setValue(user);
}
public void updateScore(String userName, Long score) {
// assume temp is a one time listener for updating value in db
ref.addListenerForSingleValueEvent(temp);
}
}
public class SplashActivity extends AppCompatActivity {
Intent intent;
GameViewModel model;
Boolean isDataReady = false;
Boolean isAnimationDone = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
model = (new ViewModelProvider(this)).get(GameViewModel.class);
model.getUsers().observe(this, u -> {
isDataReady = true;
if(isAnimationDone) {
startActivity(intent);
}
});
}
private void initViewsAndVars() {
intent = new Intent(this, LoginActivity.class);
intent = new Intent(SplashActivity.this, GameActivity.class);
if(isDataReady) {
startActivity(intent);
}
}
}
public class GameActivity extends AppCompatActivity implements GameStatusInterface {
GamePlay gamePlay;
GameViewModel model;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
gamePlay = new GamePlay(this, screenWidth, screenHeight);
btnLeader = findViewById(R.id.btnLeaderGame);
model = (new ViewModelProvider(this)).get(GameViewModel.class);
btnLeader.setOnClickListener(view -> {
Intent intent = new Intent(this, LeaderboardActivity.class);
startActivity(intent);
overridePendingTransition(0,0);
});
}
@Override
public void onGameEnded(Long score) {
model.updateScore(userName, current + score);
}
}
public class LeaderboardActivity extends AppCompatActivity {
List<User> users = new ArrayList<>();
RecyclerView recyclerView;
LeaderboardRecyclerAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_leaderboard);
adapter = new LeaderboardRecyclerAdapter(users);
recyclerView = findViewById(R.id.rv);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
GameViewModel model = (new ViewModelProvider(this)).get(GameViewModel.class);
model.getUsers().observe(this, u -> {
users.clear();
users.addAll(u);
adapter.notifyDataSetChanged();
});
}
}
public class LoginActivity extends AppCompatActivity {
Intent intent;
GameViewModel model;
List<User> userList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
sharedPref = getSharedPreferences(
SP_KEY, Context.MODE_PRIVATE);
model = (new ViewModelProvider(this)).get(GameViewModel.class);
model.getUsers().observe(this, u -> {
userList = u;
});
}
private void setListeners() {
ivLeaderboard.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
intent = new Intent(LoginActivity.this, LeaderboardActivity.class);
startActivity(intent);
overridePendingTransition(0,0);
}
});
btnLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
login();
}
});
}
private void login() {
// Login Checks Here
intent = new Intent(this, GameActivity.class);
startActivity(intent);
}
}
public void removeListener() {
repository.removeListener();
}
@Override
protected void onCleared() {
super.onCleared();
}
model.removeListener();
startActivity(intent);