[JAVA] Programmation à partir de Memorandum of Thread de 51 ans

Le résumé multi-thread est ici

Hum

J'ai peur, donc en un mot, un mémo de traitement multi-thread

■ ** Extension de classe Thread ** | ** Héritage d'interface exécutable ** ** Communication avec le fil de l'interface utilisateur **   view#post(Runnable)   View#postDelayed(Runnable.long)   runOnUiThread(Runnable) ■ Classe ** AsyncTask ** ** Traitement et communication des threads de l'interface utilisateur ** Avec execute (), doInBackground (), postExecute (), etc. ■ Classe ** Handler ** ** Réalise la communication entre plusieurs threads (OK même si ce n'est pas un thread d'interface utilisateur) **   Message   Runnable

■Thread(Thread/Runnable) Android fonctionnera sur un processus Linux avec un thread. Ce thread est appelé un seul thread et MainActivity.java s'exécute dans un seul thread. Ici, le thread sur lequel MainActivity s'exécute est appelé thread principal et est décrit. Seul le thread principal peut gérer directement les parties de l'interface utilisateur et pour faire fonctionner les parties de l'interface utilisateur à partir d'autres threads, une méthode dédiée est utilisée.

MainActivity joue le rôle d'une interface exploitée par l'utilisateur, donc si le thread principal effectue un traitement qui prend du temps, l'écran d'opération ne répondra plus ou le traitement global ralentira, ce qui le rendra difficile à utiliser. Je vais finir.

Par conséquent, afin de maintenir la facilité d'utilisation de l'application, les processus de conception qui ne sont pas liés aux opérations de l'utilisateur doivent être traités séparément à l'aide d'un thread distinct (multi-thread). Il semble qu'un autre traitement de thread soit effectué à l'aide de la classe Thread ou de l'interface Runnable.

** <Différence entre Thread et Runnable> ** Thread est une "classe publique Thread étend Object implements Runnable", une classe qui hérite de Runnable. Runnable est une "interface publique Runnable". Si vous souhaitez utiliser les constantes et les méthodes de la classe Thread, étendez la classe Thread! Sinon, pourquoi ne pas hériter de Runnable? Cela signifie t-il?

Puisqu'un autre thread est également traité sur le même processus Linux que le thread principal, s'il y a un problème avec un seul processus, envisagez de lancer un autre processus Linux (multi-processus) et de créer un autre thread si nécessaire. Peut-être (Manifest.java).

□Thread

Dans une sous-classe de Thread


public void onCreate(){
       SubThread subThread = new SubThread();
       subThread.start();
}

class SubThread extends Thread{
      public void run(){
             // todo
      }
}

□Runnable Bien qu'il s'agisse d'une description de Runnable, il existe trois méthodes de description familières.

Fonctionnel anonyme


new Thread(new Runnable(){
    @Override 
    public void run(){
           // todo
    }
}).start();

Utiliser une instance de Thread


public void onCreate(){
       MyRunnable myRunnable = new MyRunnable();
       Thread     thread     = new Thread(myRunnable);
       Thread.start();
}

class MyRunnable implement Runnable{
      @Override 
      public void run(){
             // todo
      }
}

Appelez directement la classe Thread


public void onCreate(){
       Thread thread = new Thread(MyRunnable());
}

class MyRunnable implement Runnable{
      @Override 
      public void run(){
             // todo
      }
}

Traitement d'arrêt du fil

  • Thread en cours d'exécution sur le service
  • S'il existe un service, le service ne sera pas démarré deux fois. --Arrêter avec annuler ()

MainActivity.java



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

    //Obtenez les objets de bouton de démarrage et d'arrêt!
    Button btn_start = findViewById(R.id.btn_start);
    Button btn_stop  = findViewById(R.id.btn_stop);
    
    final Intent intent = new Intent(this,MyService.class);
    btn_start.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View view) {
            
            //Si MyService ne démarre pas, démarrez-le!
            if(!MyService.serviceState) {
                startForegroundService(intent);
            }
        }
    });

    btn_stop.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View view) {
            // stopService()Alors, je vais appeler surDestroy of MyService ~
            stopService(intent);
        }
    });
}

MyService.java



public class MyService extends Service {

    // serviceState =Si vrai, MyService a déjà démarré
    // threadState  =Si vrai, Thread continuera à s'exécuter
    static boolean serviceState;
    boolean threadState;

    public MyService() {
        serviceState = true;
        threadState  = true;
    }

    @Override
    public int onStartCommand(Intent intent,int flags,int startId){

        //Configurez le contenu de la notification!
        Notification notification;
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this,"id");
        notification = builder.setSmallIcon(R.drawable.notification_icon)
                              .setContentTitle("sanple")
                              .setContentText("text")
                              .build();

        //Définissez le canal de notification et son importance!
        int importance = NotificationManager.IMPORTANCE_LOW;
        NotificationChannel channel = new NotificationChannel("id","name",importance);
        NotificationManager manager = getSystemService(NotificationManager.class);
        manager.createNotificationChannel(channel);
        startForeground(1,notification);

        //Lancez le fil!
        new Thread(new Runnable() {
            @Override
            public void run() {
                int count = 0;

                //Exécutez le journal de comptage toutes les 2 secondes tant que threadState est true.
                while(threadState){
                    Log.d("msg",String.valueOf(count));

                    try {
                        sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    count++;
                }

            }
        }).start();

        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy(){
        Log.d("msg","onDestroy");

        //StopService dans MainActivity()Lorsque vous appelez surDestroy()Est appelé
        //MyService est arrêté, Thread est également défini sur arrêté
        serviceState = false;
        threadState  = false;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

Thread discard, arrêt forcé

La destruction des threads (stop ()) est obsolète depuis l'API15. Cela dit, même avant cela, il y avait un besoin de code tel que vouloir détruire Thread ou le terminer de force, et j'ai également recommandé du code qui peut être détruit. Cependant, il est obsolète depuis l'API15. C'est parce que la suppression des fils laisse beaucoup de déchets.

Lorsque Thread s'exécute normalement, les objets protégés peuvent devenir instables en raison de la suppression de Thread, ce qui peut entraîner un comportement inattendu. Puisqu'il est difficile de trouver ou d'identifier des objets qui ont été libérés de Thread, examinons si vous pouvez concevoir un programme avec interruption () sans abandonner Thread, et à partir de l'API 15, vous pouvez forcer l'arrêt du thread. Il est obsolète. Pour les applications mignonnes mignonnes (et pour les utilisateurs qui aiment votre application), n'utilisez pas Thread.stop (), utilisez simplement interruption () pour concevoir votre code!

Si vous aimez toujours stop ()! Alors est-il bon de l'utiliser pour qu'il n'y ait pas de personnes manquantes (objets, etc.)?

■ Communication entre les threads

□ UI thread <-worker thread □ Fil de travail <-Fil de travail

□ Communication inter-thread (Handler: Looper et Queue)

Handle est une classe qui communique entre les threads, et le thread qui a créé l'instance Handle a les fonctions de file d'attente et de zone répétée requises pour la communication. Les informations envoyées par d'autres threads sont stockées dans une file d'attente, et Looper récupère les informations stockées et les traite dans le thread principal (puisqu'elles sont traitées dans le thread principal, il est également possible d'exploiter des parties de l'interface utilisateur).

□ Communiquer du thread de travail au thread de l'interface utilisateur

Il semble que les parties de l'interface utilisateur ne peuvent pas être opérées directement à partir du thread de travail, utilisez donc des méthodes et des classes pour faire fonctionner les parties de l'interface utilisateur pour agir comme si le traitement des opérations des parties de l'interface utilisateur était passé au thread de l'interface utilisateur.

  • View.post(Runnable)
  • View.postDelayed(Runnable,long)
  • Activity.runOnUiThread(Runnable)
  • Classe de gestionnaire
  • Traitement asynchrone de la classe AsyncTask

La méthode de manipulation de View à l'aide de View.post devient difficile à maintenir car l'opération devient compliquée </ font>. Il existe également un moyen d'utiliser Handle dans le thread de travail, mais AsyncTask est recommandé pour référence.

View.post () et View.postDelayed (), qui sont toutes deux des méthodes trouvées dans les objets View. Post () à partir d'une vue différente (TextView.post () ou Button.Post ()) sera reçu comme le même View.post () du côté de la file d'attente de réception (identifiez l'expéditeur comme TextView ou EditText) Ne pas).

· Voir l'article ()

public boolean post(Runnable action)

Méthodes de classe View: comme TextView.post, TextEdit.post (), Button.post (), les parties de vue peuvent utiliser les méthodes post () et postDelayed (). post ajoute Runnable à la file d'attente de messages et traite Runnable dans le thread de l'interface utilisateur. Si le processus exécutable réussit, il retournera true. Si faux, il semble qu'il existe de nombreux cas où la file d'attente de messages s'est terminée.

Publier dans la classe Thread

activity_main.xml


    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:id="@+id/textView"
        />

Utilisation de la classe Thread


public class MainActivity extends AppCompatActivity {

    public static TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = (TextView) findViewById(R.id.textView);
        
        //Instancier et démarrer la classe Thread
        ThreadSample threadSample = new ThreadSample();
        threadSample.start();
    }
}

class ThreadSample extends Thread{
    public void run(){
        //Exploiter les parties de l'interface utilisateur de l'activité principale
        // post()Puisque la méthode prend Runnable comme argument, c'est comme suit
        MainActivity.textView.post(new Runnable(){
            @Override
            public void run() {
                MainActivity.textView.setText("From ThreadSample");
            }
        });
    }
}
Post () dans une classe anonyme

Pour rappel, je l'écrirai également dans la classe anonyme.

python


public class MainActivity extends AppCompatActivity {

    public static TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = (TextView) findViewById(R.id.textView);

        new Thread(new Runnable() {
            @Override
            public void run() {
                textView.post(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText("From Another Thread");
                    }
                });
            }
        }).start();
    }
}

・ View.postDelayed

public boolean postDelayed(Runnable action,long delayMillis) delay ... delay; Millis ... milliseconde </ font> postDelayed ajoute Runnable à la file d'attente de messages et, après un laps de temps spécifié, traite le Runnable dans le thread d'interface utilisateur.

Lorsque vous exécutez le code ci-dessous, le textview sera accueilli avec la valeur initiale "Hello World!", Mais après 5 secondes, l'affichage changera en "From ThreadSample".

activity_main.xml


    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:id="@+id/textView"
        />

Dans la classe Thread


public class MainActivity extends AppCompatActivity {

    public static TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = (TextView) findViewById(R.id.textView);
        ThreadSample threadSample = new ThreadSample();
        threadSample.start();
    }
}

class ThreadSample extends Thread{
    public void run(){
        MainActivity.textView.postDelayed(new Runnable(){
            @Override
            public void run() {
                MainActivity.textView.setText("From ThreadSample");
            }
        },5000);
    }
}

・ Activity.runOnUiThread

public final void runOnUiThread(Runnable action)

Méthode de classe d'activité: ** L'activité peut utiliser runOnUiThread () **. L'activité fournit l'écran de l'interface utilisateur.

runOnUiThread exécute l'action spécifiée sur le thread d'interface utilisateur. Si le thread actuel est un thread d'interface utilisateur, l'action est immédiate! Sinon, l'action sera ajoutée à la file d'attente d'événements du thread d'interface utilisateur. Il semble que le comportement fonctionne presque de la même manière que la méthode post ()! ..

public class MainActivity extends AppCompatActivity {

    public static TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = (TextView) findViewById(R.id.textView);

        new Thread(new Runnable(){
            @Override
            public void run() {
                MainActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText("runOnUiThread");
                    }
                });
            }
        }).start();
    }
}

■Handler Pour plus d'informations, cliquez ici "Résumé Hanler" Vous pouvez utiliser le gestionnaire pour envoyer des objets exécutables et traiter les messages associés à la file d'attente de messages d'un thread. Une instance de Handler est associée à un seul thread et à une file d'attente de messages. Renvoie true lorsqu'il est ajouté à la file d'attente des messages. Il ne s'agit pas de savoir si le processus a réussi. Si le boucleur se termine avant la fin du temps spécifié, Runnable sera abandonné. Si faux, soupçonnez que la file d'attente des messages est terminée!

■android.os.AsyncTask public abstract class AsyncTask extends Object android.os.AsyncTask<Params,Progress,Result>

Résumé ici Code de référence ici

AsyncTask est un processus asynchrone. Particulièrement adapté au traitement asynchrone de courte durée. ** Veuillez utiliser d'autres API (Executor, ThreadPoolExecutor, etc.) ** pour un traitement qui s'exécute pendant une longue période!

Recommended Posts