web-dev-qa-db-fra.com

Une vue personnalisée peut-elle savoir que onPause a été appelée?

J'ai une vue personnalisée qui exécute une opération de thread qui se trouve autour des appels périodiques aux interwebs. Je voudrais savoir s'il y a un moyen pour moi de ne pas avoir à tuer ce thread de l'activité parent (onPause) afin que le thread ne se déplace pas en arrière-plan une fois que l'activité a été mise en arrière-plan (et/ou tuée).

L'intention ici est que la vue personnalisée soit autosuffisante et ne nécessite pas de traitement supplémentaire de l'activité. Pour ce faire, il devrait écouter lorsque son parent a été mis en arrière-plan et laisser ensuite la boucle de sommeil infinie dans le thread expirer. Je ne vois pas de moyen de le faire, mais j'espère que j'oublie quelque chose.

38
Yevgeny Simkin

Sauf si vous le notifiez directement.

Pour cela, remplacez View.onDetachedFromWindow() et abandonnez votre Thread là-bas. Ensuite, lorsque la vue est à nouveau visible, faites tourner le fil dans View.onAttachedToWindow(). Le problème avec onPause () et onResume () est que vous pouvez toujours avoir une vue visible à l'écran, mais attachée à une activité suspendue. Un exemple de cas où cela peut se produire est si vous avez une activité dans une fenêtre qui en superpose une autre.

Ou, comme le suggère William Gouvea, un fragment pourrait être mieux adapté à votre objectif car il possède déjà les crochets du cycle de vie pour la pause et la reprise, et tout ce qui parle au réseau tombe vraiment dans le royaume contrôleur en tous cas.

13
dcow

Oui, vous pouvez utiliser le code ci-dessous,

@Override
protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
    super.onVisibilityChanged(changedView, visibility);
    if (visibility == View.VISIBLE) //onResume called
    else // onPause() called
}

@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
    super.onWindowFocusChanged(hasWindowFocus);
    if (hasWindowFocus) //onresume() called
    else // onPause() called
}

@Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        // onDestroy() called
}

@Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        // onCreate() called
}
51
Yogesh Rathi

Oui, vous pouvez. Tout ce dont vous avez besoin est d'avoir un champ de type LifecycleOwner. Plus d'informations à ce sujet dans documentation officielle . Dans mon cas, j'ai créé une vue personnalisée avec une autre vue de la bibliothèque tierce - CameraView.

Au début, la vue personnalisée doit implémenter l'interface LifecycleOberver

public class MakePhotoView extends ConstraintLayout implements LifecycleObserver

Donc, j'ai un champ dans ma vue personnalisée:

private LifecycleOwner mLifecycleOwner;

Je le passe dans le constructeur comme l'un des paramètres:

public MakePhotoView(Context context, OnPhotoMadeListener onPhotoMadeListener, LifecycleOwner lifecycleOwner) {
    super(context);
    mOnPhotoMadeListener = onPhotoMadeListener;
    mLifecycleOwner = lifecycleOwner;
    init();
}

Après cela, j'enregistre ma vue personnalisée en tant qu'observateur des événements du cycle de vie dans LifecycleOwner:

private void init() {
    //other code
    mLifecycleOwner.getLifecycle().addObserver(this);
}

Et enfin, je peux écouter les événements du cycle de vie:

@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void startCamera() {
    AppLog.logObject(this, "On Resume called for MakeCameraView");
    mCameraView.start();
}

@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void stopCamera() {
    AppLog.logObject(this, "On Pause called for MakeCameraView");
    mCameraView.stop();
}

@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void destroyCamera() {
    AppLog.logObject(this, "On Destroy called for MakeCameraView");
    mCameraView.destroy();
}
5
Alexander Bernat

Soit vous devez faire savoir à votre vue que l'activité propriétaire n'est plus au premier plan, soit interroger le système avec une méthode pour demander quelle tâche est actuellement au premier plan, ce qui semble très inefficace.

Voici deux liens qui ont résolu ce problème:

(Ce n'est peut-être pas vraiment une réponse, mais c'était trop grand pour un commentaire)

2
Merlevede

Si vous remplacez simplement la classe View et créez votre propre CustomView, vous pouvez créer une interface pour agir comme un écouteur, qui devrait être implémentée par votre activité parent, donc quand quelque chose se produit, vous déclenchez l'événement et établissez la communication entre ces composants d'avant en arrière .

En fonction de ce que vous souhaitez réaliser, les fragments peuvent être utiles car ce composant a votre propre cycle de vie similaire à l'activité (onPause/onResume par exemple), détient votre propre état, a ou non une vue et peut conserver leur état entre les chamges de configuration.

Voir plus dans: http://developer.Android.com/reference/Android/app/Fragment.htmlhttp://developer.Android.com/guide/components/fragments. html

2
william gouvea