static HashMap<> - являются ли добавленные данные статичными

SQLite, Preferences, файлы, SD, Content Provider, XML, JSON
sanya5791
Сообщения: 20
Зарегистрирован: 10 окт 2014, 15:22
Откуда: Днепропетровск

static HashMap<> - являются ли добавленные данные статичными

Сообщение sanya5791 » 14 янв 2015, 10:57

Здравствуйте.
Мне нужно по ходу программы накапливать данные. Для этого я решил использовать в отдельном классе поле static EnumMap<MyEnum, Object> emap = new EnumMap<>(MyEnum.class);
Проблема в том, что иногда некоторые элементы key-value пропадают. Если я правильно понимаю, то проблема в том, что при объявлении static статичным является только объявленная ссылка на emap, а все позже добавленные элементы уже нестатические и следовательно могут пропадать.
Посоветуйте, плиз, что лучше применять для моей задачи: накапливать небольшое количество элементов<enum, Oject>, которые я собираю из многих фрагментов.
Спасибо.

Аватара пользователя
Mikhail_dev
Сообщения: 2386
Зарегистрирован: 09 янв 2012, 14:45
Откуда: Самара

Re: static HashMap<> - являются ли добавленные данные статич

Сообщение Mikhail_dev » 14 янв 2015, 11:26

EnumMap != HashMap.
P.S. ничего просто так не пропадает. Сформулируйте конкретнее что у вас там

sanya5791
Сообщения: 20
Зарегистрирован: 10 окт 2014, 15:22
Откуда: Днепропетровск

Re: static HashMap<> - являются ли добавленные данные статич

Сообщение sanya5791 » 14 янв 2015, 12:21

Да, действительно, я заменил 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);
		}
	}
}
Блин, не могу понять что я делаю не так :-(

sanya5791
Сообщения: 20
Зарегистрирован: 10 окт 2014, 15:22
Откуда: Днепропетровск

Re: static HashMap<> - являются ли добавленные данные статич

Сообщение sanya5791 » 14 янв 2015, 12:30

Кстати, сейчас переделываю код, где метод TempDataLesson.addToEnumMap(LessonInsert, Object) я сделал static.
Так не требуется создавать экземпляр класса TempDataLesson для обращения к методу добавления addToEnumMap - может здесь собака порылась. И пропадания элементов в EnumMap пока не замечено. Но хочу разобраться в матчасти.

Аватара пользователя
Foenix
Сообщения: 4201
Зарегистрирован: 20 окт 2012, 12:01

Re: static HashMap<> - являются ли добавленные данные статич

Сообщение Foenix » 14 янв 2015, 12:40

я не пойму, зачем тут вообще статики??
R.id.team

NullPointerException - что делать???
viewtopic.php?f=33&t=3899&p=28952#p28952
Где моя ошибка?
viewtopic.php?f=60&t=3198

Аватара пользователя
Mikhail_dev
Сообщения: 2386
Зарегистрирован: 09 янв 2012, 14:45
Откуда: Самара

Re: static HashMap<> - являются ли добавленные данные статич

Сообщение Mikhail_dev » 14 янв 2015, 12:42

Когда именно они пропадают? И зачем вам метод newEMap? Этот метод затирает ваши данные в коллекции
Но хочу разобраться в матчасти.
Правильно, разберитесь в матчасти, а именно отличие статических объектов от динамических, а также отличие статических методов от динамических

Аватара пользователя
KamiSempai
Сообщения: 1339
Зарегистрирован: 17 фев 2012, 21:23
Откуда: Мордор

Re: static HashMap<> - являются ли добавленные данные статич

Сообщение KamiSempai » 14 янв 2015, 18:45

Я советую ни когда не использовать статик переменные, если в них хранится какая, либо нужная информация. Логику в статике можно хранить, но ни как не данные.
Для того, что бы понять свою ошибку, добавьте следующий код по нажатию на кнопку:
[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.
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

Аватара пользователя
Foenix
Сообщения: 4201
Зарегистрирован: 20 окт 2012, 12:01

Re: static HashMap<> - являются ли добавленные данные статич

Сообщение Foenix » 14 янв 2015, 19:20

Денис, да у него данные во фрагментах, их можно в любую переменную/свойство активити собирать. Зачем эти заморочки, статики вообще не пойму я.
R.id.team

NullPointerException - что делать???
viewtopic.php?f=33&t=3899&p=28952#p28952
Где моя ошибка?
viewtopic.php?f=60&t=3198

sanya5791
Сообщения: 20
Зарегистрирован: 10 окт 2014, 15:22
Откуда: Днепропетровск

Re: static HashMap<> - являются ли добавленные данные статич

Сообщение sanya5791 » 14 янв 2015, 21:00

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. Спасибо!!! Пересмотрю подход :D

sanya5791
Сообщения: 20
Зарегистрирован: 10 окт 2014, 15:22
Откуда: Днепропетровск

Re: static HashMap<> - являются ли добавленные данные статич

Сообщение sanya5791 » 14 янв 2015, 21:10

Разобрался в своей проблеме. Дело в том, что я в TempDataLesson.finalize() добавил emap.clear() - очистку своего EnumMap. Получается, что я создавал новые экзепляры TempDataLesson из фрагментов, а когда фрагменты прибивались, то и прибивались все связанные ресурсы, а следовательно и отрабатывал TempDataLesson.finalize().
А когда я изменил метод TempDataLesson.addToEnumMap на static, то для его вызова не нужно было создавать новый экземпляр класса TempDataLesson. Следовательно при высвобождении ресурсов не вызывался метод TempDataLesson.finalize(). Т.о. проблема была workaround.

Когда я это понял, то убрал очистку Мар из TempDataLesson.finalize() и убрал static - все заработало, ура!!!

Еще раз спасибо KamiSempai. Теперь нужно будет все хранить в Preferences.

Аватара пользователя
Mikhail_dev
Сообщения: 2386
Зарегистрирован: 09 янв 2012, 14:45
Откуда: Самара

Re: static HashMap<> - являются ли добавленные данные статич

Сообщение Mikhail_dev » 14 янв 2015, 21:22

Может кто мне пояснит русским языком почему статики это плохо? Я вот ни одного аргумента не услышал
После нажатия сразу сверните приложение, через 5 секунд разверните. Активити должно восстановиться до состояния перед сворачиванием. В вашем же случае все данные будут затерты.
System.exit(0) - Имитация ситуации когда приложение находится долго в свернутом состоянии.
Чего?! А с этого момента поподробнее. С чего вдруг system.exit(0) - это имитация сворчачивания? Денис, ты ли это? о_О Это закрытие процесса, даже не процесса, а приложения, и он сработал так, как надо в этом коде. Нам как-то рассказывали как один человек в JavaEE приложении ввёл эту команду в простой обработчик ошибки. И эта строчка закрыла всё приложение, которое разворачивается не один десяток минут, работая на множестве серверов.

Вернусь к нашим баранам. Итак, что не так со статиками? Да, я читал что мол данные в нём могут пропадать, но по факту читал единожды, в одном месте, при этом ни разу не встречал такого. Если статик теряет данные, то:
1) почему паттерн ViewHolder, объявленный как статик класс такой популярный?
2) почему статик переменные (без final префикса) также популярны?

Я знаю один минус статиков - можно получить утечку. Всё другое больше смахивает на миф, либо на адски редкие случаи чего-то там-то.
Разобрался в своей проблеме. Дело в том, что я в TempDataLesson.finalize()
На сколько я помню, этот метод не рекомендуется использовать, дабы не отстрелить себе чего. Хотите освободить память? System.gc() вам в помощь.

sanya5791
Сообщения: 20
Зарегистрирован: 10 окт 2014, 15:22
Откуда: Днепропетровск

Re: static HashMap<> - являются ли добавленные данные статич

Сообщение sanya5791 » 15 янв 2015, 10:28

Да, возвращаясь на нашим баранам и подтянув матчасть хочу изложить ход своих размышлений, а Вы поправьте, плиз.
Итак, объявлен static HashMap<T, V> hmap = new HashMap<String, String>. Это значит, что при первом обращении к его классу, hmap инициализируется в первую очередь и под него статически выделяется память. Сколько под него может быть выделно памяти? Ровно столько, сколько нужно чтобы статически хранить ссылку на hmap, к которой прикрепляется динамический объект с местом для хранения 16 ячеек.
Затем мы заполняем hmap.put("key", "value"). Это значит, что мы заполняем первые 16 ячеек, когда они закончатся будет выделен новый объект с новыми ячейками и паровозом прикрепится к статической ссылке hmap и ранее выделенным 16-ти ячейкам.
Т.е. мы имеем статическую ссылку и за ней паровоз объектов. Сборщик мусора уничтожает только те объекты, на которые нет активных ссылок в коде, а наша ссылка hmap всегда активна, а занчит и все динамические объекты будут жить до тех пор, пока мы не сделаем hmap.clear(). И эту очистку нужно делать самостоятельно, если хочешь избежать "мифических утечек".
И конечно, если приложение будет остановлено системой, то все линки на объекты утратят актуальность и будут очищены сборщиком мусора - следовательно и очиститься нашь static hmap.
Вроде так. Поправьте, если я где ошибаюсь.

Аватара пользователя
Mikhail_dev
Сообщения: 2386
Зарегистрирован: 09 янв 2012, 14:45
Откуда: Самара

Re: static HashMap<> - являются ли добавленные данные статич

Сообщение Mikhail_dev » 15 янв 2015, 10:56

чтобы статически хранить ссылку на hmap
Что значит хранить статически ссылку? Ссылка она и в Африке ссылка на сколько мне известно, и не имеет различий динамически и статически
когда они закончатся будет выделен новый объект с новыми ячейками и паровозом прикрепится к статической ссылке hmap и ранее выделенным 16-ти ячейкам.
Да
Сборщик мусора уничтожает только те объекты, на которые нет активных ссылок в коде, а наша ссылка hmap всегда активна, а занчит и все динамические объекты будут жить до тех пор, пока мы не сделаем hmap.clear()
Да.
И эту очистку нужно делать самостоятельно, если хочешь избежать "мифических утечек".
Да, либо использовать WeakReference
И конечно, если приложение будет остановлено системой, то все линки на объекты утратят актуальность и будут очищены сборщиком мусора - следовательно и очиститься нашь static hmap.
Если приложение умрёт, то по определению у вас ничего не останется доступным =). У каждого приложения своя песочница.

Аватара пользователя
KamiSempai
Сообщения: 1339
Зарегистрирован: 17 фев 2012, 21:23
Откуда: Мордор

Re: static HashMap<> - являются ли добавленные данные статич

Сообщение KamiSempai » 15 янв 2015, 16:42

Mikhail_dev писал(а):Может кто мне пояснит русским языком почему статики это плохо? Я вот ни одного аргумента не услышал
Когда система грохает приложение все статики затираются, поэтому в них нельзя хранить информацию, которую нельзя восстановить из другого места.
Mikhail_dev писал(а):
После нажатия сразу сверните приложение, через 5 секунд разверните. Активити должно восстановиться до состояния перед сворачиванием. В вашем же случае все данные будут затерты.
System.exit(0) - Имитация ситуации когда приложение находится долго в свернутом состоянии.
Чего?! А с этого момента поподробнее. С чего вдруг system.exit(0) - это имитация сворчачивания? Денис, ты ли это? о_О Это закрытие процесса, даже не процесса, а приложения, и он сработал так, как надо в этом коде.
Я не говорил, что это имитация сворачивания, это имитация долгого нахождения в свернутом состоянии. Уж поверь мне, я на это много времени потратил. Судя по тому, что говорят в интернетах, это именно то, что делает система для освобождения памяти от давно свернутых приложений.
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

Аватара пользователя
Mikhail_dev
Сообщения: 2386
Зарегистрирован: 09 янв 2012, 14:45
Откуда: Самара

Re: static HashMap<> - являются ли добавленные данные статич

Сообщение Mikhail_dev » 15 янв 2015, 16:50

Я не понял из твоих слов каким боком тут статик ссылки. разговор о System.exit(0) не входит сюда никаким образом и тот код очень странный.

Аватара пользователя
KamiSempai
Сообщения: 1339
Зарегистрирован: 17 фев 2012, 21:23
Откуда: Мордор

Re: static HashMap<> - являются ли добавленные данные статич

Сообщение KamiSempai » 15 янв 2015, 17:48

Mikhail_dev писал(а):Я не понял из твоих слов каким боком тут статик ссылки. разговор о System.exit(0) не входит сюда никаким образом и тот код очень странный.
System.exit(0) убивает все статик ссылки.
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

Аватара пользователя
Mikhail_dev
Сообщения: 2386
Зарегистрирован: 09 янв 2012, 14:45
Откуда: Самара

Re: static HashMap<> - являются ли добавленные данные статич

Сообщение Mikhail_dev » 15 янв 2015, 18:16

Он убивает приложение, а не статик ссылки. Покажи мне ссылки где написано что убивает статик ссылки.

Аватара пользователя
KamiSempai
Сообщения: 1339
Зарегистрирован: 17 фев 2012, 21:23
Откуда: Мордор

Re: static HashMap<> - являются ли добавленные данные статич

Сообщение KamiSempai » 15 янв 2015, 18:55

System.exit(0) убивает приложение
+
Убитое приложение теряет все статик ссылки
=
System.exit(0) убивает все статик ссылки.
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

Аватара пользователя
Mikhail_dev
Сообщения: 2386
Зарегистрирован: 09 янв 2012, 14:45
Откуда: Самара

Re: static HashMap<> - являются ли добавленные данные статич

Сообщение Mikhail_dev » 15 янв 2015, 19:29

Великолепная логика
"Не используйте статик ссылки. Вы можете проверить почему, запустив команду System.exit(0), которая убьёт приложение, а с ним и все статик ссылки. То, что оно убьёт вообще все приложение со всеми его статическимиp и динамическими объектами, а не просто статические, это неважно. Главное помните - не используйте статик ссылки".
В итоге вопрос: почему нельзя использовать статик ссылки?

Аватара пользователя
KamiSempai
Сообщения: 1339
Зарегистрирован: 17 фев 2012, 21:23
Откуда: Мордор

Re: static HashMap<> - являются ли добавленные данные статич

Сообщение KamiSempai » 16 янв 2015, 12:42

Используя эту логику я могу написать приложение которое развернется и продолжит свою работу как ни в чем не бывало даже если его убить этой командой. А система это может сделать. Ей наплевать, что у тебя там статика или динамика.
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

Ответить