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

Android应用HashMap/ArrayList持久化异常:添加读写代码后无法登录

Fixing Android Persistence Issue: Registration Success but Login Fails After Adding Serialization Code

Hey there, let's break down why your app is failing to log in after adding persistence code, and how to fix it step by step.

Core Problem Analysis

From your code and description, the key issues likely stem from incorrect serialization setup, missing equality checks for HashMap keys, or flawed error handling that hides critical issues. Let's dive into each possible cause:

1. Missing Serializable Implementation

All classes stored in your collections (User, EventManager, Parent, Event) must implement the Serializable interface to be saved/loaded via ObjectOutputStream/ObjectInputStream. If any class (or its nested custom members) doesn't implement this, serialization will fail silently (caught by your catch blocks) and return null when loading, leaving your static collections empty or corrupted.

Fix:
Add Serializable to all relevant classes, e.g.:

public class User implements Serializable {
    // Your existing fields and methods
}

2. Broken equals() and hashCode() for HashMap Keys

Your UsersDB uses User as a HashMap key. Without properly overriding equals() and hashCode() in the User class, HashMap will compare object memory addresses instead of meaningful identifiers (like email). This means the User object you create during login won't match the one stored in the HashMap, even if the email is the same.

Fix:
Override equals() and hashCode() using a unique identifier (e.g., user email):

public class User implements Serializable {
    private String mail;
    // Other fields

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(mail, user.mail);
    }

    @Override
    public int hashCode() {
        return Objects.hash(mail);
    }
}

3. Unsafe Type Casting & Poor Error Handling

Your readArrayListFromSD method name is misleading (you save both HashMaps and ArrayLists), and you cast the returned object directly without type checks. If the loaded object isn't the expected type, a ClassCastException is caught, returns null, and your static collections may end up empty or null.

Fix:
Rename the method to readObjectFromSD, add type checks, and initialize empty collections if loading fails:

private Object readObjectFromSD(Context mContext, String filename){
    try {
        FileInputStream fis = mContext.openFileInput(filename + ".dat");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Object obj = ois.readObject();
        fis.close();
        return obj;
    } catch (Exception e) {
        Log.e("Persistence", "Failed to read file: " + filename, e); // Use Log.e for visibility
        return null;
    }
}

// Update loadDataToDB with type checks
public void loadDataToDB(){
    try {
        // Load EventManagers
        Object emObj = readObjectFromSD(context, EVENTMANAGERDB);
        if (emObj instanceof HashMap) {
            EventManagersDB.loadAllManagers((HashMap<EventManager, String>) emObj);
        } else {
            Log.w("Persistence", "EventManager data invalid, initializing empty");
            EventManagersDB.initEmpty();
        }

        // Load Users
        Object userObj = readObjectFromSD(context, USERSDB);
        if (userObj instanceof HashMap) {
            UsersDB.loadFromFile((HashMap<User, String>) userObj);
        } else {
            Log.w("Persistence", "User data invalid, initializing empty");
            UsersDB.initEmpty();
        }

        // Repeat similar checks for ParentsDB and EventsDB
        Object parentObj = readObjectFromSD(context, PARENTSDB);
        if (parentObj instanceof HashMap) {
            ParentsDB.loadFromFile((HashMap<Parent, String>) parentObj);
        } else {
            Log.w("Persistence", "Parent data invalid, initializing empty");
            ParentsDB.initEmpty();
        }

        Object eventObj = readObjectFromSD(context, EVENTSDB);
        if (eventObj instanceof ArrayList) {
            EventsDB.setAllEvents((ArrayList<Event>) eventObj);
        } else {
            Log.w("Persistence", "Event data invalid, initializing empty");
            EventsDB.initEmpty();
        }
    } catch (Exception e){
        Log.e("Persistence", "Failed to load all data", e);
        // Fallback to empty collections
        EventManagersDB.initEmpty();
        UsersDB.initEmpty();
        ParentsDB.initEmpty();
        EventsDB.initEmpty();
    }
}

Then add initEmpty() methods to your DB classes to ensure collections are never null:

public class UsersDB {
    private static HashMap<User, String> users;

    public static void loadFromFile(HashMap<User, String> loadedUsers) {
        users = loadedUsers != null ? loadedUsers : new HashMap<>();
    }

    public static void initEmpty() {
        users = new HashMap<>();
    }

    // Rest of your methods
}

4. Missing Save Call After Registration

Your current code only saves data after login, but not after registration. This means newly registered users are only stored in memory, not persisted to disk. Even worse, if you restart the app, the loaded (empty) data will overwrite the in-memory users.

Fix:
Call saveDataToDB() immediately after a successful registration:

btnRegister.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        boolean isRegistered = presenter.register(/* your registration params */);
        if (isRegistered) {
            presenter.saveDataToDB();
            Toast.makeText(Login_activity.this, "Registration successful!", Toast.LENGTH_SHORT).show();
        }
    }
});

Final Checks

  1. Check Logcat: Filter for the Persistence tag to see any hidden errors (like serialization failures or type mismatches).
  2. Test Flow: Register a user, verify the .dat files are created in your app's internal storage, then restart the app and attempt login.

内容的提问来源于stack exchange,提问作者Paris Constantinides

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:10:23