Страница 1 из 1

Lazy Adapter

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

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

Re: Lazy Adapter

Добавлено: 12 апр 2013, 22:48
KamiSempai
Если нужно работать с большими объемами данных, могу посоветовать вот это решение: http://habrahabr.ru/post/154817/

Re: Lazy Adapter

Добавлено: 12 апр 2013, 23:00
KamiSempai
По поводу второй части. Тут либо View будет переиспользована либо либо скрыта. Думаю, если ссылка на View будет храниться в таске, по поводу обращения к null бояться не стоит.
Касательно реализации, я бы в таск дополнительно записывал ID строки и при попытке прописать данные в View сверял его с ID в холдере. Если ID разные, значит View уже переиспользована.

Re: Lazy Adapter

Добавлено: 12 апр 2013, 23:03
rezak90
наверное стоило упомянуть то что использую orm

Re: Lazy Adapter

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

Re: Lazy Adapter

Добавлено: 12 апр 2013, 23:23
KamiSempai
rezak90 писал(а):наверное стоило упомянуть то что использую orm
Тогда предложенный мной вариант должен быть как раз кстати.
По поводу пропадания View из поля зрения. Можно использовать setRecyclerListener. Я им ни разу не пользовался и не могу точно сказать когда он срабатывает, только когда View отправляется в мусор или еще когда View переиспользуется. Если что, переиспользование можно самому обработать в getView.

Re: Lazy Adapter

Добавлено: 12 апр 2013, 23:31
rezak90
Жаль что нету у View метода onDestroy или ему подобного.
А за setRecyclerListener спасибо, завтра попробую.

Re: Lazy Adapter

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

PS: Сейчас заглянул в исходники, похоже, что View всякий раз отправляется в мусор перед переиспользованием, так-что на счет переиспользования можно не беспокоиться.

Re: Lazy Adapter

Добавлено: 13 апр 2013, 00:15
rezak90
так а view в мусорной куче как то освобождает ресурсы или всё таки кушает память?

Re: Lazy Adapter

Добавлено: 13 апр 2013, 00:57
KamiSempai
В куче есть методы которые следят за количеством View, на случай если адаптер не переиспользует переданные ему View или их количество неожиданно превысило необходимое. А так, да, они сидят там, кушают память и ждут своего часа)
Хотя, если брать в учет принципы работы Java, даже после удаления они будут потреблять ресурсы пока их сборщик мусора не соберет :)

Re: Lazy Adapter

Добавлено: 13 апр 2013, 09:13
Finch
Лучше этого примера чем от гугл я не встречал, тут вся фишка в паузе при прокрутке, какими бы не были битмапы, каким бы слабым не был смартфон, лист вью не тормозит вообще, там хорошо организовано кэширование и уборка мусора.
используется LruCache.
Api >= 7
http://developer.android.com/intl/ru/tr ... index.html
http://developer.android.com/intl/ru/tr ... itmap.html

Re: Lazy Adapter

Добавлено: 13 апр 2013, 09:16
rezak90
ага я помню ты бросал на форум уже, я просто забыл о нём, но в моём случае пауза не прокатит так как основные данные грузятся сразу с локальной бд, а картинки уже с сервера на ходу должны без заминок

Re: Lazy Adapter

Добавлено: 13 апр 2013, 12:03
rezak90
Кстати ещё такой вопрос: есть смысл в CursorAdapter'e использовать ViewHolder? cпотому что я не видел реализации такой связки.

Re: Lazy Adapter

Добавлено: 14 апр 2013, 00:59
rezak90
Вот что только что за часик успел накидать:
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) Картинка остаётся после первой загрузки на всех ячейках, даже на тех которых загрузка картинки ещё не произошла (может с ссылкой где то провтыкал).