Android中Map<String,String>转List<Map<String,String>>循环仅存当前值问题
问题:List<Map<String, String>>添加元素后所有元素被最后一次数据覆盖
我尝试通过以下代码向List<Map<String, String>>中添加元素:
@NonNull public static List<Map<String, String>> mysqlSelect(@NonNull String select, String where) { Map<String, String> info = new HashMap<String,String>(); List<Map<String, String>> list = new ArrayList<>(); int selectCnt = select.replaceAll("[^,]","").length(); final boolean[] b = {true}; new Thread(new Runnable() { @Override public void run(){ try (Connection connection = DriverManager.getConnection(URL, USER, PASSWORD)) { String sql = "SELECT fb_firstname, fb_lastname, fb_id FROM fbuser"; PreparedStatement statement = connection.prepareStatement(sql); ResultSet resultSet = statement.executeQuery(); while (resultSet.next()) { info.put("name", resultSet.getString("fb_firstname")); info.put("address", resultSet.getString("fb_lastname")); info.put("phone_number", resultSet.getString("fb_id")); list.add(info); } b[0] = false; } catch (Exception e) { Log.e("InfoAsyncTask", "Error reading school information", e); b[0] = false; } } }).start(); while (b[0]) { } return list; //result.get("name") }
在while循环执行时,列表会被填充所需的3个字符串值,但每次循环后,之前所有元素的值都会被替换为最后一次读取的数据。例如:
第一次循环后:
name: bob barker address: something phone-number = 4235421212
第二次循环后:
name: steve jobs address: something again phone-number = 8546521111
此时列表中第一次循环的数据也变成了第二次的内容:
name: steve jobs address: something again phone-number = 8546521111
请问我忽略了什么?
更新1
我原本的代码如下:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new InfoAsyncTask().execute(); } @SuppressLint("StaticFieldLeak") public class InfoAsyncTask extends AsyncTask<Void, Void, Map<String, String>> { @Override protected Map<String, String> doInBackground(Void... voids) { Map<String, String> info = new HashMap<>(); try (Connection connection = DriverManager.getConnection(URL, USER, PASSWORD)) { String sql = "SELECT fb_firstname, fb_lastname, fb_id FROM fbuser LIMIT 1"; PreparedStatement statement = connection.prepareStatement(sql); ResultSet resultSet = statement.executeQuery(); if (resultSet.next()) { info.put("name", resultSet.getString("fb_firstname")); info.put("address", resultSet.getString("fb_lastname")); info.put("phone_number", resultSet.getString("fb_id")); } } catch (Exception e) { Log.e("InfoAsyncTask", "Error reading school information", e); } return info; } @Override protected void onPostExecute(Map<String, String> result) { if (!result.isEmpty()) { TextView textViewName = findViewById(R.id.textViewName); TextView textViewAddress = findViewById(R.id.textViewAddress); TextView textViewPhoneNumber = findViewById(R.id.textViewPhone); textViewName.setText(result.get("name")); textViewAddress.setText(result.get("address")); textViewPhoneNumber.setText(result.get("phone_number")); } } }
但我想将这段逻辑放到独立的类文件中,并在onCreate中调用。
解答
核心问题:重复引用同一个Map对象
你只创建了一个Map<String, String> info实例,每次循环只是修改这个实例里的键值对,然后把同一个对象的引用添加到List中。List里的所有元素本质上都是指向同一个Map对象的指针,所以最后一次修改会覆盖所有元素的显示内容。
修复方案
把Map<String, String> info = new HashMap<>();的创建放到while (resultSet.next())循环内部,每次循环都生成一个新的Map实例:
while (resultSet.next()) { // 每次循环新建一个Map对象 Map<String, String> info = new HashMap<>(); info.put("name", resultSet.getString("fb_firstname")); info.put("address", resultSet.getString("fb_lastname")); info.put("phone_number", resultSet.getString("fb_id")); list.add(info); }
额外优化建议
- 避免忙等待(空循环):你用
while (b[0]) { }实现线程等待,这会占用CPU资源,推荐用CountDownLatch来实现异步任务的结果等待:
public static List<Map<String, String>> mysqlSelect(@NonNull String select, String where) { List<Map<String, String>> list = new ArrayList<>(); CountDownLatch latch = new CountDownLatch(1); new Thread(new Runnable() { @Override public void run(){ try (Connection connection = DriverManager.getConnection(URL, USER, PASSWORD)) { String sql = "SELECT fb_firstname, fb_lastname, fb_id FROM fbuser"; PreparedStatement statement = connection.prepareStatement(sql); ResultSet resultSet = statement.executeQuery(); while (resultSet.next()) { Map<String, String> info = new HashMap<>(); info.put("name", resultSet.getString("fb_firstname")); info.put("address", resultSet.getString("fb_lastname")); info.put("phone_number", resultSet.getString("fb_id")); list.add(info); } } catch (Exception e) { Log.e("InfoAsyncTask", "Error reading school information", e); } finally { latch.countDown(); } } }).start(); try { latch.await(); // 等待线程执行完成 } catch (InterruptedException e) { Thread.currentThread().interrupt(); } return list; }
- 独立类的实现:如果要把数据库逻辑放到独立类,推荐用回调来传递结果(避免阻塞主线程),示例如下:
// 独立的数据库操作类 public class DbHelper { private static final String URL = "你的数据库URL"; private static final String USER = "用户名"; private static final String PASSWORD = "密码"; // 用回调返回结果 public interface OnDataLoadedListener { void onDataLoaded(List<Map<String, String>> data); void onError(Exception e); } public void fetchUserList(OnDataLoadedListener listener) { new Thread(new Runnable() { @Override public void run() { List<Map<String, String>> list = new ArrayList<>(); try (Connection connection = DriverManager.getConnection(URL, USER, PASSWORD)) { String sql = "SELECT fb_firstname, fb_lastname, fb_id FROM fbuser"; PreparedStatement statement = connection.prepareStatement(sql); ResultSet resultSet = statement.executeQuery(); while (resultSet.next()) { Map<String, String> info = new HashMap<>(); info.put("name", resultSet.getString("fb_firstname")); info.put("address", resultSet.getString("fb_lastname")); info.put("phone_number", resultSet.getString("fb_id")); list.add(info); } // 主线程回调结果 new Handler(Looper.getMainLooper()).post(() -> listener.onDataLoaded(list)); } catch (Exception e) { Log.e("DbHelper", "Error fetching user data", e); new Handler(Looper.getMainLooper()).post(() -> listener.onError(e)); } } }).start(); } }
在Activity的onCreate中调用:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DbHelper dbHelper = new DbHelper(); dbHelper.fetchUserList(new DbHelper.OnDataLoadedListener() { @Override public void onDataLoaded(List<Map<String, String>> data) { // 处理返回的用户列表,比如更新UI if (!data.isEmpty()) { // 示例:显示第一个用户数据 Map<String, String> firstUser = data.get(0); TextView textViewName = findViewById(R.id.textViewName); TextView textViewAddress = findViewById(R.id.textViewAddress); TextView textViewPhoneNumber = findViewById(R.id.textViewPhone); textViewName.setText(firstUser.get("name")); textViewAddress.setText(firstUser.get("address")); textViewPhoneNumber.setText(firstUser.get("phone_number")); } } @Override public void onError(Exception e) { // 处理错误 Toast.makeText(MainActivity.this, "数据加载失败", Toast.LENGTH_SHORT).show(); } }); }
内容的提问来源于stack exchange,提问作者StealthRT
相关产品推荐
相关产品推荐

