web-dev-qa-db-fra.com

Se connecter automatiquement Android événements de cycle de vie à l'aide d'ActivityLifecycleCallbacks?

J'essaie de capturer et de consigner automatiquement Android événements de cycle de vie en utilisant ActivityLifecycleCallbacks, cependant la documentation sur ce sujet est rare, pour dire le moins:

    public void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)

Je ne veux pas avoir à étendre la classe Activity ou remplacer les méthodes de cycle de vie existantes (onCreate, onResume, etc ...) Je cherche à avoir une classe séparée à l'écoute de ces événements et à agir en conséquence.

Quelqu'un a-t-il une expérience dans ce domaine ou a-t-il des liens vers une bonne documentation solide ou des tutoriels sur la façon dont cela fonctionne? Plus précisément, comment s'inscrire à ActivityLifecycleCallbacks et comment les gérer?

29
AWT

J'ai fait ma propre implémentation de Application.ActivityLifecycleCallbacks . J'utilise SherlockActivity, mais pour une classe d'activité normale, cela pourrait fonctionner.

Tout d'abord, je crée une interface qui a toutes les méthodes pour suivre le cycle de vie des activités:

public interface ActivityLifecycleCallbacks{
    public void onActivityStopped(Activity activity);
    public void onActivityStarted(Activity activity);
    public void onActivitySaveInstanceState(Activity activity, Bundle outState);
    public void onActivityResumed(Activity activity);
    public void onActivityPaused(Activity activity);
    public void onActivityDestroyed(Activity activity);
    public void onActivityCreated(Activity activity, Bundle savedInstanceState);
}

Deuxièmement, j'ai implémenté cette interface dans la classe de mon application:

public class MyApplication extends Application implements my.package.ActivityLifecycleCallbacks{

    @Override
    public void onCreate() {
        super.onCreate();           
    }

    @Override
    public void onActivityStopped(Activity activity) {
        Log.i("Tracking Activity Stopped", activity.getLocalClassName());

    }

    @Override
    public void onActivityStarted(Activity activity) {
        Log.i("Tracking Activity Started", activity.getLocalClassName());

    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
    }

    @Override
    public void onActivityResumed(Activity activity) {
        Log.i("Tracking Activity Resumed", activity.getLocalClassName());
    }

    @Override
    public void onActivityPaused(Activity activity) {
        Log.i("Tracking Activity Paused", activity.getLocalClassName());
    }

    @Override
    public void onActivityDestroyed(Activity activity) {
        Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
    }

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        Log.i("Tracking Activity Created", activity.getLocalClassName());
    }
}

Troisièmement, je crée une classe qui s'étend de SherlockActivity:

public class MySherlockActivity extends SherlockActivity {

    protected MyApplication nMyApplication;

    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        nMyApplication = (MyApplication) getApplication();
        nMyApplication.onActivityCreated(this, savedInstanceState);
    }

    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
        nMyApplication.onActivityResumed(this);
    }

    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        nMyApplication.onActivityPaused(this);
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        nMyApplication.onActivityDestroyed(this);
    }

    @Override
    protected void onStart() {
        super.onStart();
        nMyApplication.onActivityStarted(this);
    }

    @Override
    protected void onStop() {
        super.onStop();
        nMyApplication.onActivityStopped(this);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        nMyApplication.onActivitySaveInstanceState(this, outState);
    }   
}

Quatrièmement, toutes les classes qui s'étendent de SherlockActivity, j'ai remplacé MySherlockActivity:

public class MainActivity extends MySherlockActivity{

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

}

Maintenant, dans le logcat, vous verrez les journaux programmés dans l'implémentation de l'interface faite dans MyApplication.

[~ # ~] mise à jour [~ # ~]

Cette implémentation a été testée à partir de l'API Niveau 9 (Gingerbread), de l'API Level 12 (Honeycomb) et de l'API Level 17 (Jelly Bean) et fonctionne très bien. Pourrait fonctionner dans les anciennes versions d'Android.

33
ClarkXP

Je n'ai aucune expérience de première main, mais à en juger par l'API, vous pouvez simplement écrire votre propre classe qui implémente le Application.ActivityLifecycleCallbacks interface et enregistrez cette classe sur l'instance de classe Application fournie

getApplicaton().registerActivityLifecycleCallbacks(yourCustomClass);

Cette classe recevra les mêmes rappels que vos activités individuelles. Bonne chance.

PS. Il s'agit du niveau 14 API btw, donc cela ne fonctionnera pas sur les téléphones plus anciens.

46
Jeroen

Essayez ceci: http://engineering.meetme.com/2015/04/Android-determine-when-app-is-opened-or-closed/#comment-202

Il propose un AppForegroundStateManager auquel chaque activité rend compte à travers ses fonctions onStop() et onStart() comme ceci:

@Override
protected void onStart() {
    super.onStart();
    AppForegroundStateManager.getInstance().onActivityVisible(this);
}

@Override
protected void onStop() {
    AppForegroundStateManager.getInstance().onActivityNotVisible(this);
    super.onStop();
}

Votre classe Application implémente un écouteur comme celui-ci:

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        AppForegroundStateManager.getInstance().addListener(this);
    }

    @Override
    public void onAppForegroundStateChange(AppForegroundStateManager.AppForegroundState newState) {
        if (AppForegroundStateManager.AppForegroundState.IN_FOREGROUND.equals(newState)) {
            // App just entered the foreground. Do something here!
            Log.i(TAG, "App Just Entered the Foreground with launch mechanism of: " + mLaunchMechanism);
        } else {
            // App just entered the background. Set our launch mode back to the default of direct.
            mLaunchMechanism = LaunchMechanism.DIRECT;
        }
    }
}

Il comprend également des conseils et astuces pour déterminer comment l'application a été ouverte - à partir d'une notification, d'une URL ouvrant votre application ou directement à partir du menu Applications. Cela se fait via un Enum dans la classe Application:

public enum LaunchMechanism {
    DIRECT,
    NOTIFICATION,
    URL,
    BACKGROUND
}

private LaunchMechanism mLaunchMechanism = LaunchMechanism.DIRECT;

public void setLaunchMechanism(LaunchMechanism launchMechanism) {
    mLaunchMechanism = launchMechanism;
}

Dans notre implémentation de cela, nous avons des drapeaux pour quand nous démarrons une activité qui lancera une activité tierce, comme si l'utilisateur fait un appel téléphonique depuis notre application ou si un navigateur est lancé. Dans la onStop() de l'activité de lancement, nous effectuons une vérification comme celle-ci pour signaler uniquement la non-visibilité de l'activité lorsque ces indicateurs sont faux:

if(!flag_userLaunchedThirdPartyActivity){
     AppForegroundStateManager.getInstance().onActivityNotVisible(this);
     }

Pour vérifier si l'application passe en arrière-plan - par exemple lorsque l'écran de l'appareil s'assombrit ou lorsque l'utilisateur reçoit un appel téléphonique - cela fonctionne comme ceci:

public static boolean isApplicationGoingToBackground(final Context context) {

    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningTaskInfo> tasks = am.getRunningTasks(1);
    if (!tasks.isEmpty()) {
        ComponentName topActivity = tasks.get(0).topActivity;
        if (!topActivity.getPackageName().equals(context.getPackageName())) {
            setLaunchMechanism(LaunchMechanism.BACKGROUND);
            return true;
        }
    }

    setLaunchMechanism(LaunchMechanism.DIRECT);
    return false;
}

Cette solution ne dépend pas d'un niveau d'API, elle devrait donc remonter jusqu'au niveau d'API 1.

3
marienke
@Override
public void onCreate() {
    super.onCreate();
    registerActivityLifecycleCallbacks(MyApplication.this/*(Your Application Name)*/);

// registerActivityLifecycleCallbacks (MyApplication.this/(Votre nom d'application)/// n'ajoutez cette ligne qu'à la classe Application tout fonctionne bien

}

2
Anand Raj Mehta