52 votes

Optimisation de la vitesse de lancement des tiroirs et des activités

J'utilise l'application Google DrawerLayout .

Lorsqu'un élément est cliqué, le tiroir est fermé en douceur et un message d'avertissement est affiché. Activity sera lancé. Transformer ces activités en Fragment s est no une option. De ce fait, lancer une activité puis fermer le tiroir n'est pas non plus une option. Fermer le tiroir et lancer l'activité en même temps fera bégayer l'animation de fermeture.

Étant donné que je veux d'abord le fermer en douceur, puis lancer l'activité, j'ai un problème de latence entre le moment où un utilisateur clique sur l'élément du tiroir et celui où il voit l'activité à laquelle il voulait accéder.

Voici à quoi ressemble l'écouteur de clics pour chaque élément.

final View.OnClickListener mainItemClickListener = new View.OnClickListener() {
    @Override
    public void onClick(final View v) {
        mViewToLaunch = v;
        mDrawerLayout.closeDrawers();
    }
};

Mon activité est également le DrawerListener, son onDrawerClosed ressemble à une méthode :

@Override
public synchronized void onDrawerClosed(final View view) {
    if (mViewToLaunch != null) {
        onDrawerItemSelection(mViewToLaunch);
        mViewToLaunch = null;
    }
}

onDrawerItemSelection lance simplement l'une des cinq activités.

Je ne fais rien sur onPause de la DrawerActivity .

Je l'instrumente et il faut en moyenne 500-650 ms entre le moment où onClick est appelé et celui où onDrawerClosed se termine.

Il y a un décalage notable, une fois que le tiroir se ferme, avant que l'activité correspondante ne soit lancée.

Je réalise que plusieurs choses se passent :

  • L'animation de fermeture a lieu, ce qui représente quelques millisecondes (disons 300).

  • Ensuite, il y a probablement une certaine latence entre la fermeture visuelle du tiroir et le déclenchement de son écouteur. J'essaie de comprendre exactement ce qui se passe. en regardant DrawerLayout source mais je n'ai pas encore trouvé la solution.

  • Ensuite, il y a le temps nécessaire à l'activité lancée pour exécuter ses méthodes du cycle de vie de démarrage jusqu'à, et y compris, onResume . Je ne l'ai pas encore instrumenté mais je l'estime à environ 200-300ms.

Il s'agit d'un problème pour lequel il serait très coûteux de faire fausse route. Je veux donc être sûr de bien le comprendre.

Une solution consiste à sauter l'animation de fermeture, mais j'espérais pouvoir la conserver.

Comment puis-je réduire autant que possible le temps de transition ?

27voto

iDroid Explorer Points 7726

J'ai rencontré le même problème avec DrawerLayout.

J'ai fait des recherches à ce sujet et j'ai trouvé une bonne solution.

Ce que je fais, c'est .....

Si vous vous référez à l'exemple d'application Android pour le DrawerLayout, vérifiez le code pour selectItem(position) ;

Dans cette fonction, basée sur la sélection de la position, le fragment est appelé. Je l'ai modifié avec le code ci-dessous en fonction de mes besoins et cela fonctionne bien sans animation proche du bégaiement.

private void selectItem(final int position) {
    //Toast.makeText(getApplicationContext(), "Clicked", Toast.LENGTH_SHORT).show();
    mDrawerLayout.closeDrawer(drawerMain);
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            Fragment fragment = new TimelineFragment(UserTimeLineActivity.this);
            Bundle args = new Bundle();
            args.putInt(TimelineFragment.ARG_PLANET_NUMBER, position);
            fragment.setArguments(args);

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

            // update selected item and title, then close the drawer
            mCategoryDrawerList.setItemChecked(position, true);

            setTitle("TimeLine: " + mCategolyTitles[position]);
        }
    }, 200);

    // update the main content by replacing fragments

}

Ici, je ferme d'abord le DrawerLayout, ce qui prend environ 250 milisecondes, puis mon handler appelle le fragment. Ce qui fonctionne bien et conformément à l'exigence.

J'espère qu'il vous sera également utile.

Bon codage... :)

19voto

yarian Points 1396

Il semble donc que j'ai résolu le problème avec une solution raisonnable.

La source la plus importante de latence perceptible était le délai entre le moment où le tiroir était visuellement fermé et le moment où le tiroir était fermé. onDrawerClosed a été appelé. J'ai résolu ce problème en postant un Runnable à un privé Handler qui lance l'activité prévue à un moment donné. Ce délai est choisi pour correspondre à la fermeture du tiroir.

J'ai essayé de faire le lancement onDrawerSlide après une progression de 80 %, mais cela pose deux problèmes. Le premier est qu'il bégaie. Le second est que si vous augmentez le pourcentage à 90% ou 95%, la probabilité qu'il ne soit pas appelé du tout à cause de la nature de l'animation augmente - et vous devez alors revenir à onDrawerClosed ce qui va à l'encontre du but recherché.

Cette solution a la possibilité de bégayer, en particulier sur les téléphones plus anciens, mais la probabilité peut être réduite à 0 simplement en augmentant le délai suffisamment haut. Je pensais que 250 ms était un équilibre raisonnable entre bégaiement et latence.

Les parties pertinentes du code ressemblent à ceci :

public class DrawerActivity extends SherlockFragmentActivity {
    private final Handler mDrawerHandler = new Handler();

    private void scheduleLaunchAndCloseDrawer(final View v) {
        // Clears any previously posted runnables, for double clicks
        mDrawerHandler.removeCallbacksAndMessages(null); 

        mDrawerHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                onDrawerItemSelection(v);
            }
        }, 250);
        // The millisecond delay is arbitrary and was arrived at through trial and error

        mDrawerLayout.closeDrawer();
    }
}

2voto

oracleicom Points 230

Une meilleure approche serait d'utiliser la méthode onDrawerSlide(View, float) et de lancer l'activité une fois que le slideOffset est égal à 0. Voir ci-dessous

public void onDrawerSlide(View drawerView, float slideOffset) {
    if (slideOffset <= 0 && mPendingDrawerIntent != null) {
        startActivity(mPendingDrawerIntent);
        mPendingDrawerIntent = null;
    }
}

Il suffit de définir le mPendingDrawerIntent dans la méthode ListView.OnItemClickListener onItemClick du tiroir.

-1voto

user3761431 Points 9

Modifiez votre balise AndroidManifest.xml uses-sdk comme ceci !!!

    android:minSdkVersion="8"
    android:targetSdkVersion="19" />

J'espère que cela vous aidera !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X