You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SQLite数据库变更后RecyclerView无法自动更新UI的问题求助

SQLite数据库变更后RecyclerView无法自动更新UI的问题求助

我现在在做一个安卓应用,其中有个Fragment需要展示某场赛事任务里的可用人员,原本期望数据库新增或删除人员时UI能自动同步更新,但目前只有Fragment刚创建时才会加载显示人员列表,后续数据库有任何增删操作,UI完全没反应。我不想改用Room,打算继续用原生SQLite来实现,下面是我的相关代码,求各位帮忙看看问题出在哪,怎么修改才能实现自动更新?

我的TeamViewModel代码

public class TeamViewModel extends AndroidViewModel {
    private static final String TAG = "TeamViewModel";

    private TeamRepository teamRepository;
    private MutableLiveData<PlayerTeam> playersLiveData;

    public TeamViewModel(Application application) {
        super(application);
        Log.d(TAG, "Initializing TeamViewModel");

        // Initialize repository and LiveData        
        teamRepository = new TeamRepository(new DatabaseHelper(application));
        playersLiveData = new MutableLiveData<>();

        Log.d(TAG, "TeamViewModel initialized successfully");
    }

    public LiveData<PlayerTeam> getPlayersForMatch(int matchId) {
        Log.d(TAG, "getPlayersForMatch called with matchId: " + matchId);

        // Fetch players from the repository in a background thread        
        new Thread(() -> {
            try {
                Log.d(TAG, "Fetching players from repository for matchId: " + matchId);
                PlayerTeam playerTeam = teamRepository.getPlayersForMatch(matchId);

                if (playerTeam == null) {
                    Log.e(TAG, "PlayerTeam fetched is null for matchId: " + matchId);
                } else {
                    Log.d(TAG, "PlayerTeam fetched successfully for matchId: " + matchId);
                    Log.d(TAG, "Team 1 Players Count: " + playerTeam.getTeam1Players().size());
                    for (Player player : playerTeam.getTeam1Players()) {
                        Log.d(TAG, "Team 1 Player: " + player.toString());
                    }

                    Log.d(TAG, "Team 2 Players Count: " + playerTeam.getTeam2Players().size());
                    for (Player player : playerTeam.getTeam2Players()) {
                        Log.d(TAG, "Team 2 Player: " + player.toString());
                    }
                }
                // Post the fetched data to LiveData                
                playersLiveData.postValue(playerTeam);
            } catch (Exception e) {
                Log.e(TAG, "Error while fetching players for matchId: " + matchId, e);
            }
        }).start();

        Log.d(TAG, "Returning playersLiveData for matchId: " + matchId);
        return playersLiveData;
    }
}

我的PlayerAdapter代码

public class PlayerAdapter extends RecyclerView.Adapter<PlayerAdapter.PlayerViewHolder> {
    private List<Player> players;

    // Constructor to accept List<Player>    
    public PlayerAdapter(List<Player> players) {
        this.players = players;
    }

    @NonNull    
    @Override    
    public PlayerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_player, parent, false);
        return new PlayerViewHolder(view);
    }

    @Override    
    public void onBindViewHolder(@NonNull PlayerViewHolder holder, int position) {
        Player player = players.get(position);
        holder.bind(player);
    }

    @Override    
    public int getItemCount() {
        return players != null ? players.size() : 0;
    }

    // Method to update the dataset and notify the RecyclerView    
    public void updatePlayers(List<Player> newPlayers) {
        DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffUtil.Callback() {
            @Override            
            public int getOldListSize() {
                return players != null ? players.size() : 0;
            }

            @Override            
            public int getNewListSize() {
                return newPlayers != null ? newPlayers.size() : 0;
            }

            @Override            
            public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
                // Assuming Player has a unique identifier like ID                
                return players.get(oldItemPosition).getPlayerId() == newPlayers.get(newItemPosition).getPlayerId();
            }

            @Override            
            public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
                // Compare content equality                
                return players.get(oldItemPosition).equals(newPlayers.get(newItemPosition));
            }
        });

        // Update the dataset        
        this.players = newPlayers;
        // Notify RecyclerView of changes        
        diffResult.dispatchUpdatesTo(this);
    }

    // ViewHolder class    
    public static class PlayerViewHolder extends RecyclerView.ViewHolder {
        private TextView playerName;

        public PlayerViewHolder(@NonNull View itemView) {
            super(itemView);
            playerName = itemView.findViewById(R.id.playerNameView);
        }

        public void bind(Player player) {
            playerName.setText(player.getName());
        }
    }
}

我的Fragment代码

@Override    
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Log.d(TAG, "onCreateView called");
        // Inflate the layout for the fragment        
        View view = inflater.inflate(R.layout.activity_mp_teams, container, false);
        Log.d(TAG, "Layout inflated successfully");
        // SharedPreferences for team names        
        if (getActivity() != null) {
            sharedPreferences = requireContext().getSharedPreferences("match_prefs", Context.MODE_PRIVATE);
        }
        // Initialize RecyclerViews and TextViews for team names        
        team1RecyclerView = view.findViewById(R.id.team1PlayerRecyclerView);
        team2RecyclerView = view.findViewById(R.id.team2PlayerRecyclerView);
        TextView teamATextView = view.findViewById(R.id.team1TextView);
        TextView teamBTextView = view.findViewById(R.id.team2TextView);
        // Set team names in TextViews from SharedPreferences        
        String teamAName = sharedPreferences.getString("teamAName", "");
        String teamBName = sharedPreferences.getString("teamBName", "");
        teamATextView.setText(teamAName);
        teamBTextView.setText(teamBName);
        // Set GridLayoutManager for RecyclerViews (4 columns per team)        
        team1RecyclerView.setLayoutManager(new GridLayoutManager(getContext(), 4));
        team2RecyclerView.setLayoutManager(new GridLayoutManager(getContext(), 4));
        // Initialize adapters with empty lists        
        team1Adapter = new PlayerAdapter(new ArrayList<>());
        team2Adapter = new PlayerAdapter(new ArrayList<>());
        // Set adapters to RecyclerViews        
        team1RecyclerView.setAdapter(team1Adapter);
        team2RecyclerView.setAdapter(team2Adapter);
        // Initialize ViewModel        
        teamViewModel = new ViewModelProvider(this).get(TeamViewModel.class);
        Log.d(TAG, "onCreateView completed");
        return view;
    }
    
    @Override    
    public void onResume() {
        super.onResume();
        Log.d(TAG, "onResume called");
        matchId = sharedPreferences.getLong("currentMatchId", -1);
        teamViewModel.getPlayersForMatch((int) matchId).observe(getViewLifecycleOwner(), playerTeam -> {
            Log.d(TAG, "LiveData observed, updating UI");
            if (playerTeam != null) {
                List<Player> team1Players = playerTeam.getTeam1Players();
                List<Player> team2Players = playerTeam.getTeam2Players();
                Log.d(TAG, "Team 1 Players Count: " + team1Players.size());
                for (Player player : team1Players) {
                    Log.d(TAG, "Team 1 Player: " + player.toString());
                }
                // Update Team 1 Adapter                
                team1Adapter.updatePlayers(team1Players);
                Log.d(TAG, "Team 2 Players Count: " + team2Players.size());
                for (Player player : team2Players) {
                    Log.d(TAG, "Team 2 Player: " + player.toString());
                }
                team2Adapter.updatePlayers(team2Players);
            } else {
                Log.e(TAG, "PlayerTeam object is null");
            }
        });
        Log.d(TAG, "onResume completed");
    }
}

我自己分析的问题(可能不对)

现在的代码里,LiveData只在getPlayersForMatch被调用时才会去查一次数据库,但是数据库变了之后,完全没有通知LiveData去重新查询的机制,因为原生SQLite不像Room自带了数据变更监听。所以现在只是单次查询,不是持续监听。

求各位大佬帮忙给出具体的修改方案,让数据库增删人员后,UI能自动刷新!

备注:内容来源于stack exchange,提问作者Reddy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 17:34:49