2015-06-21 2 views
6

У меня есть объект ArrayList, который я сохраняю в SharedPreferences в моем методе onPause. Когда я пытаюсь сериализации его JSON, я получаю следующее в журналах (эти 2 заявления повторить и перегружать LogCat):toJson метод, вызывающий зависание пользовательского интерфейса

06-20 20:33:31.620 26245-26252/com.example.app W/art﹕ Suspending all threads took: 21.556ms 
06-20 20:33:31.620 26245-26260/com.example.app W/art﹕ Suspending all threads took: 5.901ms 
06-20 20:33:31.650 26245-26260/com.example.app I/art﹕ Background partial concurrent mark sweep GC freed 210493(6MB) AllocSpace objects, 87(2MB) LOS objects, 25% free, 47MB/63MB, paused 16.970ms total 155.761ms 
06-20 20:33:32.480 26245-26260/com.example.app I/art﹕ Background sticky concurrent mark sweep GC freed 346396(10MB) AllocSpace objects, 140(4MB) LOS objects, 14% free, 48MB/56MB, paused 13ms total 88.199ms 

Я инициализации ArrayList в OnCreate, а затем дать ему объекты, когда я закончу выполнение Asynctask. Вот проблемный метод, который вызывает пользовательский интерфейс для замораживания:

@Override 
    protected void onPause() { 
    super.onPause(); 
    String json = mGson.toJson(mSelectedContactList); 
    mSharedPreferences.edit().putString("contact_list", json).apply(); 
    } 

Я также попытался следующие, и продолжать получать замораживание до:

JsonElement element = 
    mGson.toJsonTree(mSelectedContactList, new TypeToken<ArrayList<ContactObject>>() { 
    }.getType()); 
    String jsonString = element.getAsJsonArray().getAsString(); 

Я знаю, что это не то SharedPreferences, что является проблема. Я подозреваю, что метод toJson не может обрабатывать этот процесс, но я не могу понять, в чем проблема. Любая помощь будет высоко ценится.

* EDIT: Вот класс, который я использую:

public class ContactObject implements Parcelable { 

// Instance variables 
private String mID; 
private String mNumber; 
private String mName; 
private boolean mHasPhoto; 
private ArrayMap<Long, InboxSmsObject> mSentMessages; 
private ArrayMap<Long, OutboxSmsObject> mReceivedMessages; 
... 
} 
+0

Какой размер JSON вы сериализуете? попробуйте использовать список контактов только с одним элементом и посмотреть, все ли он застрял. – alfasin

+0

Я сериализую ArrayList объектов. Я проверил размер, и это всего лишь 7. Я попробую ваше предложение просто добавить его. –

+0

Каков тип объектов в списке массивов? вы не используете дженерики случайно, не так ли? https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/Gson.html#toJson(java.lang.Object) – alfasin

ответ

0

У меня была аналогичная проблема. Я мог почти гарантировать, что проблема связана с тем, что GSON с трудом сериализует ваш объект InboxSmsObject или OutboxSmsObject. Класс ContactObject выглядит просто, но вы должны иметь в виду, что GSON также придется сериализовать объекты в ArrayMap.

Первое, что вам нужно сделать, это попытаться изменить один или оба этих класса внутри класса ContactObject на некоторый простой класс, например String. Я был бы готов поспорить, что сериализация работает в этом сценарии.

Как только вы подтвердите, что это действительно так, вы можете работать над решением. Решением, которое я использовал, было создание простого класса с настройками, необходимыми для построения InboxSmsObject. Например, создайте класс с именем InboxSmsObjectSettings, который имеет только существенную информацию, необходимую для создания экземпляра класса InboxSmsObject (я бы предположил, что этому классу требуется всего несколько строк). Затем создать конструктор как

InboxSmsObject (настройки InboxSmsObjectSettings)

, так что вы можете легко создать экземпляр InboxSmsObject из настроек. Я знаю, что это не лучшее решение, так как вам придется перекодировать некоторые вещи, но это сработало для меня.

+0

В любом случае вы должны сделать это вне основной темы. –

+0

Я не согласен с Юджином. Если он пытается что-то выполнить, когда активность закрывается, то он должен делать это в основном потоке. Если вы сделаете это вне основного потока, вам не гарантируется, что сериализация завершится до очистки нового потока. Я пытался сделать то, что вы предлагаете, и не раз видел, как Android преждевременно убивает мою сериализацию. Это происходит, например, если пользователь перехватывает этот процесс из списка последних приложений. Единственный способ обеспечить сериализацию - сделать задачу настолько малой, насколько это возможно, и сделать это в основном потоке. –

+0

Вот почему мы не просто создаем потоки, как нам нравится, но используем специальные инструменты для Android, такие как [IntentService] (http://developer.android.com/reference/android/app/IntentService.html), которые ** a) * * не зависит от активности ** b) ** выполняется на рабочем потоке. –

0

Это может быть рекурсивный вопрос.

Пожалуйста, проверьте, если у Вас есть рекурсивные модели, например:

public class ClassA { 

    ClassB b; 

} 

public class ClassB { 

    List<ClassA> aList; 

} 
+0

Не совсем. Наличие рекурсивных отношений приведет к переполнению стека, а не к замораживанию.Сегодня я столкнулся с подобной проблемой, но, вероятно, возник из-за другой причины, и я действительно сомневаюсь, что из-за этого. –

0

Одна из возможных причин этого вопроса является ProGuard-ки над лексем типа, вероятно, когда запутывания не подавляется. Я тоже был очень похожая проблема, и общий сценарий был:

  • Там было простой внешний пакет видимого класса, содержащий TypeToken экземпляров только, таким образом, является маркером реестра типа для того, чтобы не создать экземпляр типа жетонов каждый раз, когда я нужна десериализация. Стоит отметить (но на самом деле это не влияет на случай), маркеры типа были выставлены как статические конечные поля, видимые в виде пакетов.
  • Существовал десериализатор, который ссылался на реестр.После выполнения самой первой десериализации (таким образом, , ссылаясь на класс реестра токенов типа), поток пользовательского интерфейса приложения зависает до тех пор, пока устройство не попросит, чтобы приложение было заморожено с просьбой остановить его.

Я не заметил сразу, что инициализаторы статического поля были причиной замораживания. После некоторой отладки я понял, что какой-то конструктор в абстрактном классе TypeToken вызывает зависание. Вот почему простой доступ к статическому полю заставил приложение замораживать. Я не могу вспомнить, какой конструктор вызывает его, но я бы сказал, что маркеры типа GSON могут работать в бесконечном цикле где-то в своих внутренних компонентах, если ваша параметризация токенов типа стирается во время ProGuard-ing. Так просто повторно настройка ProGuard исправляет проблему:

-keepattributes Signature 

Посмотреть больше для ProGuard Attributes.

0

Если у вас есть конструктор для ContactObject, просто удалите его. После этого он должен хорошо работать.

Смежные вопросы