【问题标题】:Infinite loop in.readTypedList method android parcelable无限循环 in.readTypedList 方法 android parcelable
【发布时间】:2014-04-18 13:58:59
【问题描述】:

我在体验 2-depth Parcelable 时遇到了一些问题。我有 3 个班级,包括他们自己作为这个架构:

Serie
    List<Qcm>
        List<Proposition>

他们都在实现来自android.os.Parcelable 的 Parcelable 接口。 当我尝试使用putExtra()Serie 对象传递给另一个活动时,就会出现问题,当我从要检索Serie 对象的活动中使用getParcelable() 时,会出现java.lang.OutOfMemoryError

正常的行为应该如下:

  • 一个 Serie 包含可变数量的 Qcm (N Qcm)
  • 一个 Qcm 包含 5 个命题

事实是,当我记录 createFromParcel() 调用时,我看到 Proposition 中的 createFromParcel() 在第一次循环迭代中被调用了 5 次,然后在下一次迭代中永远不会停止调用。

我的堆栈跟踪:

04-18 15:19:19.565  14089-14089/com.examed.maprepaquotidienne D/MPQ.Qcm.createFromParcel﹕ qcm cree
04-18 15:19:19.570  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.570  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.570  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.570  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.575  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.575  14089-14089/com.examed.maprepaquotidienne D/MPQ.Qcm.createFromParcel﹕ qcm cree
04-18 15:19:19.575  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.575  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.580  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.580  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.580  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.580  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.580  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.585  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.585  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.585  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.585  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.590  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.590  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.590  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.590  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.590  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.600  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree
04-18 15:19:19.600  14089-14089/com.examed.maprepaquotidienne D/MPQ.Proposition.createFromParcel﹕ proposition cree

Serie.java

package examed.lib.classes;

import android.content.Context;
import android.content.Intent;
import android.os.Parcel;
import android.os.Parcelable;
import examed.lib.DAO.FrequenceDAO;
import examed.lib.DAO.SerieDAO;
import examed.lib.DAO.UEDAO;
import examed.lib.workers.APIHelper;
import org.json.JSONException;
import org.json.JSONObject;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class Serie implements Parcelable
{

    private int id;
    private UE uniteEnseignement;
    private Frequence frq;
    private int type;
    private String authorFirstname, authorName, authorAvatar;
    private Date datePublication;
    private int anneeSerie, nbQcm, order;
    private String title, subtitle;
    private String beforeText;
    private String afterText;
    private List<Qcm> listeQcm = new ArrayList<Qcm>();
    private float chanceCoeff;
    private boolean enCreation;
    private boolean publiee;
    private Date dateValidationPubliee;
    private Date dateFinCreation;
    private int maxTime;
    private int statut;

    public Serie(Parcel in) throws ParseException, NullPointerException
    {
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        this.id = in.readInt();
        this.uniteEnseignement = in.readParcelable(UE.class.getClassLoader());
        this.frq = in.readParcelable(Frequence.class.getClassLoader());
        this.type = in.readInt();
        this.authorFirstname = in.readString();
        this.authorName = in.readString();
        this.authorAvatar = in.readString();
        this.datePublication = dateFormat.parse(in.readString());
        this.anneeSerie = in.readInt();
        this.nbQcm = in.readInt();
        this.order = in.readInt();
        this.title = in.readString();
        this.subtitle = in.readString();
        this.beforeText = in.readString();
        this.afterText = in.readString();
        in.readTypedList(this.listeQcm, Qcm.CREATOR);
        this.chanceCoeff = in.readFloat();
        this.enCreation = (in.readInt() > 0);
        this.publiee = (in.readInt() > 0);
        this.dateValidationPubliee = dateFormat.parse(in.readString());
        this.dateFinCreation = dateFormat.parse(in.readString());
        this.maxTime = in.readInt();
        this.statut = in.readInt();
    }

    [...]

    // region [PARCELABLE]

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

    public void writeToParcel(Parcel dest, int flags)
    {
        dest.writeInt(this.id);
        dest.writeParcelable(this.uniteEnseignement, flags);
        dest.writeParcelable(this.frq, flags);
        dest.writeInt(this.type);
        dest.writeString(this.authorFirstname);
        dest.writeString(this.authorName);
        dest.writeString(this.authorAvatar);
        dest.writeString(this.getDatePublication());
        dest.writeInt(this.anneeSerie);
        dest.writeInt(this.nbQcm);
        dest.writeInt(this.order);
        dest.writeString(this.title);
        dest.writeString(this.subtitle);
        dest.writeString(this.beforeText);
        dest.writeString(this.afterText);
        dest.writeTypedList(this.listeQcm);
        dest.writeDouble((double) this.chanceCoeff);
        dest.writeInt((this.enCreation) ? 1 : 0);
        dest.writeInt((this.publiee) ? 1 : 0);
        dest.writeString(this.getDateValidationPubliee());
        dest.writeString(this.getDateFinCreation());
        dest.writeInt(this.maxTime);
        dest.writeInt(this.statut);
    }

    public static final Parcelable.Creator<Serie> CREATOR = new Parcelable.Creator<Serie>()
    {
        @Override
        public Serie createFromParcel(Parcel source)
        {
            Serie serie = null;

            try {
                serie = new Serie(source);
            } catch (ParseException e) {
                e.printStackTrace();
            }

            return serie;
        }

        @Override
        public Serie[] newArray(int size)
        {
            return new Serie[size];
        }
    };

    // endregion
}

Qcm.java

package examed.lib.classes;

import android.os.Parcel;
import android.os.Parcelable;
import examed.lib.workers.APIHelper;
import org.json.JSONException;
import org.json.JSONObject;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class Qcm implements Parcelable
{
    private int id;
    private String question;
    private int typeNotation;
    private List<Proposition> propositions = new ArrayList<Proposition>();
    private Date dateCreation;
    private Date dateUpdate;
    private int typeChapitre;
    private boolean validee;
    private int annee;
    private boolean origineAnnale;
    private float coeff;
    private int duree;

    public static String FIELD_QCM_ID = "QCMID";
    public static String FIELD_QCM_QUESTION = "Question";
    public static String FIELD_QCM_TYPE_NOTATION_ID = "TypeNotationID";
    public static String FIELD_QCM_DATE_CREATION = "DateCreation";
    public static String FIELD_QCM_DATE_MODIF = "DateUpdate";
    public static String FIELD_QCM_TYPE_CHAPITRE = "TypeChapitreID";
    public static String FIELD_QCM_VALIDEE = "Validee";
    public static String FIELD_QCM_ANNEE = "Annee";
    public static String FIELD_QCM_ORIGINE_ANNALE = "OrigineAnnale";
    public static String FIELD_QCM_COEFF = "coef";
    public static String FIELD_QCM_DUREE = "dureeQCM";


    public Qcm(Parcel in) throws ParseException
    {
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        this.id = in.readInt();
        this.question = in.readString();
        this.typeNotation = in.readInt();
        in.readTypedList(this.propositions, Proposition.CREATOR);
        this.dateCreation = dateFormat.parse(in.readString());
        this.dateUpdate = dateFormat.parse(in.readString());
        this.typeChapitre = in.readInt();
        this.validee = (in.readInt() > 0);
        this.annee = in.readInt();
        this.origineAnnale = (in.readInt() > 0);
        this.coeff = in.readFloat();
        this.duree = in.readInt();
    }

    // region [PARCELABLE]

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

    public void writeToParcel(Parcel dest, int flags)
    {
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        dest.writeInt(this.id);
        dest.writeString(this.question);
        dest.writeInt(this.typeNotation);
        dest.writeTypedList(this.propositions);
        dest.writeString(dateFormat.format(this.dateCreation));
        dest.writeString(dateFormat.format(this.dateUpdate));
        dest.writeInt(this.typeChapitre);
        dest.writeInt((this.validee) ? 1 : 0);
        dest.writeInt(this.annee);
        dest.writeInt((this.origineAnnale) ? 1 : 0);
        dest.writeDouble((double)this.coeff);
        dest.writeInt(this.duree);
    }

    public static final Parcelable.Creator<Qcm> CREATOR = new Parcelable.Creator<Qcm>()
    {
        @Override
        public Qcm createFromParcel(Parcel source)
        {
            Qcm qcm = null;
            APIHelper.log('d', "qcm cree");
            try {
                qcm = new Qcm(source);
            } catch (ParseException e) {
                e.printStackTrace();
            }

            return qcm;
        }

        @Override
        public Qcm[] newArray(int size)
        {
            return new Qcm[size];
        }
    };

    // endregion

}

Proposition.java

package examed.lib.classes;

import android.os.Parcel;
import android.os.Parcelable;
import examed.lib.workers.APIHelper;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;

public class Proposition implements Parcelable
{

    private String content;
    private boolean toCheck;
    private String correction;


    public Proposition(Parcel in) throws ParseException
    {
        this.content = in.readString();
        this.toCheck = (in.readInt() > 0);
        this.correction = in.readString();
    }

    // region [PARCELABLE]

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

    public void writeToParcel(Parcel dest, int flags)
    {
        dest.writeString(this.content);
        dest.writeInt((this.toCheck) ? 1 : 0);
        dest.writeString(this.correction);
    }

    public static final Parcelable.Creator<Proposition> CREATOR = new Parcelable.Creator<Proposition>()
    {
        @Override
        public Proposition createFromParcel(Parcel source)
        {
            Proposition proposition = null;

            try {
                proposition = new Proposition(source);
                APIHelper.log('d', "proposition cree");
            } catch (ParseException e) {
                e.printStackTrace();
            }

            return proposition;
        }

        @Override
        public Proposition[] newArray(int size)
        {
            return new Proposition[size];
        }
    };

    // endregion

}

我如何在目标 Activity 中执行 getParcelable

Intent intent = getIntent();

if(intent.getExtras() != null)
{
    APIHelper.log('d', intent.getExtras().getParcelable("SELECTED_SERIE"));
    this.serie = intent.getExtras().getParcelable("SELECTED_SERIE");
    APIHelper.log('d', this.serie);
}

如果您还需要其他东西,请告诉我。我已经坚持了几个小时,我真的不明白。 谢谢!

【问题讨论】:

    标签: android arraylist out-of-memory infinite-loop parcelable


    【解决方案1】:

    最后使用一个变通解决方案,我一直在使用我的 JSON 响应,将它提供给下一个带有附加功能的活动,并在下一个活动上构建我的对象。

    我认为这是一个奇怪的解决方案,但似乎叠瓦状可包裹物体的深度太长会变得疯狂。

    希望对你有帮助。

    【讨论】:

    • 如果您有多深度 Parcelables,您应该尝试为它创建一个包含大量数据的单元测试,以查看它是否不会耗尽内存或需要很长时间才能加载。原始类型的简单列表应该不是什么大问题,但是当对象变得更复杂时,可能会占用大量内存和时间。
    • 我会在下一个版本中尝试,谢谢你的建议。老实说,就我自己而言,我认为这不是复杂对象的问题,我的对象上最常用的类型是基元。不过,我会尝试你的建议。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-28
    • 1970-01-01
    • 1970-01-01
    • 2011-05-11
    • 1970-01-01
    • 2022-08-15
    相关资源
    最近更新 更多