- PVSM.RU - https://www.pvsm.ru -

Как я боролся с лагом NavigationDrawer с помощью AsyncTask

Привет!

Меня зовут Никита. Я занимаюсь разработкой под Android. Хотел бы написать продолжение публикации «Как я с лагом Navigation Drawer боролся» [1], где автор рассказывал, что обойти лаг Navigation Drawer при загрузке фрагмента можно через поток, который будет спать 300мс, и, соответственно, за это время должен успеть загрузиться фрагмент, а после закрыться NavigationDrawer.

Но, как я посчитал, это не наилучший метод решения проблемы, ибо для каждого устройства может понадобиться разное время, так как время работы потока зависит напрямую от характеристик устройства: чем оно слабее — тем больше времени требуется и наоборот.

Я тестировал свое приложение на двух устройствах

Samsung Galaxy Tab 2 7.0 (2 ядра — 1ГГц)
Huawei Honor 3x (8 ядер — 1.7 ГГц)

Конечно же, устройства неслабые (для тестового приложения), но одноядерного бюджетного смартфона у меня не имеется, а чтобы проверить работоспособность своего метода, добавил в фрагменты различные элементы (ImageView с картинкой в разрешении HD, TextView, TabHost и другие), потому что если фрагмент будет пустой, то AsyncTask даже не понадобится, ибо ничего загружаться не будет.

Ну, давайте приступим:

Создадим разметку главного экрана main.xml

Код

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent"
     tools:context=".MainActivity">

    <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

        <!-- The main content view -->

        <FrameLayout
            android:id="@+id/container"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
        <!-- The navigation drawer -->

        <ListView
            android:id="@+id/left_drawer"
            android:layout_width="240dp"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:background="#ff396c99"
            android:divider="@android:color/transparent"
            android:dividerHeight="0dp" />

    </android.support.v4.widget.DrawerLayout>
</RelativeLayout>

Теперь разметку фрагмента start_fragment.xml:

Код

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

        <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/photo"/>

</LinearLayout>

Теперь перейдем к MainActivity:

Код главной активности

public class MainActivity extends Activity {

    private ListView mListView;
    private DrawerLayout mDrawerLayout;
    private FrameLayout mContainer;
    private ActionBarDrawerToggle mDrawerToggle;
    CharSequence mTitle;
    MyAsyncTask mytask;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mListView = (ExpandableListView) findViewById(R.id.left_drawer);
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mContainer = (FrameLayout) findViewById(R.id.container);
        mTitle = getActionBar().getTitle();
        mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); // установка тени к NavDrawer

        final String[] names = new String[] {
                "Фрагмент 1",
                "Фрагмент 2",
                "Фрагмент 3"
        };

        // используем адаптер данных
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,	android.R.layout.simple_list_item_1, names);

        mListView.setAdapter(adapter);

        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View itemClicked, int position,
                                    long id) {
                switch (position){
                    case 0:
                        mytask = new MyAsyncTask();
                        mytask.execute(new StartFragment()); //выбираете фрагмент, который хотите загрузить
                        break;
                    case 1:
                        mytask = new MyAsyncTask();
                        mytask.execute(new StartFragment2());
                        break;
                    default:;
                }
            }
        });

        mDrawerToggle = new ActionBarDrawerToggle(
                this,
                mDrawerLayout,
                R.drawable.ic_drawer,
                R.string.drawer_open,
                R.string.drawer_close
        ) {
            public void onDrawerClosed(View view) {
                getActionBar().setTitle(mTitle);
                invalidateOptionsMenu();
            }

            public void onDrawerOpened(View drawerView) {
                invalidateOptionsMenu();
            }
        };
        // Set the drawer toggle as the DrawerListener
        mDrawerLayout.setDrawerListener(mDrawerToggle);

        getActionBar().setDisplayHomeAsUpEnabled(true);
        getActionBar().setHomeButtonEnabled(true);

        if (savedInstanceState == null){
            /*Здесь загрузим стартовый фрагмент, если нужно*/
        }
    }


    /*
    *** Меню
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (mDrawerToggle.onOptionsItemSelected(item)) {
            return true;
        }
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        boolean drawerOpen = mDrawerLayout.isDrawerOpen(mListView);
        return super.onPrepareOptionsMenu(menu);
    }
    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        mDrawerToggle.syncState();
    }
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        mDrawerToggle.onConfigurationChanged(newConfig);
    }

    /*
    * Собственно сам AsyncTask
    * */
    private class MyAsyncTask extends AsyncTask<Fragment, Integer, Fragment> {
        @Override
        protected Fragment doInBackground(Fragment... fragment) {
            FragmentManager fragmentManager = getFragmentManager();
            FragmentTransaction fragmentTransaction = fragmentManager
                    .beginTransaction();
            fragment[0].setRetainInstance(true);
            fragmentTransaction.replace(R.id.container, fragment[0]);
            fragmentTransaction.commit();
            return fragment[0];
        }

        @Override
        protected void onPostExecute(Fragment fragment) {
            super.onPostExecute(fragment);
            mDrawerLayout.closeDrawers();
        }
    }

}

Не буду приводить пример Java кода фрагмента, ибо вы его сможете настроить сами и добавить свои элементы.

Пока каких-либо багов не обнаружено, приложение не вылетает и NavigationDrawer закрывается плавно.

Однако хочу отметить, что возможны зависания на слабых устройствах, если фрагмент действительно громоздкий, но в таком случае я бы добавил ProgressBar, который показывал бы, что приложение не зависло.

Был использован материал: «AsyncTask — сайт Александра Климова» [2]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/pesochnitsa/81024

Ссылки в тексте:

[1] «Как я с лагом Navigation Drawer боролся»: http://habrahabr.ru/post/220835/

[2] «AsyncTask — сайт Александра Климова»: http://developer.alexanderklimov.ru/android/theory/asynctask.php