解决方案(最小修改):
1. 给CountryAdapter添加一个updateData方法:
public class ClientListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
// 添加操作监听接口
public interface OnDeviceActionListener {
void onBlockDevice(String deviceName, int position);
void onDeleteDevice(String deviceName, int position);
}
private OnDeviceActionListener listener;
// 设置监听器
public void setOnDeviceActionListener(OnDeviceActionListener listener) {
this.listener = listener;
}
}
// 在onBindViewHolder中修改长按事件
switch (status) {
case 0: // 在线设备
lineItem.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
TPPopupMenu popupMenu = new TPPopupMenu(lineItem.getContext(), v, R.menu.menu_block)
.setIconEnable(true);
// 添加菜单项点击监听器
popupMenu.setOnMenuItemClickListener(item -> {
if (item.getItemId() == R.id.menu_block) {
showBlockConfirmDialog(deviceName, position);
return true;
}
return false;
});
popupMenu.show();
return true;
}
});
break;
case 1: // 离线设备
lineItem.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
TPPopupMenu popupMenu = new TPPopupMenu(lineItem.getContext(), v, R.menu.menu_delete)
.setIconEnable(true);
popupMenu.setOnMenuItemClickListener(item -> {
if (item.getItemId() == R.id.menu_block) {
showBlockConfirmDialog(deviceName, position);
return true;
} else if (item.getItemId() == R.id.menu_delete) {
showDeleteConfirmDialog(deviceName, position);
return true;
}
return false;
});
popupMenu.show();
return true;
}
});
break;
}
// 显示拉黑确认对话框
private void showBlockConfirmDialog(String deviceName, int position) {
new androidx.appcompat.app.AlertDialog.Builder(context)
.setTitle("拉黑设备")
.setMessage("确定要将 \"" + deviceName + "\" 加入黑名单吗?")
.setPositiveButton("确定", (dialog, which) -> {
if (listener != null) {
listener.onBlockDevice(deviceName, position);
}
})
.setNegativeButton("取消", null)
.show();
}
// 显示删除确认对话框
private void showDeleteConfirmDialog(String deviceName, int position) {
new androidx.appcompat.app.AlertDialog.Builder(context)
.setTitle("删除设备")
.setMessage("确定要删除 \"" + deviceName + "\" 吗?")
.setPositiveButton("确定", (dialog, which) -> {
if (listener != null) {
listener.onDeleteDevice(deviceName, position);
}
})
.setNegativeButton("取消", null)
.show();
}// ClientMainFragment 和 ClientGuestFragment 都需要实现
public class ClientMainFragment extends BaseMvvmFragment<FragmentClientsMainBinding>
implements ClientListAdapter.OnDeviceActionListener {
private void initView() {
onlineAdapter = new ClientListAdapter(
viewModel.getCurrentMainOnlineCount(),
requireActivity().getBaseContext(),
true
);
onlineAdapter.setOnDeviceActionListener(this); // 设置监听器
viewBinding.rvOnline.setAdapter(onlineAdapter);
// 离线adapter也要设置
offlineAdapter.setOnDeviceActionListener(this);
}
@Override
public void onBlockDevice(String deviceName, int position) {
viewModel.blockDevice(deviceName);
Toast.makeText(getContext(), deviceName + " 已加入黑名单", Toast.LENGTH_SHORT).show();
}
@Override
public void onDeleteDevice(String deviceName, int position) {
Toast.makeText(getContext(), deviceName + " 已删除", Toast.LENGTH_SHORT).show();
}
}
111
public class ClientMainFragment extends BaseMvvmFragment<FragmentClientsMainBinding>
implements ClientListAdapter.OnDeviceActionListener {
// ... 现有代码保持不变 ...
@Override
protected void subscribeViewModel(@Nullable Bundle savedInstanceState) {
viewModel = new ViewModelProvider(requireActivity()).get(ClientViewModel.class);
initView();
observeViewModel(); // 添加观察方法
}
private void observeViewModel() {
viewModel.getMainOnlineCount().observe(this, onlineCount -> {
if (onlineCount != null && onlineAdapter != null) {
// 如果数量变化,重新创建adapter
onlineAdapter = new ClientListAdapter(onlineCount, requireActivity(), true);
onlineAdapter.setOnDeviceActionListener(this);
viewBinding.rvOnline.setAdapter(onlineAdapter);
}
checkAndShowEmptyState();
});
viewModel.getMainOfflineCount().observe(this, offlineCount -> {
if (offlineCount != null && offlineAdapter != null) {
offlineAdapter = new ClientListAdapter(offlineCount, requireActivity(), false);
offlineAdapter.setOnDeviceActionListener(this);
viewBinding.rvOffline.setAdapter(offlineAdapter);
}
checkAndShowEmptyState();
});
}
private void checkAndShowEmptyState() {
Integer onlineCount = viewModel.getMainOnlineCount().getValue();
Integer offlineCount = viewModel.getMainOfflineCount().getValue();
boolean isEmpty = (onlineCount == null || onlineCount == 0) &&
(offlineCount == null || offlineCount == 0);
if (isEmpty) {
showEmptyView();
} else {
showDeviceList();
}
}
private void showEmptyView() {
viewBinding.rvOnline.setVisibility(View.GONE);
viewBinding.rvOffline.setVisibility(View.GONE);
viewBinding.emptyLayout.setVisibility(View.VISIBLE);
viewBinding.emptyImage.setImageResource(R.drawable.empty_device);
viewBinding.emptyText.setText("没有设备记录");
}
private void showDeviceList() {
viewBinding.rvOnline.setVisibility(View.VISIBLE);
viewBinding.rvOffline.setVisibility(View.VISIBLE);
viewBinding.emptyLayout.setVisibility(View.GONE);
}
@Override
public void onBlockDevice(String deviceName, int position, boolean isOnlineAdapter) {
viewModel.blockDevice(deviceName);
// 更新对应的设备数量
if (isOnlineAdapter) {
viewModel.updateMainOnlineCount(viewModel.getCurrentMainOnlineCount() - 1);
} else {
viewModel.updateMainOfflineCount(viewModel.getCurrentMainOfflineCount() - 1);
}
Toast.makeText(getContext(), deviceName + " 已加入黑名单", Toast.LENGTH_SHORT).show();
}
@Override
public void onDeleteDevice(String deviceName, int position, boolean isOnlineAdapter) {
if (isOnlineAdapter) {
viewModel.updateMainOnlineCount(viewModel.getCurrentMainOnlineCount() - 1);
} else {
viewModel.updateMainOfflineCount(viewModel.getCurrentMainOfflineCount() - 1);
}
Toast.makeText(getContext(), deviceName + " 已删除", Toast.LENGTH_SHORT).show();
}
}
public class ClientGuestFragment extends BaseMvvmFragment<FragmentClientsGuestBinding>
implements ClientListAdapter.OnDeviceActionListener {
@Override
protected void subscribeViewModel(@Nullable Bundle savedInstanceState) {
viewModel = new ViewModelProvider(requireActivity()).get(ClientViewModel.class);
initView();
observeViewModel();
}
private void observeViewModel() {
viewModel.getGuestCount().observe(this, guestCount -> {
if (guestCount != null && adapter != null) {
adapter = new ClientListAdapter(guestCount, requireActivity(), true);
adapter.setOnDeviceActionListener(this);
viewBinding.rvOnline.setAdapter(adapter);
}
if (guestCount == null || guestCount == 0) {
showEmptyView();
} else {
showDeviceList();
}
});
}
private void showEmptyView() {
viewBinding.rvOnline.setVisibility(View.GONE);
viewBinding.emptyLayout.setVisibility(View.VISIBLE);
viewBinding.emptyImage.setImageResource(R.drawable.empty_device);
viewBinding.emptyText.setText("没有设备记录");
}
private void showDeviceList() {
viewBinding.rvOnline.setVisibility(View.VISIBLE);
viewBinding.emptyLayout.setVisibility(View.GONE);
}
@Override
public void onBlockDevice(String deviceName, int position, boolean isOnlineAdapter) {
viewModel.blockDevice(deviceName);
viewModel.updateGuestCount(viewModel.getCurrentGuestCount() - 1);
Toast.makeText(getContext(), deviceName + " 已加入黑名单", Toast.LENGTH_SHORT).show();
}
@Override
public void onDeleteDevice(String deviceName, int position, boolean isOnlineAdapter) {
viewModel.updateGuestCount(viewModel.getCurrentGuestCount() - 1);
Toast.makeText(getContext(), deviceName + " 已删除", Toast.LENGTH_SHORT).show();
}
}
// 在CountryAdapter类中添加这个方法
public void updateData(List<String> newCountryList) {
this.countryList.clear();
this.countryList.addAll(newCountryList);
// 重新计算选中位置,基于国家名称
selectedPosition = -1;
for (int i = 0; i < countryList.size(); i++) {
if (countryList.get(i).equals(selectedCountryName)) {
selectedPosition = i;
break;
}
}
notifyDataSetChanged();
}
2. 修改Activity中的setupCountrySelectionUI方法:
java
private void setupCountrySelectionUI(View contentView, TPModalBottomSheet modal) {
RecyclerView recyclerView = contentView.findViewById(R.id.recyclerView_countries);
CountryAdapter countryAdapter = new CountryAdapter(countryViewModel.getAllCountries());
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(countryAdapter);
// 设置当前选中的国家
String currentCountry = countryViewModel.getCurrentSelectedCountry();
if (currentCountry != null && !currentCountry.trim().isEmpty()) {
countryAdapter.setSelectedCountry(currentCountry);
}
// 设置国家点击监听
countryAdapter.setOnCountryClickListener(new CountryAdapter.OnCountryClickListener() {
@Override
public void onCountryClick(String countryName, int position) {
countryViewModel.selectCountry(countryName);
modal.dismiss();
}
});
// ★ 关键修改:取消注释并启用这个观察者
countryViewModel.filteredCountries.observe(this, countries -> {
countryAdapter.updateData(countries); // 使用新添加的updateData方法
});
// 设置搜索功能
setupSearchView(contentView, countryAdapter, modal);
}
3. 简化setupSearchView方法:
java
private void setupSearchView(View contentView, CountryAdapter countryAdapter, TPModalBottomSheet modal) {
TPSearchBar tpSearchBar = contentView.findViewById(R.id.tp_search);
// 创建搜索建议数据
ArrayList<String> searchData = new ArrayList<>(countryViewModel.getAllCountries());
// 创建搜索适配器
SearchViewBaseAdapter<String> searchAdapter = new SearchViewBaseAdapter<String>(
searchData,
new SearchViewBaseAdapter.OnBindDataListener<String>() {
@Override
public void onBindViewHolder(String model, SearchViewBaseViewHolder viewHolder, int type, int position) {
viewHolder.setText(R.id.tv_country_name, model);
}
@Override
public int getLayoutId(int type) {
return R.layout.country_item;
}
}
);
// 设置搜索结果点击事件
searchAdapter.setItemClickListener(new SearchViewBaseAdapter.OnItemClickListener<String>() {
@Override
public void onClick(View view, String data) {
countryViewModel.selectCountry(data);
tpSearchBar.dismissSearchView();
countryViewModel.clearSearch(); // 这会触发filteredCountries更新,从而更新RecyclerView
modal.dismiss();
}
});
// ★ 关键修改:移除countryAdapter.filterCountries调用
tpSearchBar.setTextChangeListener(new TPMaterialSearchView.TextChangeListener() {
@Override
public void onTextChange(String searchText) {
// 只通过ViewModel处理搜索过滤
countryViewModel.filterCountries(searchText);
// 删除这一行:countryAdapter.filterCountries(searchText);
// 过滤搜索建议
if (searchText == null || searchText.trim().isEmpty()) {
searchAdapter.updateData(new ArrayList<>(countryViewModel.getAllCountries()));
} else {
ArrayList<String> filteredList = getFilteredCountries(searchText);
searchAdapter.updateData(filteredList);
}
}
});
tpSearchBar.setManager(getSupportFragmentManager());
tpSearchBar.setSearchViewAdapter(searchAdapter);
// 其余代码保持不变...
}
工作流程:
- 用户在搜索框输入文字
countryViewModel.filterCountries(searchText)被调用- ViewModel更新
filteredCountries - 观察者
countryViewModel.filteredCountries.observe被触发 - 调用
countryAdapter.updateData(countries)更新RecyclerView - 用户在搜索结果中选择国家,点击搜索建议
- 调用
countryViewModel.clearSearch()清除搜索 - 再次触发观察者,RecyclerView回到完整列表,且保持选中状态
总结:
你的CountryAdapter写得很好,只需要加一个updateData方法。主要问题是Activity中没有正确连接ViewModel和Adapter,导致ViewModel的状态变化没有传递给UI。通过添加观察者和updateData方法,就能实现你想要的功能:搜索后选择国家,能够正确回到主列表并显示选中状态。