Lazy Adapter

SQLite, Preferences, файлы, SD, Content Provider, XML, JSON
Ответить
Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Lazy Adapter

Сообщение rezak90 » 12 апр 2013, 21:42

Вопросы к гуру.
Все знают что адаптеры на курсорах быстрее работают чем обычные, отсюдова первый вопрос: Возможно ли построить cursor lazy adapter? (я просто таких не встречал)
Второй вопрос по легче: viеw которые не видны в данный момент на экране то их не существует в памяти? (я думаю да исходя из базовых адаптеров, просто задал для подтверждения)
Если построить lazy на обычном адаптере то он будет быстрее курсора? (скользкий вопрос)

Вторая часть вопросов.
Здесь даже не вопросы а как бы наталкните хотя бы на мысль, как правильно организовать загрузку в ячейках адаптера. Мне нужно два асинхронных потока для каждой ячейке (загрузка картинок и данных). Возникает куча вопросов таких как: когда таски отработают а этих вьюх уже нету в поле видимости то как они себя поведут; как таски будут знать в какую ячейку писать? Если кто поможет ссылкой то будет здорово, так как нормального примера пока не нашёл.
R.id.team
Политика на форуме запрещена

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

Re: Lazy Adapter

Сообщение KamiSempai » 12 апр 2013, 22:48

Если нужно работать с большими объемами данных, могу посоветовать вот это решение: http://habrahabr.ru/post/154817/
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

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

Re: Lazy Adapter

Сообщение KamiSempai » 12 апр 2013, 23:00

По поводу второй части. Тут либо View будет переиспользована либо либо скрыта. Думаю, если ссылка на View будет храниться в таске, по поводу обращения к null бояться не стоит.
Касательно реализации, я бы в таск дополнительно записывал ID строки и при попытке прописать данные в View сверял его с ID в холдере. Если ID разные, значит View уже переиспользована.
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Lazy Adapter

Сообщение rezak90 » 12 апр 2013, 23:03

наверное стоило упомянуть то что использую orm
R.id.team
Политика на форуме запрещена

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Lazy Adapter

Сообщение rezak90 » 12 апр 2013, 23:07

Да на счёт записи id думал, должно сработать, но если в теории данные в курсоре могут же поменяться во время выполнения? соответственно и записи в листе тоже.
И ещё такой тогда вопрос: если view уходит за пределы экрана она уже становится null то таск прекратится или будет всё таки дальше себе выполнятся? если выполнятся то не есть гуд, как тогда сделать что бы он прерывался если view становится нуловой?
R.id.team
Политика на форуме запрещена

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

Re: Lazy Adapter

Сообщение KamiSempai » 12 апр 2013, 23:23

rezak90 писал(а):наверное стоило упомянуть то что использую orm
Тогда предложенный мной вариант должен быть как раз кстати.
По поводу пропадания View из поля зрения. Можно использовать setRecyclerListener. Я им ни разу не пользовался и не могу точно сказать когда он срабатывает, только когда View отправляется в мусор или еще когда View переиспользуется. Если что, переиспользование можно самому обработать в getView.
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Lazy Adapter

Сообщение rezak90 » 12 апр 2013, 23:31

Жаль что нету у View метода onDestroy или ему подобного.
А за setRecyclerListener спасибо, завтра попробую.
R.id.team
Политика на форуме запрещена

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

Re: Lazy Adapter

Сообщение KamiSempai » 12 апр 2013, 23:41

rezak90 писал(а):Жаль что нету у View метода onDestroy или ему подобного.
Если бы даже и был, все равно не отработал. Фактически View ни куда не девается, а просто убирается из списка и переносится специальное хранилище(мусорная куча). И, как я уже писал выше, можно не бояться обратиться к null, объект существует пока на него есть хотя-бы одна ссылка, а ссылка есть, и она у хранилища, в которое View помещается.

PS: Сейчас заглянул в исходники, похоже, что View всякий раз отправляется в мусор перед переиспользованием, так-что на счет переиспользования можно не беспокоиться.
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Lazy Adapter

Сообщение rezak90 » 13 апр 2013, 00:15

так а view в мусорной куче как то освобождает ресурсы или всё таки кушает память?
R.id.team
Политика на форуме запрещена

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

Re: Lazy Adapter

Сообщение KamiSempai » 13 апр 2013, 00:57

В куче есть методы которые следят за количеством View, на случай если адаптер не переиспользует переданные ему View или их количество неожиданно превысило необходимое. А так, да, они сидят там, кушают память и ждут своего часа)
Хотя, если брать в учет принципы работы Java, даже после удаления они будут потреблять ресурсы пока их сборщик мусора не соберет :)
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

Аватара пользователя
Finch
Сообщения: 439
Зарегистрирован: 16 июл 2012, 21:37

Re: Lazy Adapter

Сообщение Finch » 13 апр 2013, 09:13

Лучше этого примера чем от гугл я не встречал, тут вся фишка в паузе при прокрутке, какими бы не были битмапы, каким бы слабым не был смартфон, лист вью не тормозит вообще, там хорошо организовано кэширование и уборка мусора.
используется LruCache.
Api >= 7
http://developer.android.com/intl/ru/tr ... index.html
http://developer.android.com/intl/ru/tr ... itmap.html
CEO of a company R.id.team

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Lazy Adapter

Сообщение rezak90 » 13 апр 2013, 09:16

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

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Lazy Adapter

Сообщение rezak90 » 13 апр 2013, 12:03

Кстати ещё такой вопрос: есть смысл в CursorAdapter'e использовать ViewHolder? cпотому что я не видел реализации такой связки.
R.id.team
Политика на форуме запрещена

Аватара пользователя
rezak90
Сообщения: 3422
Зарегистрирован: 26 июн 2012, 13:22
Откуда: UA
Контактная информация:

Re: Lazy Adapter

Сообщение rezak90 » 14 апр 2013, 00:59

Вот что только что за часик успел накидать:
View элемент листа

Код: Выделить всё

public class ItemView extends LinearLayout
{

	public ItemView(Context context)
	{
		super(context);
		initControls(context);
	}

	public ItemView(Context context, AttributeSet attrs)
	{
		super(context, attrs);
		initControls(context);
	}

	private void initControls(Context context)
	{
		View rootView = ((LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.item_layout, this);
		ViewHolder holder = new ViewHolder();
		holder.tvItem = (TextView) rootView.findViewById(R.id.tvItem);
		holder.ivItem = (ImageView) rootView.findViewById(R.id.ivItem);
		holder.pbItem = (ProgressBar) rootView.findViewById(R.id.pbItem);
		this.setTag(holder);
	}

	public class ViewHolder
	{
		public TextView tvItem;
		public ImageView ivItem;
		public ProgressBar pbItem;
		public int position;
	}

}
Собственно сам адаптер

Код: Выделить всё

public class HomeAdapter extends SimpleCursorAdapter
{

	private int position = 0;

	public HomeAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags)
	{
		super(context, layout, c, from, to, flags);
	}

	@Override
	public void bindView(View view, Context context, Cursor cursor)
	{
		ViewHolder holder = (ViewHolder) ((ItemView) view).getTag();
		holder.tvItem.setText(cursor.getString(cursor.getColumnIndex(DBHelper.COLUMN_TITLE)));
		holder.position = position;
		position++;
		new AscLoadImage(holder).execute();
	}

	@Override
	public View newView(Context context, Cursor cursor, ViewGroup parent)
	{
		ItemView view = new ItemView(context);
		return view;
	}

	private class AscLoadImage extends AsyncTask<Void, Void, Bitmap>
	{

		private ViewHolder holder;
		private static final String URL_DOWNLOAD = "http://s41.radikal.ru/i093/1304/3f/fdd5de69f9ad.jpg";

		public AscLoadImage(ViewHolder _holder)
		{
			holder = _holder;
			holder.pbItem.setVisibility(View.VISIBLE);
		}

		@Override
		protected void onPreExecute()
		{
			super.onPreExecute();
		}

		@Override
		protected Bitmap doInBackground(Void... params)
		{
			Bitmap bmImg = null;
			URL url = null;
			HttpURLConnection conn = null;
			InputStream is = null;
			try
			{
				url = new URL(URL_DOWNLOAD);
				conn = (HttpURLConnection) url.openConnection();
				conn.setDoInput(true);
				conn.connect();
				is = conn.getInputStream();
				// bmImg = BitmapFactory.decodeStream(is);
				BitmapFactory.Options o = new BitmapFactory.Options();
				o.inJustDecodeBounds = true;
				int scale = 1;
				scale = (int) Math.pow(2, (int) Math.round(Math.log(130 / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5)));
				BitmapFactory.Options options = new BitmapFactory.Options();
				options.inSampleSize = scale;
				bmImg = BitmapFactory.decodeStream(is, null, options);
			}
			catch (IOException e)
			{
				Log.e("MyTag", e.getMessage());
			}
			finally
			{
				if (is != null)
				{
					try
					{
						is.close();
					}
					catch (IOException e)
					{
						Log.e("MyTag", e.getMessage());
					}
				}
				if (conn != null)
				{
					conn.disconnect();
				}
			}
			return bmImg;
		}

		@Override
		protected void onPostExecute(Bitmap result)
		{
			if (holder != null && holder.ivItem != null && holder.pbItem != null)
			{
				holder.ivItem.setImageBitmap(result);
				holder.pbItem.setVisibility(View.GONE);
				Log.i("MyTag", "image load: " + holder.position);
			}
			result = null;
			super.onPostExecute(result);
		}

	}

}
Всё вроде бы нормально грузится и не тормозит, но смущает два момента:
1) Не может быть всё так просто, видимо я что то не то написал =)
2) Картинка остаётся после первой загрузки на всех ячейках, даже на тех которых загрузка картинки ещё не произошла (может с ссылкой где то провтыкал).
R.id.team
Политика на форуме запрещена

Ответить