Android-スレッド更新UIの2つの方法

33107 ワード

1つ目は、Handlerを使用してUIを更新することです.
2つ目はActivity.runOnUIThread(Runnable)uiを更新するコードをRunnableに作成する
  • xmlファイル
  • <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <Button
            android:id="@+id/UpdataUI"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginLeft="8dp"
            android:layout_marginTop="8dp"
            android:text="Handler  UI"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/text" />
    
        <EditText
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginLeft="8dp"
            android:layout_marginTop="8dp"
            android:ems="10"
            android:inputType="textPersonName"
            android:text="Name"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
        <EditText
            android:id="@+id/text2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginLeft="8dp"
            android:layout_marginTop="8dp"
            android:ems="10"
            android:inputType="textPersonName"
            android:text="Name"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/UpdataUI" />
    
        <Button
            android:id="@+id/Update"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginLeft="8dp"
            android:layout_marginTop="8dp"
            android:text="runOnUiThread  UI"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/text2" />
    
    </android.support.constraint.ConstraintLayout>
    
  • javaコード
  • package com.example.uithreadtest;
    
    import android.os.Handler;
    import android.os.Message;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    
    import static java.lang.Thread.sleep;
    
    public class MainActivity extends AppCompatActivity {
        private static int UPDATA = 1;
        private EditText text, text2;
        private UIHanlder UIhanlder;
        private UIThread thread;
        private Button UpData, UpData2;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            text = findViewById(R.id.text);
            text2 = findViewById(R.id.text2);
            UpData = findViewById(R.id.UpdataUI);
            UpData2 = findViewById(R.id.Update);
            UpData.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    UIhanlder = new UIHanlder();
                    thread = new UIThread();
                    thread.start();
                }
            });
            //  runOnUiThread  UI
            UpData2.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    try {
                                        sleep(1000);
                                    } catch (InterruptedException e) {
                                        e.printStackTrace();
                                    }
                                    text2.setText("UI    ");
                                }
                            });
                        }
                    }).start();
                }
            });
        }
    
        private class UIHanlder extends Handler {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                Bundle bundle = msg.getData();
                String args = bundle.getString("text");
                text.setText(args);
            }
        }
    
        private class UIThread extends Thread {
            @Override
            public void run() {
                super.run();
                try {
                    sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Message message = new Message();
                Bundle bundle = new Bundle();
                bundle.putString("text", "UI    ");
                message.setData(bundle);
                UIhanlder.sendMessage(message);
            }
        }
    }
    
    

    次にrunOnUI Threadを使用してUIを更新する方法について重点的に説明します.
    まずrunOnUIThreadのソースコードを見てみましょう
     public final void runOnUiThread(Runnable action) {
            if (Thread.currentThread() != mUiThread) {
                mHandler.post(action);
            } else {
                action.run();
            }
        }
    

    まず,現在のスレッドがメインスレッドであるか否かを判断し,メインスレッドであればRunnableインタフェースのrun()メソッドを直接実行する.しかし、メインスレッドでなければ?このときHandlerのpost(Runnable)メソッドが呼び出される.Handlerのpost(Runnable)メソッドを呼び出します.この過程はどのように実現されたのでしょうか.
    Looper
  • まず、Looperが一般的にスレッドを作成するときにこのように書かれている
  • について説明します.
    public class MyThread extends Thread {
    
        @Override
        public void run() {
            // do something...
        }
    }
    

    スレッドをアクティブにするためにrun()メソッドにwhile()ループを追加してアクティブにします.
    public class MyThread extends Thread {
    
        @Override
        public void run() {
            while (true) {
                // do something...
            }
        }
    }
    

    whileループが実行されない限り、スレッドは生存します.これがLooperが実現できるもので、Looperの字面は「ループ」を意味し、スレッドを生存させる.Looperについて注意する必要があります.
  • スレッドのデフォルトではLooperは取得されません.
  • は、スレッド内にLooperを作成することができる.
  • スレッドごとに1つのLooperしか作成できません.次はLooperでwhiteサイクルを置き換えます:
  • public class MyThread extends Thread {
    
        @Override
        public void run() {
            Looper.prepare(); 
            Looper.loop();
        }
    }
    
  • Looperを呼び出す.prepare()現在のスレッドにLooperがあるかどうかを確認し、ない場合は作成します.
  • Looperを呼び出す.loop()後Looperがループを開始します.

  • このようにLooperループはスレッドを生存させているが,このように何もしないスレッドが生存することは意味がない.Looperを作成すると、メッセージ(Message)を格納するメッセージキュー(MessageQueue)が作成されます.
    Message
    Messageは実際にはいくつかの命令の集合です.String,int,Runnablesなどのデータ型を保持できます.特定のスレッドでRunnablesを実行する場合は、Runnablesをメッセージに配置し、このスレッドのLooperによって作成されたメッセージキューにメッセージを配置します.では、メッセージキューにどのように配置しますか?またHandlerを使いました.
    Handler
    Handlerは処理者の意味で、彼はメッセージをLooperのメッセージキューに置くことを担当して、実行する時、彼はまたLooperがバインドしたスレッドの中でこのメッセージを実行することを担当します.Handlerが作成されるときは特定のLooperを指します.2つの異なる作成方法があります.
  • 構築方法でLooper:Handler handler=new Handler(Looper looper);
  • は、現在のスレッドのLooper:Handler handler=new Handler()を指す空の構造方法を使用する.

  • Handlerはメッセージを作成し、post()のようなLooperのメッセージキューの末尾に追加するのに非常に便利です.Runnableをpost()に転送するだけです
     handler.post(new Runnable(){ 
            @Override 
            public void run(){ 
                // do something ... 
            } 
       };
    

    runOnUIThreadのソースコードに戻る
    final Handler mHandler = new Handler();
    private Thread mUiThread;
    // ...
    public final void runOnUiThread(Runnable action) {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);
         } else {
             action.run();
         }
    // ...
    }
    

    まず,主スレッド内で無パラメトリック構造法によりHandlerを作成し,このHandlerは主スレッドを指す.runOnUIThread()を実行すると、現在のスレッドはメインスレッドではなくmHandlerが呼び出される.post(action)は、Runnableをプライマリスレッドのメッセージキューに追加します.これにより、Runnableの文はプライマリスレッドで実行されます.