解決Android開發中,ActiveAndroid和Gson同時使用,對象序列化失敗的問題


ActiveAndroid是安卓開發常用的ORM框架。

Gson則是Google提供的輕量級序列化框架,非常適合Android開發使用。

但這兩者同時使用,會產生序列化失敗的問題。你通常會收到如下信息:

java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: [your model]. Forgot to register a type adapter?

這是由於ActiveAndroid框架需要模型繼承com.activeandroid.Model類,而這個類貌似不能序列化,具體原因未深究,有興趣的同學可以看看ActiveAndroid的源碼。
在ActiveAndroid的Git上查閱了Issue后,發現有開發者遇到類似問題,但沒有有效解決辦法。

翻閱了Gson API之后,發現Google已經提供了解決途徑。

假設我們有一個基礎類ClassBase:

import java.io.Serializable;

public class ClassBase implements Serializable {
    /**
     * -6454847757470885679L
     */
    private static final long serialVersionUID = -6454847757470885679L;
    private String name;
    private int count;

    public String getName() {
        return name;
    }

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

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

}

另有一個擴展類Cnblogs:

import java.io.Serializable;

public class Cnblogs extends ClassBase implements Serializable {
    /**
     * 8568957562120574502L
     */
    private static final long serialVersionUID = 8568957562120574502L;
    private String welcome;
    private int members;
    private String url;

    public String getGuid() {
        return welcome;
    }

    public void setGuid(String welcome) {
        this.welcome = welcome;
    }

    public int getMembers() {
        return members;
    }

    public void setMembers(int members) {
        this.members = members;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}

如果我們在序列化時想要忽略父類的屬性,怎么辦呢?
這時候,你需要com.google.gson.ExclusionStrategy接口來處理這個問題。

import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;

public class SpecificClassExclusionStrategy implements ExclusionStrategy {

    private final Class<?> excludedThisClass;
    private final Class<?> excludedThisClassFields;

    /***
     * 過濾器初始化
     * 
     * @param excludedThisClass
     *            該類和繼承自該類的對象實例將被忽略
     * @param excluedThisClassFields
     *            該類的屬性將不被序列化
     */
    public SpecificClassExclusionStrategy(Class<?> excludedThisClass, Class<?> excluedThisClassFields) {
        this.excludedThisClass = excludedThisClass;
        this.excludedThisClassFields = excluedThisClassFields;
    }

    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        if (clazz == null) return false;
        if (clazz.equals(excludedThisClass)) return true;
        return shouldSkipClass(clazz.getSuperclass());
    }

    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        return f.getDeclaringClass().equals(excludedThisClassFields);
    }

}

再看看這個如何使用,

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class Main {

    public static void main(String[] args) {
        Cnblogs bl = new Cnblogs();
        bl.setName("Cnblogs"); // 設置父類屬性
        bl.setCount(1);
        
        bl.setWelcome("代碼改變世界"); // 設置當前類屬性
        bl.setMembers(176473);
        bl.setUrl("http://www.cnblogs.com");
Gson gson
= new Gson(); // 通常我們使用的初始化方法 System.out.println(gson.toJson(bl));
     // 使用了過濾器的初始化方法 Gson gson2
= new GsonBuilder().setExclusionStrategies(new SpecificClassExclusionStrategy(null, ClassBase.class)).create(); System.out.println(gson2.toJson(bl)); } }

兩條打印語句結果如下:

{"welcome":"代碼改變世界","members":2030103,"url":"http://www.cnblogs.com","name":"Cnblogs","count":1}
{"welcome":"代碼改變世界","members":2030103,"url":"http://www.cnblogs.com"}

因此,我們只需要在項目中,將gson實例的創建方式改為gson2,並將過濾類的構造函數第二個參數設為com.activeandroid.Model.class,序列化就成功了!

至於第一個參數,比如類A,則任何類A的實例或者繼承自類A的類的實例,在序列化時都會返回null值,即不被序列化。

更復雜的序列化過濾規則,可以通過調整SpecificClassExclusionStrategy類中,兩個重寫方法來實現。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM