Exemple Android détaillé du code source de HandlerThread

php中世界最好的语言
Libérer: 2023-03-18 06:22:01
original
1606 Les gens l'ont consulté

L'article que je vous propose aujourd'hui est d'analyser l'utilisation et les étapes de HandlerThread dans Android à travers un exemple de code. Les amis qui en ont besoin peuvent s'y référer.

Introduction à HandlerThread :
Nous savons que le thread Thread est un produit de consommation unique. Lorsque le thread Thread termine une tâche fastidieuse, le thread est automatiquement détruit. Si j'ai une autre tâche fastidieuse à exécuter à ce moment-là, nous devons recréer le thread pour effectuer la tâche fastidieuse. Cependant, il existe un problème de performances : la création et la destruction de threads plusieurs fois consomment

ressources système. Afin de comprendre ce problème, nous pouvons créer nous-mêmes un thread de boucle Looper Thread Lorsqu'une tâche fastidieuse est placée dans le thread de boucle, le thread exécute la tâche qui prend

temps. le thread de boucle est dans un état d'attente jusqu'à ce que la prochaine nouvelle tâche fastidieuse soit lancée. Cela évite les

problèmes de performances causés par la création répétée de threads de discussion. Vous pouvez peut-être créer vous-même un fil de boucle, mais je peux vous annoncer une bonne nouvelle. Il existe en fait un cadre de fil de boucle dans le SDK Aandroid

. À ce stade, il vous suffit de maîtriser son utilisation et c’est tout ! Bien sûr, c'est notre protagoniste HandlerThread aujourd'hui ! Ensuite, laissez HandlerThread arriver, applaudissements ~~

La classe parent de HandlerThread est Thread, donc HandlerThread est en fait un thread, mais cela vous aide à implémenter une boucle Looper en interne. Alors

comprenons d'abord comment utiliser Handler !

Étapes d'utilisation de HandlerThread :


1. Créez un objet d'instance

HandlerThread handlerThread = new HandlerThread("handlerThread");
Copier après la connexion


Les paramètres ci-dessus peuvent être n'importe lesquels <. 🎜> Chaîne de caractères

, la fonction principale du paramètre est de marquer le nom du fil de discussion en cours.

2. Démarrez le fil HandlerThread

handlerThread.start();
Copier après la connexion

À ce stade, nous avons terminé la création d'un fil de boucle. Vous vous demandez peut-être comment placer une tâche asynchrone chronophage dans le thread HandlerThread pour exécution ? Bien sûr, il existe un moyen, regardons la troisième partie.

3. Créez un mécanisme de traitement des messages en boucle

Handler subHandler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
      @Override
      public boolean handleMessage(Message msg) {
        //实现自己的消息处理
        return true;
      }
    });
Copier après la connexion

La troisième étape consiste à créer un objet Handler et à utiliser l'objet looper dans le HandlerThread ci-dessus. comme paramètre Handler. , puis réécrivez la méthode

handlerMessage dans la classe d'interface Handler's Callback pour gérer les tâches fastidieuses.

Résumé : L'ordre des trois étapes ci-dessus ne peut pas être gâché et doit être strictement suivi. À ce stade, nous pouvons appeler subHandler pour envoyer des tâches fastidieuses au thread

HandlerThread sous la forme de

envoyer un message pour exécution. L'implication est que la méthode handlerMessage dans la classe d'interface Callback dans subHandler est en fait exécutée dans le thread de travail.

Instance HandlerThread :

package com.example.handlerthread;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
  private Handler mSubHandler;
  private TextView textView;
  private Button button;
 
  private Handler.Callback mSubCallback = new Handler.Callback() {
    //该接口的实现就是处理异步耗时任务的,因此该方法执行在子线程中
    @Override
    public boolean handleMessage(Message msg) {
 
      switch (msg.what) {
      case 0:
        Message msg1 = new Message();
        msg1.what = 0;
        msg1.obj = java.lang.System.currentTimeMillis();
        mUIHandler.sendMessage(msg1);
        break;
 
      default:
        break;
      }
 
      return false;
    }
  };
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
 
    textView = (TextView) findViewById(R.id.textView);
    button = (Button) findViewById(R.id.button);
 
    HandlerThread workHandle = new HandlerThread("workHandleThread");
    workHandle.start();
    mSubHandler = new Handler(workHandle.getLooper(), mSubCallback);
 
    button.setOnClickListener(new OnClickListener() {
 
      @Override
      public void onClick(View v) {
        //投放异步耗时任务到HandlerThread中
        mSubHandler.sendEmptyMessage(0);
      }
    });
 
  }
}
Copier après la connexion

Analyse du code source HandlerThread

HandlerThread
Méthode de construction

/**
 * Handy class for starting a new thread that has a looper. The looper can then be
 * used to create handler classes. Note that start() must still be called.
 */
public class HandlerThread extends Thread {
  //线程优先级
  int mPriority;
  //当前线程id
  int mTid = -1;
  //当前线程持有的Looper对象
  Looper mLooper;
   
  //构造方法
  public HandlerThread(String name) {
    //调用父类默认的方法创建线程
    super(name);
    mPriority = Process.THREAD_PRIORITY_DEFAULT;
  }
  //带优先级参数的构造方法
  public HandlerThread(String name, int priority) {
    super(name);
    mPriority = priority;
  }
...............
}
Copier après la connexion

Analyse : Une description est donnée au début de ce cours : Cette classe permet de créer un fil avec une boucle Looper, et l'objet Looper est utilisé pour créer un objet Handler. Il convient de noter que vous devez appeler la méthode start() pour démarrer le thread avant de créer l'objet Handler

. Peut-être que certaines personnes ici ont des questions ? Pourquoi devons-nous appeler la méthode start() avant de pouvoir créer un gestionnaire ? Nous y répondrons plus tard.

Les commentaires de code ci-dessus sont très clairs. La classe HandlerThread a deux constructeurs. La différence est de définir le paramètre de priorité du thread actuel. Vous pouvez définir la priorité

en fonction de votre propre situation, ou vous pouvez utiliser la priorité par défaut.

Méthode d'exécution de HandlerThrad

public class HandlerThread extends Thread {
 /**
   * Call back method that can be explicitly overridden if needed to execute some
   * setup before Looper loops.
   */
  protected void onLooperPrepared() {
  }
 
  @Override
  public void run() {
    //获得当前线程的id
    mTid = Process.myTid();
    //准备循环条件
    Looper.prepare();
    //持有锁机制来获得当前线程的Looper对象
    synchronized (this) {
      mLooper = Looper.myLooper();
      //发出通知,当前线程已经创建mLooper对象成功,这里主要是通知getLooper方法中的wait
      notifyAll();
    }
    //设置当前线程的优先级
    Process.setThreadPriority(mPriority);
    //该方法实现体是空的,子类可以实现该方法,作用就是在线程循环之前做一些准备工作,当然子类也可以不实现。
    onLooperPrepared();
    //启动loop
    Looper.loop();
    mTid = -1;
  }
}
Copier après la connexion

Analyse : les commentaires dans le code ci-dessus ont été clairement écrits et la fonction principale de la méthode d'exécution ci-dessus est pour appeler Looper.prepare et Looper.loop, créez un thread de boucle. Il convient de mentionner

que la méthode onLooperPrepared est appelée avant de démarrer la boucle dans la méthode run. L'implémentation de cette méthode est vide et les utilisateurs peuvent implémenter cette méthode dans des sous-classes. Le but de cette méthode est de

faire un travail d'initialisation avant la boucle du thread. Bien entendu, vous n'êtes pas obligé d'implémenter cette méthode, selon vos besoins. On peut également constater que les ingénieurs de Google prennent également en compte l'évolutivité du code lors de l'écriture du code. Génial !

Autres méthodes de HandlerThread

getLooper récupère l'objet Looper du thread actuel

/**
   * This method returns the Looper associated with this thread. If this thread not been started
   * or for any reason is isAlive() returns false, this method will return null. If this thread
   * has been started, this method will block until the looper has been initialized.
   * @return The looper.
   */
  public Looper getLooper() {
    //如果线程不是存活的,则直接返回null
    if (!isAlive()) {
      return null;
    }
     
    // If the thread has been started, wait until the looper has been created.
    //如果线程已经启动,但是Looper还未创建的话,就等待,知道Looper创建成功
    synchronized (this) {
      while (isAlive() && mLooper == null) {
        try {
          wait();
        } catch (InterruptedException e) {
        }
      }
    }
    return mLooper;
  }
Copier après la connexion

Analyse : En fait, le commentaire anglais au début de la méthode a été expliqué très clairement : la fonction principale de cette méthode est d'obtenir l'objet mlooper dans le thread HandlerThread actuel.

Déterminez d'abord si le thread actuel est vivant. S'il n'est pas vivant, il renverra directement null. Deuxièmement, si le thread actuel survit, déterminez si la variable membre du thread mLooper est nulle. Si elle est

null, cela signifie que le thread actuel a été créé avec succès, mais que l'objet Looper n'a pas encore été créé. Par conséquent, la méthode wait sera appelée ici. Allez attendre. Lorsque la méthode notifyAll dans la méthode run est appelée,

notifie la méthode wait du thread actuel d'attendre la fin, sort de la boucle. , et obtient la valeur de l'objet mLooper.

总结:在获得mLooper对象的时候存在一个同步的问题,只有当线程创建成功并且Looper对象也创建成功之后才能获得mLooper的值。这里等待方法wait和run方法中的notifyAll方法共同完成同步问题。

quit结束当前线程的循环

/**
   * Quits the handler thread&#39;s looper.
   * <p>
   * Causes the handler thread&#39;s looper to terminate without processing any
   * more messages in the message queue.
   * </p><p>
   * Any attempt to post messages to the queue after the looper is asked to quit will fail.
   * For example, the {@link Handler#sendMessage(Message)} method will return false.
   * </p><p class="note">
   * Using this method may be unsafe because some messages may not be delivered
   * before the looper terminates. Consider using {@link #quitSafely} instead to ensure
   * that all pending work is completed in an orderly manner.
   * </p>
   *
   * @return True if the looper looper has been asked to quit or false if the
   * thread had not yet started running.
   *
   * @see #quitSafely
   */
  public boolean quit() {
    Looper looper = getLooper();
    if (looper != null) {
      looper.quit();
      return true;
    }
    return false;
  }
//安全退出循环
 public boolean quitSafely() {
    Looper looper = getLooper();
    if (looper != null) {
      looper.quitSafely();
      return true;
    }
    return false;
  }
Copier après la connexion

   


分析:以上有两种让当前线程退出循环的方法,一种是安全的,一中是不安全的。至于两者有什么区别? quitSafely方法效率比quit方法标率低一点,但是安全。具体选择哪种就要看具体项目了。

总结:

1.HandlerThread适用于构建循环线程。

2.在创建Handler作为HandlerThread线程消息执行者的时候必须调用start方法之后,因为创建Handler需要的Looper参数是从HandlerThread类中获得,而Looper对象的赋值又是在HandlerThread的run方法中创建。


相信看了这些案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

相关阅读:

php如何实现栈数据结构以及括号匹配算法的代码示例详解

php中最简单的字符串匹配算法,php匹配算法_PHP教程

最简单的php中字符串匹配算法教程

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal