2014-01-11 51 views
1

我试图用Gson保存一个序列化/反序列化POJOS列表。虽然一般情况下这是没有这样一个特殊的任务,我发现了一个例外,我以前从来没见过:Gson和方向变化的问题

01-11 14:17:22.556: E/AndroidRuntime(15941): java.lang.RuntimeException: 
Unable to start activity ComponentInfo{com.timkranen.playpalproject/com.timkranen.playpalproject.HomeActivity}: 
java.lang.RuntimeException: Unable to invoke no-args constructor for interface java.util.concurrent.locks.Lock. 
Register an InstanceCreator with Gson for this type may fix this problem. 

我怀疑它与事实列表项正在事加载到AsyncTask中。任何人都有这个问题的经验?

我试着把我在onSaveInstanceState内执行的逻辑(用于保存)放在同步方法中,但是没有帮助。

编辑

下面是我的一些代码,试图使之更加清晰。我有一个名为friendsList的列表。列表填充这个的AsyncTask和onCreateView()被执行

private class RetrieveFriends extends AsyncTask<Void, Integer, String> { 

    @Override 
    protected String doInBackground(Void... params) { 
     // get friends 
     if (friendProfiles == null || friendProfiles.size() == 0) { 
      friendProfiles = new ArrayList<Profile>(); 
      if (currentProfile.getFriendUids() != null 
        && currentProfile.getFriendUids().size() > 0) 
       for (String fUid : currentProfile.getFriendUids()) { 
        Profile friend = ProfileDataManager 
          .getProfileFromId(fUid); 
        friendProfiles.add(friend); 
       } 

      if (friendProfiles.size() == 0) { 
       return "null"; 
      } 
     } 

     return "notnull"; 

    } 

    @Override 
    protected void onPostExecute(String result) { 
     if (!result.equals("null")) { 
      loadingFriendsBar.setVisibility(View.INVISIBLE); 
      friendsList.setVisibility(View.VISIBLE); 
      FriendListAdapter adapter = new FriendListAdapter(
        containedActivity, R.layout.friendslist_row, 
        friendProfiles); 
      friendsList.setAdapter(adapter); 
     } else { 
      loadingFriendsBar.setVisibility(View.INVISIBLE); 
      friendMsg.setVisibility(View.VISIBLE); 
     } 
    } 

} 

现在在的onSaveInstanceState我序列化列表以JSON是这样的:

private synchronized void saveToState(Bundle state) { 
    Gson gson = new Gson(); 
    Type listOfProfiles = new TypeToken<List<Profile>>() { 
    }.getType(); 
    String json = gson.toJson(friendProfiles, listOfProfiles); 
    state.putString("json_friendProfiles", json); 
} 

该方法是直接的onSaveInstanceState(叫) 。检索它是相同的:

private synchronized void retrieveFromState(String json) { 
    Type listOfProfiles = new TypeToken<List<Profile>>() { 
    }.getType(); 
    Gson gson = new Gson(); 
    friendProfiles = (List<Profile>) gson.fromJson(json, 
      listOfProfiles); 
} 

奇怪的是,状态正确保存时导航到不同的片段。只有当我改变方向时才会出现错误。

编辑:根据要求,这里的Profile类

public class Profile { 

private String mEmail; 
private String mPassword; 
private String uid; 

// optional properties 
private String name; 
private String location; 
private String about; 
private ParseFile image; // not certain of data type 

private List<String> friendUids; 

public String getName() { 
    if (name == null || name.equals("")) { 
     return "Name unknown"; 
    } 
    return name; 
} 

public void setName(String name) { 
    this.name = name; 
} 

public String getLocation() { 
    if (location == null || location.equals("")) { 
     return "Location unknown"; 
    } 
    return location; 
} 

public void setLocation(String location) { 
    this.location = location; 
} 

public String getAbout() { 
    if (about == null || about.equals("")) { 
     return "About unknown"; 
    } 
    return about; 
} 

public void setAbout(String about) { 
    this.about = about; 
} 

public void setUid(String Uid) { 
    this.uid = Uid; 
} 

public String getUid() { 
    return this.uid; 
} 

public String getPassword() { 
    return mPassword; 
} 

public String getEmail() { 
    return mEmail; 
} 

public Profile(String email, String password) { 
    this.mEmail = email; 
    this.mPassword = password; 
} 

/* 
* Saves a Profile and returns the profiles UID This is ONLY APPLICABLE for 
* NEW profiles use the update method to update existing profile data 
*/ 
public void saveToParse(SaveCallback saveCallBack) { 
    if (ProfileDataManager.IsRegistered(this) != true) { 
     ParseObject pObject = new ParseObject("Profiles"); 
     pObject.put("email", this.mEmail); 
     pObject.put("password", this.mPassword); 
     pObject.saveInBackground(saveCallBack); 
    } else { 
     saveCallBack.done(new ParseException(ErrorCodes.ALREADY_REGISTERED, 
       "AlreadyRegistered")); 
    } 
} 

public void update() { 
    ParseQuery<ParseObject> query = ParseQuery.getQuery("Profiles"); 
    query.getInBackground(this.uid, new GetCallback<ParseObject>() { 

     @Override 
     public void done(ParseObject object, ParseException e) { 
      if (e == null) { 
       // update the object 
       object.put("email", Profile.this.mEmail); 
       object.put("password", Profile.this.mPassword); 
       if (Profile.this.name != null) { 
        object.put("name", Profile.this.name); 
       } 
       if (Profile.this.location != null) { 
        object.put("location", Profile.this.location); 
       } 
       if (Profile.this.about != null) { 
        object.put("about", Profile.this.about); 
       } 
       if (Profile.this.image != null) { 
        object.put("profileImage", Profile.this.image); 
       } 
       if (Profile.this.friendUids != null 
         && Profile.this.friendUids.size() != 0) { 
        object.put("friends", Profile.this.friendUids); 
       } 

       object.saveInBackground(); 
      } 
     } 
    }); 
} 

/* 
* Use updateWithCallBack when you want to update an object but want to show 
* the updated data immediatly using a callback, when calling this method 
* make sure that currentProfile in HomeActivity is set to the new Profile! 
*/ 
public void updateWithCallBack(final SaveCallback callBack) { 
    ParseQuery<ParseObject> query = ParseQuery.getQuery("Profiles"); 
    query.getInBackground(this.uid, new GetCallback<ParseObject>() { 

     @Override 
     public void done(ParseObject object, ParseException e) { 
      if (e == null) { 
       // update the object 
       object.put("email", Profile.this.mEmail); 
       object.put("password", Profile.this.mPassword); 
       if (Profile.this.name != null) { 
        object.put("name", Profile.this.name); 
       } 
       if (Profile.this.location != null) { 
        object.put("location", Profile.this.location); 
       } 
       if (Profile.this.about != null) { 
        object.put("about", Profile.this.about); 
       } 
       if (Profile.this.image != null) { 
        object.put("profileImage", Profile.this.image); 
       } 
       if (Profile.this.friendUids != null 
         && Profile.this.friendUids.size() != 0) { 
        object.put("friends", Profile.this.friendUids); 
       } 
       object.saveInBackground(callBack); 
      } 
     } 
    }); 
} 

// retrieves the image, when done calls callback 
public void retrieveProfileImage(GetDataCallback callBack) { 
    this.image.getDataInBackground(callBack); 
} 

public ParseFile getProfileImage() { 
    return this.image; 
} 

public void setProfileImage(ParseFile image) { 
    this.image = image; 
} 

public void saveProfileImage(Bitmap image) { 
    ByteArrayOutputStream stream = new ByteArrayOutputStream(); 
    image.compress(Bitmap.CompressFormat.JPEG, 50, stream); 
    byte[] byteArray = stream.toByteArray(); 
    String imgid = this.getUid() + "_profile_image.jpeg"; 
    String fileNameForImage = this.getUid() + "_profile_image.jpeg"; 
    this.image = new ParseFile(fileNameForImage, byteArray); 
} 

public List<String> getFriendUids() { 
    return this.friendUids; 
} 

public void addFriend(String uid) { 
    if (this.friendUids != null) { 
     friendUids.add(uid); 
    } else { 
     friendUids = new ArrayList<String>(); 
     friendUids.add(uid); 
    } 
} 

public void setFriends(Object friends) { 
    ArrayList<String> f = (ArrayList<String>) friends; 
    this.friendUids = f; 
} 

}

+0

你能告诉我们你的代码吗? –

+0

如果不需要,请写下您的应用程序,以便在方向更改时不重新创建活动。 – tolgap

+0

我编辑了我原来的问题。 @tolgap但是这不是很糟糕的做法吗?我不认为我需要它,但是像这样实施它是否安全? –

回答

1

GSON对象

private Gson gson = new GsonBuilder(). 
     setExclusionStrategies(new ParseExclusion()). 
     create(); 

排除类

private class ParseExclusion implements ExclusionStrategy { 

    public boolean shouldSkipClass(Class<?> arg0) { 
     return false; 
    } 

    public boolean shouldSkipField(FieldAttributes f) { 
     return (f.getDeclaredClass() == Lock.class); 
    } 

} 

终于:

Type type = new TypeToken<List<Profile>>() {}.getType(); 
List<Profile>) friendProfiles = new ArrayList<Profile>(); 
friendProfiles = gson.fromJson(json,type);