Pull to refresh

Как я с лагом Navigation Drawer боролся

Development of mobile applications *Development for Android *
Sandbox
Привет, Хабр!

Меня зовут Алексей. Я разрабатываю под Android. Отладка в эмуляторе подобна смерти, поэтому я пользуюсь своим HTC Desire HD. Зверёк уже очень древний, за что я не могу его не любить, потому что любые шероховатости и неровности в приложении на нём отдаются славными лагами. Кстати, очень рекомендую запускать свои проекты на аппаратах средней мощности, ведь не у всех пользователей флагманы. Так вот, работая над своим новым приложением, я обнаружил, что при переключении между фрагментами через Navigation Drawer шторка навигации заметно пролагивает. При создании фрагмента делались запросы к базе и подгружались SharedPreferences. Мне было просто противно наблюдать этот лаг, и я придумал как избавиться от него. Всех, кому интересно, прошу под кат.

Я создал простенький проект с NavigationDrawer и тремя фрагментами (ссылка на Github в конце статьи). Код не претендует на звание идеального, я старался написать максимально просто и понятно. Код шторки взят прямо из примеров Google. Решил проблему я очень просто и в лоб: загрузка фрагмента запускается в отдельном потоке и задерживается на 0,3 секунды (магическое число, подобранное экспериментально).

Сначала вешаем слушателя на элементы списка так:

mDrawerList.setOnItemClickListener(new DrawerItemClickListener());


И метод selectItem был таким:

private void selectItem(int position) {
	Fragment fragment = new ContentFragment();
	Bundle args = new Bundle();
	args.putInt("positions", position);
	fragment.setArguments(args);

	FragmentManager fragmentManager = getFragmentManager();
	fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();

	mDrawerList.setItemChecked(position, true);
	setTitle(leftDrawerTitles[position]);
	mDrawerLayout.closeDrawer(mDrawerList);
}


А чтобы убрать лаг, изменим эти два места:

1) Из selectItem перенесём в onCreate весь код по выделению активного элемента и закрытию Drawer. selectItem станет таким:

private void selectItem(int position) {
	Fragment fragment = new ContentFragment();
	Bundle args = new Bundle();
	args.putInt("positions", position);
	fragment.setArguments(args);

	FragmentManager fragmentManager = getFragmentManager();
	fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();
}


2) А в onCreate вешаем слушателя на элементы Drawer и запускаем поток:

mDrawerList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
	public void onItemClick(AdapterView<?> adapterView, View view, final int position, long l) {
		mDrawerList.setItemChecked(position, true);
		setTitle(leftDrawerTitles[position]);
		mDrawerLayout.closeDrawer(mDrawerList);

		// Смена фрагмента запускается в отдельном потоке и задерживается на 0.3 секунды,
		// чтобы избежать пролагивания при переключении
		new Thread(new Runnable() {
			public void run() {
				try {
					TimeUnit.MILLISECONDS.sleep(300);
					selectItem(position);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}).start();
	}
});


Вот и всё. Может быть это и нелепый костыль, но я всё равно был безумно рад, открыв его для себя.

P.S. Хотелось бы добавить про отладку на телефоне. Очень рекомендую пользоваться ADB Over Wi-Fi (требуются root права). Wi-Fi не ограничивает вас в передвижениях и в поворотах аппарата.
P.P.S. Очень хочу получить консруктивную критику и советы знающих людей.

Ссылка на репозиторий: https://github.com/Rozag/Lags-free-navigation-drawer
Tags:
Hubs:
Total votes 10: ↑7 and ↓3 +4
Views 11K
Comments Comments 14