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

от автора

Привет, Хабр!

Меня зовут Алексей. Я разрабатываю под 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

ссылка на оригинал статьи http://habrahabr.ru/post/220835/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *