Страница 1 из 3
static HashMap<> - являются ли добавленные данные статичными
Добавлено: 14 янв 2015, 10:57
sanya5791
Здравствуйте.
Мне нужно по ходу программы накапливать данные. Для этого я решил использовать в отдельном классе поле static EnumMap<MyEnum, Object> emap = new EnumMap<>(MyEnum.class);
Проблема в том, что иногда некоторые элементы key-value пропадают. Если я правильно понимаю, то проблема в том, что при объявлении static статичным является только объявленная ссылка на emap, а все позже добавленные элементы уже нестатические и следовательно могут пропадать.
Посоветуйте, плиз, что лучше применять для моей задачи: накапливать небольшое количество элементов<enum, Oject>, которые я собираю из многих фрагментов.
Спасибо.
Re: static HashMap<> - являются ли добавленные данные статич
Добавлено: 14 янв 2015, 11:26
Mikhail_dev
EnumMap != HashMap.
P.S. ничего просто так не пропадает. Сформулируйте конкретнее что у вас там
Re: static HashMap<> - являются ли добавленные данные статич
Добавлено: 14 янв 2015, 12:21
sanya5791
Да, действительно, я заменил HashMap на EnumMap. Извините за попытку ввести Вас в заблуждение
Вот класс, в котором находится static EnumMap:
Код: Выделить всё
package ua.sanya5791.pochemu;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.EnumMap;
import ua.sanya5791.pochemu.db.DbQueryTask;
import ua.sanya5791.pochemu.db.DbStatements.LessonInsert;
import android.app.ActionBar;
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.SimpleAdapter;
/**
* Этот класс собирает в ArrayList "data" все необходимые данные для использования в запросе LESSON_INSERT;
* @author sanya
*
*/
public class TempDataLesson {
static String TAG = "DataLessonInsert";
private static final boolean isDebug = true;
//здесь объявляю
private static EnumMap<LessonInsert, Object> emap = new EnumMap<>(LessonInsert.class);
public TempDataLesson() {
}
/**
*добавляет связку key-value to HashMap;
*
*/
void addToEnumMap(LessonInsert key, Object value){
Object oldValue = emap.put(key,value);
}
/**
* делает проверку на наличие минимума необходимых элементов в HashMap.
* @param emap входящий
* @return true; Если кого-то нет, то false
*/
private boolean isValidHashMap() {
//обязательный список элементов
LessonInsert[] emapKeys = {
LessonInsert.I_PERSON_ID,
LessonInsert.I_DATE_LESSON,
LessonInsert.I_ZONE_ID,
LessonInsert.I_SUBZONE_ID,
LessonInsert.I_MATERIAL_ID,
};
if(emap.get(LessonInsert.I_PERSON_ID) == null)
MyLogger("Не хвататет обязательного поля: "
+ LessonInsert.I_PERSON_ID.toString()
+ " для выполнения запроса LESSON_INSERT");
for(LessonInsert key : emapKeys){
if(emap.get(key) == null)
MyLogger("Не хвататет обязательного поля: "
+ key.toString() + " для выполнения запроса LESSON_INSERT");
if(! emap.containsKey(key)){
MyLogger("Не хвататет обязательного поля: "
+ key.toString() + " для выполнения запроса LESSON_INSERT");
return false;
}
}
return true;
}
/**
*
* @return either completed HashMap or null;
* null in case the HashMap is not completely filled
*/
EnumMap<LessonInsert,Object> getFilled(){
//метод: вернуть заполненный HashMap
if (isValidHashMap()) {
return emap;
} else {
return null;
}
}
void clear(){
emap.clear();
}
void newEMap(){
emap=new EnumMap<>(LessonInsert.class);
}
private void MyLogger(String statement){
if (isDebug) {
Log.v(TAG, statement);
}
}
@Override
protected void finalize() throws Throwable {
// TODO Auto-generated method stub
super.finalize();
clear();
}
}
А вот пример класса, который добавляет новый элемент.
Добавление происходит в конце метода onCreateView. Сначала я создаю новый экземпляр класса
tdl = new TempDataLesson(); и затем добавляю элемент используя метод addToEnumMap.
Код: Выделить всё
class FrZonesList1 extends Fragment implements MyInterfaces{
static String TAG = "sanya5791.pochemuchka.FragmentZonesList";
private static final boolean isDebug = true;
int selectedZone_id;
private Activity curActivity; //base Activity who places the fragment
private ResultSet rs;
private SimpleAdapter adapter;
private ListView lv;
private OnLvSelectListener onLvSelectListener;
private DbQueryTask<FrZonesList> getZonesTask;
private TempDataLesson tdl;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
curActivity = activity;
//check whether the calling activity has implemented OnSelectedZoneListener
try {
onLvSelectListener=(OnLvSelectListener)activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnLvSelectListener");
}
}
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
MyLogger("onCreateView: ");
View viewF = inflater.inflate(R.layout.fragment_zones_list,
container, false);
ActionBar actionBar = curActivity.getActionBar();
actionBar.setTitle("Список зон");
lv = (ListView) viewF.findViewById(R.id.lv_out1);
lv.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
MyLogger("The item N" + position + " is selected" +
"\nIt contains" + parent.getAdapter().getItem(position));
try {
rs.absolute(position+1);
selectedZone_id = rs.getInt("ZONE_ID");
// так мы передаем через метод onSelectedZone интерфеса OnSelectedZoneListener id зоны НАЖАТОГО элемента списка lv
onLvSelectListener.onLvSelected(this, selectedZone_id);
} catch (SQLException e) {
e.printStackTrace();
}
//так я добавляю новые элементы
tdl = new TempDataLesson();
tdl.addToEnumMap(
LessonInsert.I_ZONE_ID,
selectedZone_id);
}
});
return viewF;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
MyLogger("onActivityCreated: ");
}
private void MyLogger(String statement){
if (isDebug) {
Log.v(TAG, statement);
}
}
}
Блин, не могу понять что я делаю не так

Re: static HashMap<> - являются ли добавленные данные статич
Добавлено: 14 янв 2015, 12:30
sanya5791
Кстати, сейчас переделываю код, где метод TempDataLesson.addToEnumMap(LessonInsert, Object) я сделал static.
Так не требуется создавать экземпляр класса TempDataLesson для обращения к методу добавления addToEnumMap - может здесь собака порылась. И пропадания элементов в EnumMap пока не замечено. Но хочу разобраться в матчасти.
Re: static HashMap<> - являются ли добавленные данные статич
Добавлено: 14 янв 2015, 12:40
Foenix
я не пойму, зачем тут вообще статики??
Re: static HashMap<> - являются ли добавленные данные статич
Добавлено: 14 янв 2015, 12:42
Mikhail_dev
Когда именно они пропадают? И зачем вам метод newEMap? Этот метод затирает ваши данные в коллекции
Но хочу разобраться в матчасти.
Правильно, разберитесь в матчасти, а именно отличие статических объектов от динамических, а также отличие статических методов от динамических
Re: static HashMap<> - являются ли добавленные данные статич
Добавлено: 14 янв 2015, 18:45
KamiSempai
Я советую ни когда не использовать статик переменные, если в них хранится какая, либо нужная информация. Логику в статике можно хранить, но ни как не данные.
Для того, что бы понять свою ошибку, добавьте следующий код по нажатию на кнопку:
[syntax=java5] Thread systemExitThread = new Thread() {
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
return;
}
runOnUiThread(new Runnable() {
public void run() {
System.exit(0);
}
});
};
};
systemExitThread .start();[/syntax] После нажатия сразу сверните приложение, через 5 секунд разверните. Активити должно восстановиться до состояния перед сворачиванием. В вашем же случае все данные будут затерты.
System.exit(0) - Имитация ситуации когда приложение находится долго в свернутом состоянии.
Для хранения данных нужно использовать Preferences, Базу данных или файл. Как бы это было не печально, но таков Android.
Re: static HashMap<> - являются ли добавленные данные статич
Добавлено: 14 янв 2015, 19:20
Foenix
Денис, да у него данные во фрагментах, их можно в любую переменную/свойство активити собирать. Зачем эти заморочки, статики вообще не пойму я.
Re: static HashMap<> - являются ли добавленные данные статич
Добавлено: 14 янв 2015, 21:00
sanya5791
KamiSempai писал(а):Я советую ни когда не использовать статик переменные, если в них хранится какая, либо нужная информация. Логику в статике можно хранить, но ни как не данные.
Для того, что бы понять свою ошибку, добавьте следующий код по нажатию на кнопку:
[syntax=java5] Thread systemExitThread = new Thread() {
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
return;
}
runOnUiThread(new Runnable() {
public void run() {
System.exit(0);
}
});
};
};
systemExitThread .start();[/syntax] После нажатия сразу сверните приложение, через 5 секунд разверните. Активити должно восстановиться до состояния перед сворачиванием. В вашем же случае все данные будут затерты.
System.exit(0) - Имитация ситуации когда приложение находится долго в свернутом состоянии.
Спасибо большое за разъяснения.
KamiSempai писал(а):
Для хранения данных нужно использовать Preferences, Базу данных или файл. Как бы это было не печально, но таков Android.
Да, я ранее уже где-то встречал информацию о том, что для хранения данных лучше не рассчитывать на static. Спасибо!!! Пересмотрю подход

Re: static HashMap<> - являются ли добавленные данные статич
Добавлено: 14 янв 2015, 21:10
sanya5791
Разобрался в своей проблеме. Дело в том, что я в TempDataLesson.finalize() добавил emap.clear() - очистку своего EnumMap. Получается, что я создавал новые экзепляры TempDataLesson из фрагментов, а когда фрагменты прибивались, то и прибивались все связанные ресурсы, а следовательно и отрабатывал TempDataLesson.finalize().
А когда я изменил метод TempDataLesson.addToEnumMap на static, то для его вызова не нужно было создавать новый экземпляр класса TempDataLesson. Следовательно при высвобождении ресурсов не вызывался метод TempDataLesson.finalize(). Т.о. проблема была workaround.
Когда я это понял, то убрал очистку Мар из TempDataLesson.finalize() и убрал static - все заработало, ура!!!
Еще раз спасибо KamiSempai. Теперь нужно будет все хранить в Preferences.
Re: static HashMap<> - являются ли добавленные данные статич
Добавлено: 14 янв 2015, 21:22
Mikhail_dev
Может кто мне пояснит русским языком почему статики это плохо? Я вот ни одного аргумента не услышал
После нажатия сразу сверните приложение, через 5 секунд разверните. Активити должно восстановиться до состояния перед сворачиванием. В вашем же случае все данные будут затерты.
System.exit(0) - Имитация ситуации когда приложение находится долго в свернутом состоянии.
Чего?! А с этого момента поподробнее. С чего вдруг system.exit(0) - это имитация сворчачивания? Денис, ты ли это? о_О Это закрытие процесса, даже не процесса, а приложения, и он сработал так, как надо в этом коде. Нам как-то рассказывали как один человек в JavaEE приложении ввёл эту команду в простой обработчик ошибки. И эта строчка закрыла всё приложение, которое разворачивается не один десяток минут, работая на множестве серверов.
Вернусь к нашим баранам. Итак, что не так со статиками? Да, я читал что мол данные в нём могут пропадать, но по факту читал единожды, в одном месте, при этом ни разу не встречал такого. Если статик теряет данные, то:
1) почему паттерн ViewHolder, объявленный как статик класс такой популярный?
2) почему статик переменные (без final префикса) также популярны?
Я знаю один минус статиков - можно получить утечку. Всё другое больше смахивает на миф, либо на адски редкие случаи чего-то там-то.
Разобрался в своей проблеме. Дело в том, что я в TempDataLesson.finalize()
На сколько я помню, этот метод не рекомендуется использовать, дабы не отстрелить себе чего. Хотите освободить память? System.gc() вам в помощь.
Re: static HashMap<> - являются ли добавленные данные статич
Добавлено: 15 янв 2015, 10:28
sanya5791
Да, возвращаясь на нашим баранам и подтянув матчасть хочу изложить ход своих размышлений, а Вы поправьте, плиз.
Итак, объявлен
static HashMap<T, V> hmap = new HashMap<String, String>. Это значит, что при первом обращении к его классу, hmap инициализируется в первую очередь и под него статически выделяется память. Сколько под него может быть выделно памяти? Ровно столько, сколько нужно чтобы
статически хранить ссылку на hmap, к которой прикрепляется
динамический объект с местом для хранения
16 ячеек.
Затем мы заполняем hmap.put("key", "value"). Это значит, что мы заполняем первые 16 ячеек, когда они закончатся будет выделен новый объект с новыми ячейками и паровозом прикрепится к статической ссылке hmap и ранее выделенным 16-ти ячейкам.
Т.е. мы имеем статическую ссылку и за ней паровоз объектов. Сборщик мусора уничтожает только те объекты, на которые нет активных ссылок в коде, а наша ссылка hmap всегда активна, а занчит и все
динамические объекты будут жить до тех пор, пока мы не сделаем hmap.clear(). И эту очистку нужно делать самостоятельно, если хочешь избежать "мифических утечек".
И конечно, если приложение будет остановлено системой, то все линки на объекты утратят актуальность и будут очищены сборщиком мусора - следовательно и очиститься нашь static hmap.
Вроде так. Поправьте, если я где ошибаюсь.
Re: static HashMap<> - являются ли добавленные данные статич
Добавлено: 15 янв 2015, 10:56
Mikhail_dev
чтобы статически хранить ссылку на hmap
Что значит хранить статически ссылку? Ссылка она и в Африке ссылка на сколько мне известно, и не имеет различий динамически и статически
когда они закончатся будет выделен новый объект с новыми ячейками и паровозом прикрепится к статической ссылке hmap и ранее выделенным 16-ти ячейкам.
Да
Сборщик мусора уничтожает только те объекты, на которые нет активных ссылок в коде, а наша ссылка hmap всегда активна, а занчит и все динамические объекты будут жить до тех пор, пока мы не сделаем hmap.clear()
Да.
И эту очистку нужно делать самостоятельно, если хочешь избежать "мифических утечек".
Да, либо использовать WeakReference
И конечно, если приложение будет остановлено системой, то все линки на объекты утратят актуальность и будут очищены сборщиком мусора - следовательно и очиститься нашь static hmap.
Если приложение умрёт, то по определению у вас ничего не останется доступным =). У каждого приложения своя песочница.
Re: static HashMap<> - являются ли добавленные данные статич
Добавлено: 15 янв 2015, 16:42
KamiSempai
Mikhail_dev писал(а):Может кто мне пояснит русским языком почему статики это плохо? Я вот ни одного аргумента не услышал
Когда система грохает приложение все статики затираются, поэтому в них нельзя хранить информацию, которую нельзя восстановить из другого места.
Mikhail_dev писал(а):
После нажатия сразу сверните приложение, через 5 секунд разверните. Активити должно восстановиться до состояния перед сворачиванием. В вашем же случае все данные будут затерты.
System.exit(0) - Имитация ситуации когда приложение находится долго в свернутом состоянии.
Чего?! А с этого момента поподробнее. С чего вдруг system.exit(0) - это имитация сворчачивания? Денис, ты ли это? о_О Это закрытие процесса, даже не процесса, а приложения, и он сработал так, как надо в этом коде.
Я не говорил, что это имитация сворачивания, это имитация долгого нахождения в свернутом состоянии. Уж поверь мне, я на это много времени потратил. Судя по тому, что говорят в интернетах, это именно то, что делает система для освобождения памяти от давно свернутых приложений.
Re: static HashMap<> - являются ли добавленные данные статич
Добавлено: 15 янв 2015, 16:50
Mikhail_dev
Я не понял из твоих слов каким боком тут статик ссылки. разговор о System.exit(0) не входит сюда никаким образом и тот код очень странный.
Re: static HashMap<> - являются ли добавленные данные статич
Добавлено: 15 янв 2015, 17:48
KamiSempai
Mikhail_dev писал(а):Я не понял из твоих слов каким боком тут статик ссылки. разговор о System.exit(0) не входит сюда никаким образом и тот код очень странный.
System.exit(0) убивает все статик ссылки.
Re: static HashMap<> - являются ли добавленные данные статич
Добавлено: 15 янв 2015, 18:16
Mikhail_dev
Он убивает приложение, а не статик ссылки. Покажи мне ссылки где написано что убивает статик ссылки.
Re: static HashMap<> - являются ли добавленные данные статич
Добавлено: 15 янв 2015, 18:55
KamiSempai
System.exit(0) убивает приложение
+
Убитое приложение теряет все статик ссылки
=
System.exit(0) убивает все статик ссылки.
Re: static HashMap<> - являются ли добавленные данные статич
Добавлено: 15 янв 2015, 19:29
Mikhail_dev
Великолепная логика
"Не используйте статик ссылки. Вы можете проверить почему, запустив команду System.exit(0), которая убьёт приложение, а с ним и все статик ссылки. То, что оно убьёт вообще все приложение со всеми его статическимиp и динамическими объектами, а не просто статические, это неважно. Главное помните - не используйте статик ссылки".
В итоге вопрос: почему нельзя использовать статик ссылки?
Re: static HashMap<> - являются ли добавленные данные статич
Добавлено: 16 янв 2015, 12:42
KamiSempai
Используя эту логику я могу написать приложение которое развернется и продолжит свою работу как ни в чем не бывало даже если его убить этой командой. А система это может сделать. Ей наплевать, что у тебя там статика или динамика.