检查parceled自定义对象之间的相等性时出现NullPointerException

时间:2014-11-27 22:26:21

标签: java android arraylist nullpointerexception

我目前正在用Java编写一个Android应用程序,用于记录和存储运动员在其内部存储中的锻炼日志。然后它应该能够调用,编辑和删除现有的锻炼日志。当我尝试检查我过去的锻炼日志的内部存储的ArrayList的成员与其中一个日志的分区副本之间是否相等时,我收到了错误。

如果我尝试检查两个存储日志或存储日志与其自身之间的相等性,我会得到正确的结果,没有空指针异常。但是,当我向DataHandler类传递一个要删除的日志(在我的DetailActivity类中包含)时,会发生错误。无论我在哪里或如何尝试将此传递的,以前包含的日志与我的equals()方法进行比较,我都会得到空指针异常。我对此感到困惑,因为我知道当我打印我传递的日志的字段和我尝试删除的存储日志时,它们完全相同。我知道equals()不能处理null对象,但是这个对象显然不是null,因为我可以打印它的字段。任何帮助表示赞赏。

尝试使用copy.equals(storedObject)时出现以下错误:

Caused by: java.lang.NullPointerException
            at com.cs121.team2.workoutlog.WOLog.equals(WOLog.java:168)
            at com.cs121.team2.workoutlog.DataHandler.editLog(DataHandler.java:134)
            at com.cs121.team2.workoutlog.DetailActivity.onDeleteClick(DetailActivity.java:95)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at android.view.View$1.onClick(View.java:3592)
            at android.view.View.performClick(View.java:4202)
            at android.view.View$PerformClick.run(View.java:17340)
            at android.os.Handler.handleCallback(Handler.java:725)
            at android.os.Handler.dispatchMessage(Handler.java:92)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:5039)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
            at dalvik.system.NativeStart.main(Native Method)

这是我的DataHandler类。我在网上得到错误:

Log.d(" arraylist(1)== arrayList(1)"," result:" + dummy.equals(logList.get(1)));

在我的editLog方法中

public class DataHandler extends Activity {
    private final String TAG = "Data Handler";
    public static DataHandler _dh; //the DataHandler instance that will be constructed and kept
    private static Gson gson;
    private static Type listType;
    private static Context mContext;

    private DataHandler() throws IOException { //this is a singleton class, so this is kept private
        gson = new Gson();
        listType = new TypeToken<ArrayList<WOLog>>(){}.getType();
        File file = new File(mContext.getFilesDir(), "jsonLogs.json");
        file.createNewFile();
    }
    public synchronized static DataHandler getDataHandler(Context context) { //used to make/get the DH
        mContext = context;
        if (_dh == null) { //does the DH already exist?
            try {
                _dh = new DataHandler(); //if not, create a new one
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return _dh; //if so, just return the DH that is already instantiated
    }

    //sends the ArrayList of Logs to LLAdapter
    public synchronized ArrayList<WOLog> getLogs() throws IOException {
        //find and read data from data storage to string temp
        FileInputStream fis = mContext.openFileInput("jsonLogs.json");
        int c;
        String temp="";
        while( (c = fis.read()) != -1){
            temp = temp + Character.toString((char)c);
        }
        fis.close();

        //convert to non-JSON
        ArrayList<WOLog> toReturn = (ArrayList<WOLog>) gson.fromJson(temp, listType);
        if (toReturn == null){
            toReturn = new ArrayList<WOLog>();
            //TODO show user friendly error message
        }
        //send to LLAdapter
        return toReturn;
    }

    //appends a new log to the Log AList
    public synchronized void addLog(WOLog toAdd) throws IOException {
        //retrive data from file
        FileInputStream fis = mContext.openFileInput("jsonLogs.json");
        int c;
        String temp="";
        while( (c = fis.read()) != -1){
            temp = temp + Character.toString((char)c);
        }
        fis.close();
        //convert to non-JSON
        ArrayList<WOLog> logList = (ArrayList<WOLog>) gson.fromJson(temp, listType);

        if (logList == null) {
            logList = new ArrayList<WOLog>();
        }
        logList.add(toAdd);



        // Sorts the list of logs from oldest to newest
        Collections.sort(logList, new Comparator<WOLog>() {
            @Override
            public int compare(WOLog woLog, WOLog woLog2) {
                return woLog2.getDateCompare() - woLog.getDateCompare();
            }
        });

        // For clearing the file while testing: logList = null;

        //convert to JSON
        String jsonLog = gson.toJson(logList);
        //save to a .txt file
        FileOutputStream fos = mContext.openFileOutput("jsonLogs.json", Context.MODE_PRIVATE);
        //write to internal storage
        fos.write(jsonLog.getBytes());
        fos.close();
    }

    //edits or removes an existing log
    public synchronized void editLog(WOLog newLog, WOLog oldLog, boolean delete) throws IOException {
        //save a dummy copy of oldLog
        WOLog dummy = oldLog;
        //retrieve data from file
        FileInputStream fis = mContext.openFileInput("jsonLogs.json");
        int c;
        String temp="";
        while( (c = fis.read()) != -1){
            temp = temp + Character.toString((char)c);
        }
        fis.close();
        //convert to non-JSON
        ArrayList<WOLog> logList = (ArrayList<WOLog>) gson.fromJson(temp, listType);
        //for(WOLog bleh : logList) {
          //  Log.d("logList bleh",bleh.toStringList());
        //}

        if(delete) { //are we deleting the log?
            //Log.d("oldLog fields","oldLog. date: " + oldLog.getDate() + ", name: " + oldLog.getName() + ", time: ." + oldLog.getTime() + ", distance: " + oldLog.getDistance() + ", mood: " + oldLog.getMood() + ", weight " + oldLog.getWeight() + ", sets: " + oldLog.getSets() + ", reps: " + oldLog.getReps() + ", memo: " + oldLog.getMemo() + ", type: " + oldLog.getType() + ", subtype: " + oldLog.getSubtype() + ", dateCompare: " + oldLog.getDateCompare());
            //Log.d("arrayList(0) fields","arrayList(0). date: " + logList.get(0).getDate() + ", name: " + logList.get(0).getName() + ", time: ." + logList.get(0).getTime() + ", distance: " + logList.get(0).getDistance() + ", mood: " + logList.get(0).getMood() + ", weight " + logList.get(0).getWeight() + ", sets: " + logList.get(0).getSets() + ", reps: " + logList.get(0).getReps() + ", memo: " + logList.get(0).getMemo() + ", type: " + logList.get(0).getType() + ", subtype: " + logList.get(0).getSubtype() + ", dateCompare: " + logList.get(0).getDateCompare());
            //Log.d("arrayList(1) fields","arrayList(1). date: " + logList.get(1).getDate() + ", name: " + logList.get(1).getName() + ", time: ." + logList.get(1).getTime() + ", distance: " + logList.get(1).getDistance() + ", mood: " + logList.get(1).getMood() + ", weight " + logList.get(1).getWeight() + ", sets: " + logList.get(1).getSets() + ", reps: " + logList.get(1).getReps() + ", memo: " + logList.get(1).getMemo() + ", type: " + logList.get(1).getType() + ", subtype: " + logList.get(1).getSubtype() + ", dateCompare: " + logList.get(1).getDateCompare());
            Log.d("arraylist(1)==arrayList(1)","result: " + dummy.equals(logList.get(1)));
            //Log.d("contained?","oldLog contained: " + logList.contains(oldLog));
            //Log.d("arrayList(0)",logList.get(0).toStringDetail());
            //logList.indexOf(oldLog); //...if so, delete the log
            //Log.d("past remove","we got past remove(oldLog)");
        }
        else { //...if not, we're editing the log
            int myIndex = logList.indexOf(oldLog); //find the index of the old log
            logList.set(myIndex, newLog); //set the old log to the new log
        }

        // For clearing the file while testing: logList = new ArrayList<WOLog>();

        //sort loglist
        if(!logList.isEmpty()) {
            Collections.sort(logList, new Comparator<WOLog>() {
                @Override
                public int compare(WOLog woLog, WOLog woLog2) {
                    return woLog2.getDateCompare() - woLog.getDateCompare();
                }
            });
        }
        Log.d("past sort","we got past Collections.sort");

        //convert to JSON
        String jsonLog = gson.toJson(logList);
        Log.d("past toJson","we got past jsonLog = gson.toJson(logList)");
        //save to a .txt file
        FileOutputStream fos = mContext.openFileOutput("jsonLogs.json", Context.MODE_PRIVATE);
        Log.d("past fos","we got past fos = mContext.openFileOutput(...)");
        //write to internal storage
        fos.write(jsonLog.getBytes());
        Log.d("past write","we got past fos.write(...)");
        fos.close();
        Log.d("past close","we got past fos.close()");
    }
}

最后,这里是我的WOLog类,其中包含equals方法。终端说错误发生在返回线上。

public class WOLog implements Parcelable {
    // Just a lot of static data
    final static int TYPE_CARDIO = 0;
    final static int TYPE_STRENGTH = 1;
    final static int TYPE_CUSTOM = 2;
    final static int SUBTYPE_NONE = 0;
    final static int SUBTYPE_TIME_BODY = 1;
    final static int SUBTYPE_DIST_WEIGHTS = 2;

    final static String[] MOOD_ARRAY = {"awful", "bad", "k", "good", "perfect"};
    final static String[] TYPE_ARRAY = {"Cardio", "Strength", "Custom"};
    final static String[] SUBTYPE_ARRAY = {"None", "Time/Body", "Distance/Weights"};

    // Data stored in log
    private int dateCompare;
    private String date, name, time, distance, mood, weight, sets, reps, memo, type, subtype;

    //tag for debug logging.
    private static final String TAG = "WOLog";

    public WOLog()
    {
        dateCompare = 0;
        date = name = time = distance = mood = weight = sets = reps = memo = type = subtype = null;
    }


    // Setter Methods
    public void setDate(int m, int dy, int yr, int hr, int min){
        date = m + "-" + dy + "-" + yr + " " + hr + ":";
        if (min < 10) date += "0" + min;
        else date += min;

        dateCompare += min;
        dateCompare += hr * 10;
        dateCompare += dy * 1000;
        dateCompare += m * 100000;
        dateCompare += yr * 10000000;
    }

    public void setName(String t){ name = t; }

    public void setTime(String t){ time = t; }

    public void setDistance(String d){ distance = d; }

    public void setReps(String r){ reps = r; }

    public void setSets(String s){ sets = s; }

    public void setWeight(String w){ weight = w;}

    public void setMood(String m){ mood = m; }

    public void setMemo(String m) { memo = m; }

    public void setType(String t) { type = t; }

    public void setSubtype(String t) { subtype = t; }


    // Getter Methods
    // TODO: Remove these if we don't wind up using them for stats
    public int getDateCompare(){ return dateCompare; }

    public String getDate(){ return date; }

    public String getName(){ return name; }

    public String getTime(){ return time; }

    public String getDistance(){ return distance; }

    public String getReps() { return  reps; }

    public String getSets() { return sets; }

    public String getWeight() { return weight; }

    public String getMood(){ return mood; }

    public String getMemo() { return memo; }

    public String getType() { return type; }

    public String getSubtype() { return subtype; }


    // toString formatted with HTML for ListView
    public String toStringList(){
        String s = "";

        s += "<center><b>" + name + "</b>";

        if(date != null){
            s += "<br><b>Date: </b>" + date;
        }
        if(mood != null){
            s += "<br><b>Mood: </b>" + mood;
        }

        s += "</center>";

        return s;
    }

    // toString formatted with HTML for DetailView
    public String toStringDetail(){
        String s = "";

        s += "<center><b>" + name.toUpperCase() + "</b><br>";
        s += "<b>(Workout Info):</b><br>";

        if(date != null && !date.isEmpty()){
            s += "<b>Date: </b>" + date + "<br>";
        }

        if(time != null && !time.isEmpty()){
            s += "<b>Time: </b>" + time + "<br>";
        }
        if(mood != null && !mood.isEmpty()){
            s += "<b>Mood: </b>" + mood + "<br>";
        }
        if(distance != null && !distance.isEmpty()){
            s += "<b>Distance: </b>" + distance + "<br>";
        }
        if(weight != null && !weight.isEmpty()) {
            s += "<b>Weight: </b>" + weight + "<br>";
        }
        if(sets != null && !sets.isEmpty()) {
            s += "<b>Sets: </b>" + sets + "<br>";
        }
        if(reps != null && !reps.isEmpty()) {
            s += "<b>Reps: </b>" + reps + "<br>";
        }
        if(memo != null && !memo.isEmpty()) {
            s += "<b>Memo: </b>" + memo + "<br>";
        }

        s += "</center>";

        return s;
    }

    // TODO: Write comparable function in WOLog instead of overriding in DataHandler?

    //Equals function
    @Override
    public boolean equals(Object otherLog){
        //return true if objects are identical
        if (this == otherLog) {
            return true;
        }
        //return false if the otherLog is null
        if (otherLog == null) {
            return false;
        }
        //return false if other object is wrong type
        if (!(otherLog instanceof WOLog)) {
            return false;
        }
        return (this.getDate().equals(((WOLog)otherLog).getDate()) &&
                this.getName().equals(((WOLog)otherLog).getName()) &&
                this.getTime().equals(((WOLog)otherLog).getTime()) &&
                this.getDistance().equals(((WOLog)otherLog).getDistance()) &&
                this.getMood().equals(((WOLog)otherLog).getMood()) &&
                this.getWeight().equals(((WOLog)otherLog).getWeight()) &&
                this.getSets().equals(((WOLog)otherLog).getSets()) &&
                this.getReps().equals(((WOLog)otherLog).getReps()) &&
                this.getMemo().equals(((WOLog)otherLog).getMemo()) &&
                this.getType().equals(((WOLog)otherLog).getType()) &&
                this.getSubtype().equals(((WOLog)otherLog).getSubtype()));
    }

    //in case this project ever uses hash coding, make sure they know they have to write it
    @Override public int hashCode() {
        throw new UnsupportedOperationException();
    }

    //The following functions allow for a WOLog to be passed as a Parcel
    public static final Parcelable.Creator<WOLog> CREATOR = new Parcelable.Creator<WOLog>() {
        public WOLog createFromParcel(Parcel in) {
            return new WOLog(in);
        }

        public WOLog[] newArray(int size) {
            return new WOLog[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(dateCompare);
        dest.writeString(name);
        dest.writeString(time);
        dest.writeString(distance);
        dest.writeString(mood);
        dest.writeString(date);
        dest.writeString(memo);
        dest.writeString(weight);
        dest.writeString(sets);
        dest.writeString(reps);
        dest.writeString(type);
        dest.writeString(subtype);
    }

    private WOLog(Parcel in) {
        dateCompare = 0;
        dateCompare = in.readInt();
        name = null;
        name = in.readString();
        time = null;
        time = in.readString();
        distance = null;
        distance = in.readString();
        mood = null;
        mood = in.readString();
        date = null;
        date = in.readString();
        memo = null;
        memo = in.readString();
        weight = null;
        weight = in.readString();
        sets = null;
        sets = in.readString();
        reps = null;
        reps = in.readString();
        type = null;
        type = in.readString();
        subtype = null;
        subtype = in.readString();
    }
}

1 个答案:

答案 0 :(得分:0)

尝试使用ApacheCommons&#39; EqualsBuilder类:

public boolean equals(Object obj) {
    return EqualsBuilder.reflectionEquals(this, obj);
}

http://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/builder/EqualsBuilder.html